第一步. 自动配置类
主启动类添加:@EnableScheduling //开启定时任务aop和redis POM添加:
<!--redis驱动--><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-data-redis</artifactId></dependency><!--aop面向切面编程--><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-aop</artifactId></dependency>
自定义分布式定时任务注解
/*** @program:* @description: 定时任务锁* @author: wangZhiDong* @created: /11/29 09:06*/@Target(ElementType.METHOD)@Retention(RetentionPolicy.RUNTIME)@Documentedpublic @interface TaskLock {/*** 定时任务名称* @return*/String name() default "";/*** redis缓存key值* @return*/String key();/*** 过期时间单位s (自动解锁时间,防止死锁)* @return*/int expired();/*** 执行完毕是否解锁* @return*/boolean unLock() default true;}
定义分布式定时任务 切面具体实现
/*** @program:* @description: 定时任务锁切面* @author: wangZhiDong* @created: /10/29 09:12*/@Aspect@Component@Slf4j@AllArgsConstructor@Order(10)public class TaskLockAspect {private RedisTemplate redisTemplate;@Pointcut("@annotation(com.wang.timedtask.annotation.TaskLock)")public void TaskLockAspect() {}@Around("TaskLockAspect() && @annotation(taskLock)")public Object doAround(ProceedingJoinPoint proceedingJoinPoint,TaskLock taskLock) throws Throwable {String value = UUID.randomUUID().toString();try {if (lock(taskLock.key(), value, taskLock.expired())) {return proceedingJoinPoint.proceed();}} catch (Exception e) {log.error("定时任务执行失败,{}", taskLock.key(), e);} finally {// 执行完毕解除锁if (!taskLock.unLock()) {return null;}String lockValue = getLockValue(taskLock.key());if (StringUtils.isEmpty(lockValue) || !lockValue.equals(value)) {return null;}// 解锁设置为延时1SunLock(taskLock.key());}return null;}/*** 加锁* @param key* @param value* @param time* @return*/public boolean lock(String key , String value , int time){return redisTemplate.opsForValue().setIfAbsent(key , value , time , TimeUnit.SECONDS);}/*** 解锁* @param key*/public void unLock(String key){redisTemplate.expire(key , 1 , TimeUnit.SECONDS);}/*** 获取锁值* @param key* @return*/public String getLockValue(String key){return (String) redisTemplate.opsForValue().get(key);}}
简单使用
/*** @Author wangZhiDong* @Date /8/22* 启动数据纠正**/@Slf4j@Componentpublic class TransferService {public static int num = 0;DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss");@Scheduled(cron = "0/5 * * * * ?")@TaskLock(name = "测试分布式定时任务5秒执行一次", key = "test_task",expired = 5)public void start(){num++;System.out.println(LocalDateTime.now().format(formatter)+"第"+num+"次执行的是第一个");}/*** 使用 public 的 定时任务才行*/@Scheduled(cron = "0/5 * * * * ?")@TaskLock(name = "测试分布式定时任务5秒执行一次", key = "test_task",expired = 5)public void start2(){TransferService.num++;System.out.println(LocalDateTime.now().format(formatter)+"第"+TransferService.num+"次执行的是第二个");}@Scheduled(cron = "0/5 * * * * ?")@TaskLock(name = "测试分布式定时任务5秒执行一次", key = "test_task",expired = 5)public void start3(){TransferService.num++;System.out.println(LocalDateTime.now().format(formatter)+"第"+TransferService.num+"次执行的是第三个");}}
执行结果:
-12-01 14:35:40第1次执行的是第一个
-12-01 14:35:45第2次执行的是第二个
-12-01 14:35:50第3次执行的是第三个
-12-01 14:35:55第4次执行的是第三个
-12-01 14:36:00第5次执行的是第二个
-12-01 14:36:05第6次执行的是第一个
-12-01 14:36:10第7次执行的是第三个
-12-01 14:36:15第8次执行的是第一个
-12-01 14:36:20第9次执行的是第二个
-12-01 14:36:25第10次执行的是第三个
-12-01 14:36:30第11次执行的是第一个
...