SpringTask的定时任务,在集群环境下会多次执行,我们可以通过使用分布式锁的方式进行解决
@Scheduled(cron = "1/10 * * * * ?")
@Async
public 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 {
@Resource
private 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();
}

被折叠的 条评论
为什么被折叠?



