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