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");
}
}