使用Aop和自定义注解实现SpringTask定时任务中加锁逻辑的封装
SpringTask的定时任务,在集群环境下会多次执行,我们可以通过使用分布式锁的方式进行解决
@Scheduled(cron = "1/10 * * * * ?")@Asyncpublic void updateGrassLikeNum() {RLock lock = redissonClient.getLock("like:lock");try {if (lock.tryLock(0, 0, TimeUnit.SECONDS)) {grassService.updateLikeNumTask();}} catch (Exception e) {throw new RuntimeException(e);} finally {if (lock.isHeldByCurrentThread() && lock.isLocked()) {lock.unlock();}}}
但是,项目中可能存在很多定时任务,每次使用RLock加锁比较麻烦,我们可以使用AOP+自定义注解的方式进行优化
自定义注解
@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
public @interface LockAnnotation {/*** 锁名称** @return*/String lockName() default "";/*** 加锁等待时间** @return*/long lockWaitTime() default 0;/*** 锁超时时间** @return*/long lockTimeOut() default 0;
}
切面类
@Component
@Aspect
public class LockAspect {@Resourceprivate RedissonClient redissonClient;// 切点@Pointcut("@annotation(com.qfedu.common.core.annotataion.LockAnnotation)")public void pointcut() {}// 环绕通知@Around("pointcut()")public Object around(ProceedingJoinPoint joinPoint) {// 获取被注解的方法MethodInvocationProceedingJoinPoint mjp = (MethodInvocationProceedingJoinPoint) joinPoint;MethodSignature signature = (MethodSignature) mjp.getSignature();Method method = signature.getMethod();Object ret = null;// 获取注解对应的对象LockAnnotation annotation = method.getAnnotation(LockAnnotation.class);if (annotation != null) {String lockName = annotation.lockName();long lockWaitTime = annotation.lockWaitTime();long lockTimeOut = annotation.lockTimeOut();RLock lock = redissonClient.getLock(lockName);try {if (lock.tryLock(lockWaitTime, lockTimeOut, TimeUnit.SECONDS)) {// 调用目标方法ret = joinPoint.proceed();}} catch (Throwable e) {throw new RuntimeException(e);} finally {if (lock.isHeldByCurrentThread() && lock.isLocked()) {lock.unlock();}}}return ret;}
使用自定义注解的定时任务方法修改如下:
@Scheduled(cron = "1/10 * * * * ?")@Async@LockAnnotation(lockName = "like:lock", lockWaitTime = 0, lockTimeOut = 10)public void updateGrassLikeNum() {grassService.updateLikeNumTask();}