添加分布式部署定时任务
This commit is contained in:
+57
@@ -0,0 +1,57 @@
|
||||
package com.jero.common.aspect;
|
||||
|
||||
import com.jero.common.aspect.annotation.RedisLock;
|
||||
import com.jero.common.exception.JeroBootException;
|
||||
import com.jero.common.util.RedisLockHelper;
|
||||
import com.jero.common.util.RedisUtil;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.aspectj.lang.ProceedingJoinPoint;
|
||||
import org.aspectj.lang.annotation.Around;
|
||||
import org.aspectj.lang.annotation.Aspect;
|
||||
import org.aspectj.lang.reflect.MethodSignature;
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
import javax.annotation.Resource;
|
||||
import java.lang.reflect.Method;
|
||||
import java.util.UUID;
|
||||
|
||||
/**
|
||||
* 分布式部署定时任务
|
||||
* @Author lqt
|
||||
*/
|
||||
@Slf4j
|
||||
@Aspect
|
||||
@Component
|
||||
public class LockMethodAspect {
|
||||
@Resource
|
||||
private RedisLockHelper redisLockHelper;
|
||||
@Resource
|
||||
private RedisUtil redisUtis;
|
||||
|
||||
@Around("@annotation(com.jero.common.aspect.annotation.RedisLock)")
|
||||
public Object around(ProceedingJoinPoint joinPoint) {
|
||||
MethodSignature signature = (MethodSignature) joinPoint.getSignature();
|
||||
Method method = signature.getMethod();
|
||||
RedisLock redisLock = method.getAnnotation(RedisLock.class);
|
||||
String value = UUID.randomUUID().toString();
|
||||
log.info("====value=====" + value + "===========");
|
||||
String key = redisLock.key();
|
||||
log.info("====key======" + key + "===========");
|
||||
try {
|
||||
final boolean islock = redisLockHelper.lock(redisUtis, key, value, redisLock.expire(), redisLock.timeUnit());
|
||||
log.info("isLock : {}", islock);
|
||||
if (!islock) {
|
||||
log.error("获取锁失败");
|
||||
throw new JeroBootException("获取锁失败");
|
||||
}
|
||||
try {
|
||||
return joinPoint.proceed();
|
||||
} catch (Throwable throwable) {
|
||||
throw new JeroBootException("系统异常");
|
||||
}
|
||||
} finally {
|
||||
log.info("释放锁");
|
||||
redisLockHelper.unlock(redisUtis, key, value);
|
||||
}
|
||||
}
|
||||
}
|
||||
+24
@@ -0,0 +1,24 @@
|
||||
package com.jero.common.aspect.annotation;
|
||||
|
||||
import java.lang.annotation.*;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
/**
|
||||
* @author LQT
|
||||
*/
|
||||
@Target(ElementType.METHOD)
|
||||
@Retention(RetentionPolicy.RUNTIME)
|
||||
@Documented
|
||||
@Inherited
|
||||
public @interface RedisLock {
|
||||
/*** 业务键** @return*/
|
||||
String key();
|
||||
|
||||
/*** 锁的过期秒数,默认是5秒** @return*/
|
||||
int expire() default 5;
|
||||
|
||||
/*** 尝试加锁,最多等待时间** @return*/
|
||||
long waitTime() default Long.MIN_VALUE;
|
||||
|
||||
/*** 锁的超时时间单位** @return*/
|
||||
TimeUnit timeUnit() default TimeUnit.SECONDS;
|
||||
}
|
||||
+116
@@ -0,0 +1,116 @@
|
||||
package com.jero.common.util;
|
||||
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.springframework.data.redis.core.script.DefaultRedisScript;
|
||||
import org.springframework.data.redis.core.script.RedisScript;
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
import java.util.Collections;
|
||||
import java.util.Objects;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
|
||||
@Slf4j
|
||||
@Component
|
||||
public class RedisLockHelper {
|
||||
|
||||
private long sleepTime = 100;
|
||||
/**
|
||||
* 直接使用setnx + expire方式获取分布式锁
|
||||
* 非原子性
|
||||
*
|
||||
* @param key
|
||||
* @param value
|
||||
* @param timeout
|
||||
* @return
|
||||
*/
|
||||
public boolean lockSetNx(RedisUtil redisTemplate, String key, String value, int timeout) {
|
||||
if ( redisTemplate.setnx(key, value)) {
|
||||
return redisTemplate.expire(key, timeout);
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 使用Lua脚本,脚本中使用setnex+expire命令进行加锁操作
|
||||
*
|
||||
* @param redisTemplate
|
||||
* @param key
|
||||
* @param uniqueId
|
||||
* @param seconds
|
||||
* @return
|
||||
*/
|
||||
public boolean lockWithLua(RedisUtil redisTemplate, String key, String uniqueId, int seconds) {
|
||||
if(!Objects.isNull(seconds)){
|
||||
log.info("未使用参数:" + seconds);
|
||||
}
|
||||
String luaScript = "if redis.call('setnx',KEYS[1],ARGV[1]) == 1 then" +
|
||||
"redis.call('expire',KEYS[1],ARGV[2]) return 1 else return 0 end";
|
||||
Object result = redisTemplate.eval(RedisScript.of(luaScript), Collections.singletonList(key), uniqueId);
|
||||
//判断是否成功
|
||||
return result.equals(1L);
|
||||
}
|
||||
|
||||
/**
|
||||
* 在Redis的2.6.12及以后中,使用 set key value [NX] [EX] 命令
|
||||
*
|
||||
* @param key
|
||||
* @param value
|
||||
* @param timeout
|
||||
* @return
|
||||
*/
|
||||
public boolean lock(RedisUtil redisTemplate, String key, String value, int timeout, TimeUnit timeUnit) {
|
||||
long seconds = timeUnit.toSeconds(timeout);
|
||||
return redisTemplate.setnx(key, value, seconds);
|
||||
}
|
||||
|
||||
/**
|
||||
* 自定义获取锁的超时时间
|
||||
*
|
||||
* @param redisTemplate
|
||||
* @param key
|
||||
* @param value
|
||||
* @param timeout
|
||||
* @param waitTime
|
||||
* @param timeUnit
|
||||
* @return
|
||||
* @throws InterruptedException
|
||||
*/
|
||||
public boolean lockWithWaitTime(RedisUtil redisTemplate, String key, String value, int timeout, long waitTime, TimeUnit timeUnit) throws InterruptedException {
|
||||
long seconds = timeUnit.toSeconds(timeout);
|
||||
while (waitTime >= 0) {
|
||||
if (redisTemplate.setnx(key, value, seconds)) {
|
||||
return true;
|
||||
}
|
||||
waitTime -= sleepTime;
|
||||
Thread.sleep(sleepTime);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
/**
|
||||
* 错误的解锁方法—直接删除key
|
||||
*
|
||||
* @param key
|
||||
*/
|
||||
public void unlockWithDel(RedisUtil redisTemplate, String key) {
|
||||
redisTemplate.del(key);
|
||||
}
|
||||
|
||||
/**
|
||||
* 使用Lua脚本进行解锁操纵,解锁的时候验证value值
|
||||
*
|
||||
* @param redisTemplate
|
||||
* @param key
|
||||
* @param value
|
||||
* @return
|
||||
*/
|
||||
public boolean unlock(RedisUtil redisTemplate, String key, String value) {
|
||||
String luaScript = "if redis.call('get',KEYS[1]) == ARGV[1] then " +
|
||||
"return redis.call('del',KEYS[1]) else return 0 end";
|
||||
DefaultRedisScript<Long> redisScript =new DefaultRedisScript<> ();
|
||||
redisScript.setScriptText(luaScript);
|
||||
// 这个值类型要跟lua返回值类型一致才行,否则就会报 java.lang.IllegalStateException
|
||||
redisScript.setResultType(Long.class);
|
||||
return redisTemplate.eval(redisScript, Collections.singletonList(key), value);
|
||||
}
|
||||
}
|
||||
+35
@@ -1,10 +1,12 @@
|
||||
package com.jero.common.util;
|
||||
|
||||
import java.time.Duration;
|
||||
import java.util.*;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.data.redis.core.*;
|
||||
import org.springframework.data.redis.core.script.RedisScript;
|
||||
import org.springframework.stereotype.Component;
|
||||
import org.springframework.util.CollectionUtils;
|
||||
|
||||
@@ -609,4 +611,37 @@ public class RedisUtil {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* setnx
|
||||
*/
|
||||
public boolean setnx(String key, String value) {
|
||||
try {
|
||||
return redisTemplate.opsForValue().setIfAbsent(key, value);
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* setnx
|
||||
*/
|
||||
public boolean setnx(String key, String value,long time) {
|
||||
try {
|
||||
return redisTemplate.opsForValue().setIfAbsent(key,value, Duration.ofSeconds(time));
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* eval
|
||||
*/
|
||||
public Boolean eval(RedisScript<Long> luaScripts, List<String> keys, String values) {
|
||||
Long flag = redisTemplate.execute(luaScripts, keys, values);
|
||||
//判断是不是为1
|
||||
return flag == 1L;
|
||||
}
|
||||
}
|
||||
|
||||
+5
@@ -1,12 +1,16 @@
|
||||
package com.jero.modules.quartz.job;
|
||||
|
||||
import com.jero.common.aspect.annotation.RedisLock;
|
||||
import com.jero.common.util.DateUtils;
|
||||
import org.quartz.DisallowConcurrentExecution;
|
||||
import org.quartz.Job;
|
||||
import org.quartz.JobExecutionContext;
|
||||
import org.quartz.JobExecutionException;
|
||||
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
|
||||
import java.util.concurrent.TimeUnit;
|
||||
|
||||
/**
|
||||
* 示例带参定时任务
|
||||
*
|
||||
@@ -25,6 +29,7 @@ public class SampleParamJob implements Job {
|
||||
}
|
||||
|
||||
@Override
|
||||
@RedisLock(key = "lock----TestJob",expire=60,timeUnit= TimeUnit.SECONDS)
|
||||
public void execute(JobExecutionContext jobExecutionContext) {
|
||||
log.info(" Job Execution key:"+jobExecutionContext.getJobDetail().getKey());
|
||||
log.info("welcome " + this.parameter + " Jero-Boot 带参数定时任务 SampleParamJob ! 时间:" + DateUtils.now());
|
||||
|
||||
Reference in New Issue
Block a user