一、案例需求
在一个SpringBoot项目,其中定时任务和web端代码耦合在一起,并部署在多个服务器节点上,但这样会存在一个问题,每个节点都会触发一次定时任务,这显然重复执行了。为了达到唯一控制效果,引入了分布式锁的功能。但是有个缺点是每写一个定时任务都得写一份与业务无关的分布式锁代码,这样造成大量的冗余代码。所以想着通过注解+切面的方式来实现代码的精简。
二、代码
1.注解
@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface EnableDistributedLock {
String key();
int expTime() default 30;
}
分布式锁用的是redis实现的,所以注解简单定义了key和过期时间。
2.AOP
@Aspect
@Component
public class DistributedLockAspect {
private final static Logger logger = LoggerFactory.getLogger(DistributedLockAspect.class);
@Resource(name = "exclusiveLock")
private DistributedLock exclusiveLock;
@Pointcut("@annotation(EnableDistributedLock)")
public void distributedLockPointCut() {
}
@Around("distributedLockPointCut()")
public void aroud(ProceedingJoinPoint joinPoint) throws Throwable {
MethodSignature methodSignature = (MethodSignature) joinPoint.getSignature();
Method method = methodSignature.getMethod();
method.setAccessible(true);
EnableDistributedLock enableDistributedLock = method.getAnnotation(EnableDistributedLock.class);
String lockKey = enableDistributedLock.key();
if (StringUtils.isBlank(lockKey)) {
throw new Throwable("分布式锁aop错误,key为空,请检查注解配置");
}
if (exclusiveLock.isLock(lockKey)) {
logger.info("该任务已在进行,正常退出");
return;
} else {
exclusiveLock.lock(lockKey);
}
try {
joinPoint.proceed();
} catch (Exception e) {
throw e;
} finally {
exclusiveLock.unLock(lockKey);
}
}
}
这个AOP呢,其实就是注解的处理类,扫描带有@EnableDistributedLock注解的方法,然后环绕注释方法添加分布式锁的相关代码。
3.使用
@EnableDistributedLock(key = lockKey, expTime = 60 * 3)
public void execute() {
//业务代码
}
需要用的方法添加@EnableDistributedLock即可,且支持方法在多节点下唯一执行。