监听Apollo配置,无需重启,动态更新定时任务调度时间
痛点:虽然项目集成了携程的开源框架Apollo配置中心,但是在修改Apollo上配置时,spring启动容器时注册的类无法更新属性,需项目重启重新加载。
本编文章研究下,如何动态更新通过@Schedule注入到容器的定时任务的配置。
- 监听Apollo发生的变化
//配置监听的namespace
@ApolloConfigChangeListener("application")
private void onChange(ConfigChangeEvent changeEvent) {
Set<String> changedKeys = changeEvent.changedKeys();
for (String key : changedKeys) {
//拦截以xxx开头的
if (key.startsWith(PREFIX)) {
ConfigChange change = changeEvent.getChange(key);
log.debug("Apollo LAMA config[{}] changed from [{}] to [{}]", key, change.getOldValue(), change.getNewValue());
switch (key) {
//监听到目标key
case xxx.xxx.xxx:
//执行对应逻辑
reloadScheduledTask(xxx);
break;
default:
log.info("暂不支持该定时任务的动态更新,key:{}", key);
}
}
}
}
- 移除任务,重新加载任务
//注入spring 定时任务控制类
@Autowired
private ScheduledAnnotationBeanPostProcessor postProcessor;
/**
* 通过 ScheduledAnnotationBeanPostProcessor 终止定时任务-重新启动定时任务
*/
public void reloadScheduledTask(xxx) {
// 拿到所有的task
Set<ScheduledTask> tasks = postProcessor.getScheduledTasks();
Object taskObject = null;
for (ScheduledTask task : tasks) {
Task t = task.getTask();
ScheduledMethodRunnable runnable = (ScheduledMethodRunnable) t.getRunnable();
if (StringUtils.equalsIgnoreCase(xxx, StringUtils.substringBefore(runnable.getTarget().getClass().getSimpleName(), "$$"))) {
taskObject = runnable.getTarget();
break;
}
}
if (taskObject == null) {
return;
}
log.info("==============重新加载class:{}=============", taskObject.getClass().getName());
// 调用postProcessBeforeDestruction()方法,将task移除并cancel
postProcessor.postProcessBeforeDestruction(taskObject, "scheduledTasks");
// 调用postProcessAfterInitialization()方法重新schedule task
postProcessor.postProcessAfterInitialization(taskObject, "scheduledTasks");
}
- 后面在研究一下,如何动态加载 @Bean 注入的类,实现热部署