第一步. 自动配置类

  • 主启动类添加:@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: 2021/11/29 09:06
 */
@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @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: 2021/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;
            }
            // 解锁设置为延时1S
            unLock(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 2021/8/22
 * 启动数据纠正
 **/
@Slf4j
@Component
public 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+"次执行的是第三个");
    }


}

执行结果:

2021-12-01 14:35:40第1次执行的是第一个
2021-12-01 14:35:45第2次执行的是第二个
2021-12-01 14:35:50第3次执行的是第三个
2021-12-01 14:35:55第4次执行的是第三个
2021-12-01 14:36:00第5次执行的是第二个
2021-12-01 14:36:05第6次执行的是第一个
2021-12-01 14:36:10第7次执行的是第三个
2021-12-01 14:36:15第8次执行的是第一个
2021-12-01 14:36:20第9次执行的是第二个
2021-12-01 14:36:25第10次执行的是第三个
2021-12-01 14:36:30第11次执行的是第一个
...