自定义注解使用在AOP切面编程里
自定义注解:
@Target({ElementType.METHOD})
@Retention(RetentionPolicy.RUNTIME)
public @interface RedisDistributeLock {
String key();
int leastLockMs() default 1500;
}
使用自定义注解:
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.boot.autoconfigure.condition.ConditionalOnExpression;
import org.springframework.scheduling.annotation.Scheduled;
import org.springframework.stereotype.Component;
import java.util.HashMap;
import java.util.concurrent.atomic.AtomicInteger;
@Slf4j
@Component
@RequiredArgsConstructor
@ConditionalOnExpression(value = "${enable.job:true}")
public class MyJob {
final MyService myService;
@Scheduled(cron = "${cron.MyJob}")
@RedisDistributeLock(key = "redis.lock.MyJob")
public void executeJob() {
log.info("start MyJob")
}
}
AOP拦截:
package com.my.aop;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Pointcut;
import org.aspectj.lang.reflect.MethodSignature;
import org.springframework.core.annotation.AnnotatedElementUtils;
import org.springframework.data.redis.core.ReactiveRedisTemplate;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Component;
import java.time.Duration;
import java.time.temporal.ChronoUnit;
@Slf4j
@Aspect
@Component
@RequiredArgsConstructor
public class RedisDistributeLockAopForJob {
final RedisTemplate<String, Object> redisTemplate;
final ReactiveRedisTemplate<String, Object> reactiveRedisTemplate;
@Pointcut(value = "@annotation(com.my.aop.RedisDistributeLock)")
public void scheduleDistributeLock() {
}
@Around("scheduleDistributeLock()")
public Object handle(ProceedingJoinPoint pjp) throws Throwable {
RedisDistributeLock redisLockAnnotation = AnnotatedElementUtils
.getMergedAnnotation(
((MethodSignature) pjp.getSignature()).getMethod()
, RedisDistributeLock.class
);
try {
assert redisLockAnnotation != null;
if (Boolean.TRUE.equals(redisTemplate.opsForValue()
.setIfAbsent(redisLockAnnotation.key(), Thread.currentThread().getId(), Duration.ofMillis(redisLockAnnotation.leastLockMs())))) {
log.info("aop lock success. job name = {}, least lock {} ms", redisLockAnnotation.key(), redisLockAnnotation.leastLockMs());
long startLockTimeMS = System.currentTimeMillis();
Object returnObj = pjp.proceed();
long spendMs = System.currentTimeMillis() - startLockTimeMS;
long gapMs = (long) redisLockAnnotation.leastLockMs() - spendMs;
if (gapMs <= 0) {
//Boolean isDelete = redisTemplate.delete(redisLockAnnotation.key());
log.info("aop is finish and delete redis key {} is {}", redisLockAnnotation.key(), true);
} else {
log.info("aop is finish and expire time is {} s, job name = {}", this.getExpireSecondByKey(redisLockAnnotation.key()), redisLockAnnotation.key());
}
return returnObj;
} else {
log.info("aop lock fail because expire time is {} s on job {}", this.getExpireSecondByKey(redisLockAnnotation.key()), redisLockAnnotation.key());
}
} catch (Throwable throwable) {
log.error("catch aop error. job name = {}", redisLockAnnotation.key(), throwable);
throw throwable;
}
return null;
}
private Long getExpireSecondByKey(String redisKey) {
return reactiveRedisTemplate.getExpire(redisKey).defaultIfEmpty(Duration.ZERO).block(Duration.ofMillis(100)).get(ChronoUnit.SECONDS);
}
}
end.