分布式锁,springBoot 定时任务@Scheduleder
//声明注解
import java.lang.annotation.*;
import java.util.concurrent.TimeUnit;
/**
* @ClassName RedisLock
* @Author lvhoushuai(tsxylhs @ outlook.com)
* @Date 2020-08-25
**/
@Retention(RetentionPolicy.RUNTIME)
@Target({ElementType.METHOD})
@Documented
public @interface RedisLock {
String lockPrefix() default "";
String lockKey() default "";
long timeOut() default 5;
TimeUnit timeUnit() default TimeUnit.SECONDS;
}
//注解实现
import org.apache.commons.lang3.StringUtils; 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.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Component; import java.lang.reflect.Method; import java.util.HashMap; import java.util.Map; /** * @ClassName RedisLockAspect * @Author lvhoushuai(tsxylhs @ outlook.com) * @Date 2020-08-25 * @Description 拦截器实现 **/ @Aspect @Component public class RedisLockAspect { private static final Integer Max_RETRY_COUNT=3; private static final String LOCK_PRE_FIX="lockPreFix"; private static final String LOCK_KEY = "lockKey"; private static final String TIME_OUT = "timeOut"; private static final int PROTECT_TIME = 2 << 11;//4096 private static final Logger log= LoggerFactory.getLogger(RedisLock.class); @Autowired private CommonRedistHelper commonRedistHelper; @Pointcut("@annotation(com.sensetime.finance.auditlogweb.aop.RedisLock)") public void redisLockAspect(){} @Around("redisLockAspect()") public void lockAroundAction(ProceedingJoinPoint proceeding) throws Exception{
//获取redis锁
Boolean flag = this.getLock(proceeding, 0, System.currentTimeMillis());
if (flag) {
try {
proceeding.proceed();
Thread.sleep(PROTECT_TIME);
} catch (Throwable throwable) {
throw new RuntimeException("分布式锁执行发生异常" + throwable.getMessage(), throwable);
} finally {
// 删除锁
this.delLock(proceeding);
}
} else {
log.info("其他系统正在执行此项任务");
}
} //获取锁 private boolean getLock(ProceedingJoinPoint proceeding,int count,long currentTime){ //获取注解中的参数 Map<String,Object> annotationArgs=this.getAnnotationArgs(proceeding); String lockPrefix=(String)annotationArgs.get(LOCK_PRE_FIX); String key=(String)annotationArgs.get(LOCK_KEY); long expire=(long)annotationArgs.get(TIME_OUT); if (StringUtils.isEmpty(lockPrefix)||StringUtils.isEmpty(key)){ throw new RuntimeException("RedisLock,锁前缀,锁名未设置"); } if(commonRedistHelper.setNx(lockPrefix,key,expire)){ return true; }else{ //如果当前时间与锁的时间差,大于保护时间,则强制删除锁(防止死锁) long createTime=commonRedistHelper.getLockValue(lockPrefix,key); if ((currentTime-createTime)>(expire*1000+PROTECT_TIME)){ count++; if(count>Max_RETRY_COUNT){ return false; } commonRedistHelper.delete(lockPrefix,key); getLock(proceeding,count,currentTime); } return false; } } /** * 删除锁 * */ private void delLock(ProceedingJoinPoint proceeding) { Map<String, Object> annotationArgs=this.getAnnotationArgs(proceeding); String lockPrefix=(String)annotationArgs.get(LOCK_PRE_FIX); String key=(String)annotationArgs.get(LOCK_KEY); commonRedistHelper.delete(lockPrefix,key); } /** * 获取锁参数 * * @param proceeding * @return */ private Map<String, Object> getAnnotationArgs(ProceedingJoinPoint proceeding) { Class target = proceeding.getTarget().getClass(); Method[] methods = target.getMethods(); String methodName = proceeding.getSignature().getName(); for (Method method : methods) { if (method.getName().equals(methodName)) { Map<String, Object> result = new HashMap<String,Object>(); RedisLock redisLock = method.getAnnotation(RedisLock.class); result.put(LOCK_PRE_FIX, redisLock.lockPrefix()); result.put(LOCK_KEY, redisLock.lockKey()); result.put(TIME_OUT, redisLock.timeUnit().toSeconds(redisLock.timeOut())); return result; } } return null; } }
redis操作
@Component public class CommonRedistHelper { @Autowired RedisTemplate redisTemplate; /** * 添加分布式锁 * */ public boolean setNx(String track,String sector,long timeout){ ValueOperations valueOperations=redisTemplate.opsForValue(); Boolean flag=valueOperations.setIfAbsent(track+sector,System.currentTimeMillis()); if (flag){ valueOperations.set(track+sector,getLockValue(track,sector),timeout, TimeUnit.SECONDS); } return flag; } /** * 删除锁 */ public void delete(String track,String sector){ redisTemplate.delete(track+sector); } /** * 查询锁 * @return 写锁时间 */ public long getLockValue(String track, String sector) { ValueOperations valueOperations = redisTemplate.opsForValue(); long createTime = (long) valueOperations.get(track + sector); return createTime; } }
引用注解
@Scheduled(cron = "${task.cron.tradeData}") @RedisLock(lockPrefix = "**",lockKey = "estomysql") public void scheduledTask() {}