1.定义注解
import java.lang.annotation.*;
import java.util.concurrent.TimeUnit;
/** @Author: best_liu
* @Description:
* @Date: 16:13 2023/9/4
* @Param
* @return
**/
@Retention(RetentionPolicy.RUNTIME)
@Target({ElementType.METHOD})
@Documented
public @interface RedisLock {
String lockPrefix() default "";
String lockKey() default "";
//是否使用自定义过期时间,false->配置文件获取;true->自己指定过期时间
boolean expireConfig() default true;
long timeOut() default 30;
TimeUnit timeUnit() default TimeUnit.SECONDS;
}
2.aop+redis
利用redis 的setIfAbsent()方法获取锁
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.annotation.Pointcut;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Component;
import java.lang.reflect.Method;
import java.util.HashMap;
import java.util.Map;
import java.util.concurrent.TimeUnit;
/** @Author: best_liu
* @Description:
* @Date: 16:13 2023/9/4
* @Param
* @return
**/
@Aspect
@Component
@Slf4j
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 String EXPIRE_CONFIG = "expireConfig";
@Value("${schedule.expire}")
private long timeOut;
@Autowired
private RedisTemplate redisTemplate;
@Pointcut("@annotation(com.mes.dispatch.annotation.redisLock.RedisLock)")
public void redisLockAspect() {
}
@Around("redisLockAspect()")
public void lockAroundAction(ProceedingJoinPoint proceeding) throws Exception {
//获取注解中的参数
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);
boolean expireConfig = (boolean) annotationArgs.get(EXPIRE_CONFIG);
//分布式锁
boolean lock = false;
try {
//如果返回true,说明key不存在,获取到锁
lock = redisTemplate.opsForValue().setIfAbsent(key, lockPrefix);
log.info("是否获取到锁:" + lock);
if (lock) {
log.info("获取到锁,开启定时任务!");
//设置过期时间
if (expireConfig) {
redisTemplate.expire(key, expire, TimeUnit.SECONDS);
} else {
redisTemplate.expire(key, timeOut, TimeUnit.SECONDS);
}
proceeding.proceed();
} else {
log.info("其他系统正在执行此项任务");
return;
}
} catch (Exception e) {
e.printStackTrace();
} catch (Throwable throwable) {
throw new RuntimeException("分布式锁执行发生异常" + throwable.getMessage(), throwable);
}
}
/**
* 获取锁参数
*
* @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()));
result.put(EXPIRE_CONFIG, redisLock.expireConfig());
return result;
}
}
return null;
}
}