0
点赞
收藏
分享

微信扫一扫

Spring boot 定时任务Scheduled集群部署下,重复执行解决方案

三分梦_0bc3 2022-03-31 阅读 45
spring

利用redis分布式锁实现

1.声明注解

package com.rk.iam.sys.job.redis;


import java.lang.annotation.*;
import java.util.concurrent.TimeUnit;
/**
* @author wdy
* @version 1.0
* @date 2022/3/30 15:06
*/

@Retention(RetentionPolicy.RUNTIME)
@Target({ElementType.METHOD})
@Documented
public @interface RedisLock {
String lockPrefix() default "";
String lockKey() default "";
long timeOut() default 30;
TimeUnit timeUnit() default TimeUnit.SECONDS;
}

2.注解实现

package com.rk.iam.sys.job.redis;


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 wdy
* @Author lvhoushuai(tsxylhs @ outlook.com)
* @Date 2022-03-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.rk.iam.sys.job.redis.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;
}


}

3.redis操作

package com.rk.iam.sys.job.redis;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.redis.core.ValueOperations;
import org.springframework.stereotype.Component;

import java.util.concurrent.TimeUnit;

/**
* @author wdy
* @version 1.0
* @date 2022/3/30 15:08
*/

@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;
}



}

4.定时任务实现类

package com.rk.iam.sys.job;

import com.rk.iam.sys.common.enums.PushEnums;
import com.rk.iam.sys.common.vo.SysVersionVO;
import com.rk.iam.sys.job.redis.RedisLock;
import com.rk.iam.sys.service.SysProjectService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Configuration;
import org.springframework.scheduling.annotation.EnableScheduling;
import org.springframework.scheduling.annotation.Scheduled;

/**
* @author wdy
* @version 1.0
* @date 2022/3/30 17:01
*/

@Configuration
@EnableScheduling
public class SysProjectJob {
@Autowired
private SysProjectService sysProjectService;
@Scheduled(cron = "0 0 0 * * ?")
@RedisLock(lockPrefix = "iamCache:job", lockKey = "SysProjectJob",timeOut = 60)
public void sync() {

try {
sysProjectService.sysnProject();
} catch (Exception e) {
e.printStackTrace();
}

}
}
举报

相关推荐

0 条评论