nacos+定时任务动态配置 @Scheduled定时器

2022-09-04 12:57:50
maven 依赖添加   该依赖可以动态监听nacos配置文件修改
<dependency>
<groupId>com.purgeteam</groupId>
<artifactId>dynamic-config-spring-boot-starter</artifactId>
<version>0.1.1.RELEASE</version>
</dependency>
启动类加注解
@EnableDynamicConfigEvent
nacos +定时任务时间 实现动态配置
添加以下文件:
AbstractDynamicSchedule.java
NacosCronDataIdChangeListener.java
TestSchedule.java
TestSchedule内有三个方法:
taskName():定时任务名。
cronKey()
nacos配置
run()
里面写定时任务的逻辑
package cn.witsky.qydx.project.test;

/**
 * @author chenmingjing
 * @program ezd-backend
 * @description
 * @date 2022/04/08 10:05
 **/
public interface AbstractDynamicSchedule extends Runnable {

    /**
     * 任务名称
     * @return 返回执行任务名称用于打日志
     */
    String taskName();

    /**
     * 任务的cron表达式yaml key
     * @return yaml key
     */
    String cronKey();

}
package cn.witsky.qydx.project.business.manager;

import cn.witsky.qydx.project.test.AbstractDynamicSchedule;
import com.google.common.collect.Lists;
import com.purgeteam.dynamic.config.starter.event.ActionConfigEvent;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationListener;
import org.springframework.scheduling.annotation.SchedulingConfigurer;
import org.springframework.scheduling.concurrent.ConcurrentTaskScheduler;
import org.springframework.scheduling.config.CronTask;
import org.springframework.scheduling.config.ScheduledTaskRegistrar;
import org.springframework.stereotype.Component;

import javax.annotation.Resource;
import java.util.Collection;
import java.util.Map;
import java.util.Objects;
import java.util.Optional;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ScheduledFuture;

/**

 * @author Administrator

 * @date 2022/4/8 10:30
 */
@Component
@Slf4j
public class NacosCronDataIdChangeListener implements ApplicationListener<ActionConfigEvent>, SchedulingConfigurer {

    private ScheduledTaskRegistrar taskRegistrar;
    private static final ConcurrentHashMap<String, ScheduledFuture<?>> SCHEDULED_FUTURES = new ConcurrentHashMap<>();
    private static final ConcurrentHashMap<String, CronTask> CRON_TASKS = new ConcurrentHashMap<>();
    @Resource
    private ApplicationContext applicationContext;
    /**

     * 存储所有动态定时任务处理类
     */
    @Resource
    private Map<String, AbstractDynamicSchedule> scheduleMap;

    @Override
    public void onApplicationEvent(ActionConfigEvent  event) {

        Collection<AbstractDynamicSchedule> editCronScheduleMap = Lists.newArrayList();
        // 对比每一个配置
        scheduleMap.keySet().forEach(schedule -> {
            AbstractDynamicSchedule bean = (AbstractDynamicSchedule) applicationContext.getBean(schedule);
            String cronKey = bean.cronKey();
            CronTask cronTask = CRON_TASKS.get(cronKey);
            if (Objects.isNull(cronTask)) {
                // 新增
                editCronScheduleMap.add(scheduleMap.get(schedule));
                return;
            }
            if(event.getPropertyMap()==null||event.getPropertyMap().get(cronKey)==null){
                return;
            }
            String oldCronValue = cronTask.getExpression();
            String newCronValue = (String) event.getPropertyMap().get(cronKey).get("after");

            if (Objects.equals(oldCronValue, newCronValue)) {
                log.info("task time not change , cronKey={}, oldCronValue={}", cronKey, oldCronValue);
                return;
            }

            // 发生了变化
            editCronScheduleMap.add(scheduleMap.get(schedule));
        });

        this.refreshTasks(editCronScheduleMap);

    }

    public void refreshTasks(Collection<AbstractDynamicSchedule> tasks) {

        tasks.forEach(schedule -> {

            String cronKey = schedule.cronKey();

            // 取消已经删除的策略任务
            if ("-".equals(cronKey) || StringUtils.isBlank(cronKey)) {
                cancel(cronKey);
                log.info("取消已经删除的策略任务, taskName={}, cronKey={}", schedule.taskName(), schedule.cronKey());
                return;
            }

            String cronNewValue = applicationContext.getEnvironment().getProperty(cronKey);

            // 新的值为取消定时任务
            if ("-".equals(cronNewValue) || StringUtils.isBlank(cronNewValue)) {
                cancel(cronKey);
                log.info("定时任务关闭, taskName={}, cronKey={}", schedule.taskName(), schedule.cronKey());
                return;
            }

            // 定时任务没有发生任何变化
            if (SCHEDULED_FUTURES.containsKey(cronKey) && CRON_TASKS.get(cronKey).getExpression().equals(cronNewValue)) {
                log.info("定时任务没有发生任何变化, taskName={}, cronKey={}", schedule.taskName(), schedule.cronKey());
                return;
            }

            // 如果策略执行时间发生了变化,则取消当前策略的任务
            boolean isUpdate = SCHEDULED_FUTURES.containsKey(cronKey) && cancel(cronKey);

            CronTask task = new CronTask(schedule, cronNewValue);
            CRON_TASKS.put(cronKey, task);
            ScheduledFuture<?> future = Optional.ofNullable(taskRegistrar.getScheduler())
                    .orElse(new ConcurrentTaskScheduler()).schedule(task.getRunnable(), task.getTrigger());
            SCHEDULED_FUTURES.put(cronKey, future);

            if (isUpdate) {
                log.info("定时任务修改, taskName={}, cronKey={}, taskNewCron={}",
                        schedule.taskName(), cronKey, cronNewValue);
            } else {
                log.info("定时任务新增, taskName={}, cronKey={}, taskCron={}",
                        schedule.taskName(), cronKey, cronNewValue);
            }

        });

    }

    private boolean cancel(String cronKey) {
        ScheduledFuture<?> future = SCHEDULED_FUTURES.get(cronKey);
        if (Objects.nonNull(future)) {
            SCHEDULED_FUTURES.get(cronKey).cancel(false);
        }
        SCHEDULED_FUTURES.remove(cronKey);
        CRON_TASKS.remove(cronKey);
        return true;
    }

    @Override
    public void configureTasks(ScheduledTaskRegistrar taskRegistrar) {

        this.taskRegistrar = taskRegistrar;

        this.refreshTasks(scheduleMap.values());

    }

}
package cn.witsky.qydx.project.test;

import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Component;

import java.util.Date;

/**
 * @author chenmingjing
 * @program ezd-backend
 * @description
 * @date 2022/04/08 11:05
 **/
@Slf4j
@Component
public class TestSchedule implements AbstractDynamicSchedule {

    @Override
    public String taskName() {
        return "测试定时任务";
    }

    @Override
    public String cronKey() {
        return "test-dynamic-schedule";
    }

    @Override
    public void run() {
        log.debug(new Date() + "----1");
    }
}
  • 作者:码java的秃头阿姨
  • 原文链接:https://blog.csdn.net/qq_39477018/article/details/124325975
    更新时间:2022-09-04 12:57:50