//聲明注解
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() {}