在使用springboot的时候,定时任务是大多系统都会实现的一个逻辑,在系统中引入了Apollo的统一配置后,我们可以通过修改定时任务执行的时间来动态更新springboot项目中定时任务的执行,Apollo配置如下:
app:
id: smoke_detector
apollo:
meta: http://172.12.31.217:8080
bootstrap:
enabled: true
namespaces: application
eagerLoad:
enabled: true
在启动springboot的类上面我们一般可以加上@EnableApolloConfig()注解来启用Apollo,当然也可在其他可以初始化的地方引入,maven的Apollo引入如下:
<dependency>
<groupId>com.ctrip.framework.apollo</groupId>
<artifactId>apollo-client</artifactId>
<version>1.7.0</version>
</dependency>
定时任务的类如下:
@Component
public class LoginRedisSchedule implements SchedulingConfigurer {
@Resource
private ScheduleSetting scheduleSetting;
@Override
public void configureTasks(ScheduledTaskRegistrar scheduledTaskRegistrar) {
scheduledTaskRegistrar.addTriggerTask(()->{
System.out.println("zzzzzz");
},triggerContext -> {
CronTrigger cronTrigger = new CronTrigger(scheduleSetting.getLoginRedis());
return cronTrigger.nextExecutionTime(triggerContext);
});
}
这个地方需要注意了,千万不要在类上面加注解@RefreshScope ,不要把动态配置的参数放到这里来写,不然会再次重复运行定时任务,造成错误,就像上面的我们可以定义一个setting类来单独写,如下:
@Data
@ConfigurationProperties(prefix = "schedule")
@Configuration
@RefreshScope
public class ScheduleSetting {
@Value("${schedule.login.redis.enable}")
private String loginRedis;
private String follow;
}
记得这个地方一定要加上@RefreshScope注解,通过listener更新的时候才能刷新缓存,在网上其他地方参考的时候形如
@Value("${schedule.login.redis.enable}")
说会自动刷新缓存,我反正是没有刷新过,当然对于
private String follow;
这个是必须使用@RefreshScope注解才能刷新。Apollo更新的监听代码如下:
import com.ctrip.framework.apollo.model.ConfigChange;
import com.ctrip.framework.apollo.model.ConfigChangeEvent;
import org.springframework.beans.BeansException;
import org.springframework.boot.logging.LogLevel;
import org.springframework.boot.logging.LoggingSystem;
import org.springframework.cloud.context.environment.EnvironmentChangeEvent;
import org.springframework.cloud.context.scope.refresh.RefreshScope;
import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationContextAware;
import org.springframework.context.annotation.Configuration;
import javax.annotation.Resource;
/**
* @author liaoyubo
* @version 1.0
* @date 2021/1/20
* @description apollo配置修改监听
*/
@Configuration
public class ApolloConfigChangeListener implements ApplicationContextAware {
@Resource
private LoggingSystem loggingSystem;
@Resource
private RefreshScope refreshScope;
private ApplicationContext applicationContext;
/**
* 日志配置常量
*/
private static final String LOGGER_TAG = "logging.level.";
@Override
public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
this.applicationContext = applicationContext;
}
@com.ctrip.framework.apollo.spring.annotation.ApolloConfigChangeListener
public void onConfigChangeListener(ConfigChangeEvent configChangeEvent) {
/*configChangeEvent.changedKeys()
.stream()
.forEach(key->{
ConfigChange configChange = configChangeEvent.getChange(key);
// 是否为日志配置
if (StringUtils.containsIgnoreCase(key, LOGGER_TAG)) {
// 日志配置刷新
changeLoggingLevel(key, configChange);
}else {
// 更新相应的bean的属性值,主要是存在@ConfigurationProperties注解的bean
applicationContext.publishEvent(new EnvironmentChangeEvent(configChangeEvent.changedKeys()));
refreshScope.refreshAll();
}
});*/
// 更新相应的bean的属性值,主要是存在@ConfigurationProperties注解的bean
applicationContext.publishEvent(new EnvironmentChangeEvent(configChangeEvent.changedKeys()));
refreshScope.refreshAll();
}
/**
* 刷新日志级别
*/
private void changeLoggingLevel(String key, ConfigChange change) {
if (null == loggingSystem) {
return;
}
String newLevel = change.getNewValue();
LogLevel level = LogLevel.valueOf(newLevel.toUpperCase());
loggingSystem.setLogLevel(key.replace(LOGGER_TAG, ""), level);
}
}
就这样,完美了。