ZCo*_*ode 7 spring spring-cloud spring-cloud-consul
我有一个监控应用程序,其中正在运行固定速率任务。这是拉入用 Consul 配置的配置参数。我想引入更新的配置,所以我添加了@RefreshScope。但是,一旦我更新 Consul 上的配置值,fixedRate 任务就会停止运行。
@Service
@RefreshScope
public class MonitorService {
@Autowired
private AppConfig appConfig;
@PostConstruct
public void postConstRun() {
System.out.println(appConfig.getMonitorConfig());
}
@Scheduled(fixedRate = 1000)
public void scheduledMonitorScan() {
System.out.println("MonitorConfig:" + appConfig.getMonitorConfig());
}
}
Run Code Online (Sandbox Code Playgroud)
AppConfig 类只有一个 String 参数:
@Configuration
@Getter
@Setter
public class AppConfig {
@Value("${monitor-config:default value}")
private String monitorConfig;
}
Run Code Online (Sandbox Code Playgroud)
一旦我更新领事中的值,计划任务就会停止运行(在 sheduledMonitorScan 方法中显示)并停止显示。
小智 9
我成功地获取并覆盖了来自领事配置服务器的值RefreshScopeRefreshedEvent
import java.text.SimpleDateFormat;
import java.util.Date;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.cloud.context.config.annotation.RefreshScope;
import org.springframework.cloud.context.scope.refresh.RefreshScopeRefreshedEvent;
import org.springframework.context.ApplicationListener;
import org.springframework.scheduling.annotation.Scheduled;
import org.springframework.stereotype.Component;
@Component
@RefreshScope
public class AlertSchedulerCron implements ApplicationListener<RefreshScopeRefreshedEvent> {
private SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
@Value("${pollingtime}")
private String pollingtime;
/*
* @Value("${interval}") private String interval;
*/
@Scheduled(cron = "${pollingtime}")
//@Scheduled(fixedRateString = "${interval}" )
public void task() {
System.out.println(pollingtime);
System.out.println("Scheduler (cron expression) task with duration : " + sdf.format(new Date()));
}
@Override
public void onApplicationEvent(RefreshScopeRefreshedEvent event) {
// TODO Auto-generated method stub
}
}
Run Code Online (Sandbox Code Playgroud)
以下是我们解决此问题的方法。
/**
* Listener of Spring's lifecycle to revive Scheduler beans, when spring's
* scope is refreshed.
* <p>
* Spring is able to restart beans, when we change their properties. Such a
* beans marked with RefreshScope annotation. To make it work, spring creates
* <b>lazy</b> proxies and push them instead of real object. The issue with
* scope refresh is that right after refresh in order for such a lazy proxy
* to be actually instantiated again someone has to call for any method of it.
* <p>
* It creates a tricky case with Schedulers, because there is no bean, which
* directly call anything on any Scheduler. Scheduler lifecycle is to start
* few threads upon instantiation and schedule tasks. No other bean needs
* anything from them.
* <p>
* To overcome this, we had to create artificial method on Schedulers and call
* them, when there is a scope refresh event. This actually instantiates.
*/
@RequiredArgsConstructor
public class RefreshScopeListener implements ApplicationListener<RefreshScopeRefreshedEvent> {
private final List<RefreshScheduler> refreshSchedulers;
@Override
public void onApplicationEvent(RefreshScopeRefreshedEvent event) {
refreshSchedulers.forEach(RefreshScheduler::materializeAfterRefresh);
}
}
Run Code Online (Sandbox Code Playgroud)
因此,我们定义了一个接口,它不执行任何具体操作,但允许我们调用刷新的作业。
public interface RefreshScheduler {
/**
* Used after refresh context for scheduler bean initialization
*/
default void materializeAfterRefresh() {
}
}
Run Code Online (Sandbox Code Playgroud)
这里是实际的作业,其参数from.properties可以刷新。
public class AJob implements RefreshScheduler {
@Scheduled(cron = "${from.properties}")
public void aTask() {
// do something useful
}
}
Run Code Online (Sandbox Code Playgroud)
更新:当然AJob bean必须在@Configuration中用@RefreshScope标记
@Configuration
@EnableScheduling
public class SchedulingConfiguration {
@Bean
@RefreshScope
public AJob aJob() {
return new AJob();
}
}
Run Code Online (Sandbox Code Playgroud)
小智 2
我已经通过实现 SchedulingConfigurer 接口来解决这种情况。在这里,我从外部属性文件动态更新“scheduler.interval”属性,即使在执行器刷新之后,调度程序也能正常工作,因为我不再使用@RefreshScope。希望这对您的情况也有帮助。
public class MySchedulerImpl implements SchedulingConfigurer {
@Autowired
private Environment env;
@Bean(destroyMethod = "shutdown")
public Executor taskExecutor() {
return Executors.newScheduledThreadPool(10);
}
@Override
public void configureTasks(final ScheduledTaskRegistrar taskRegistrar) {
taskRegistrar.setScheduler(this.taskExecutor());
taskRegistrar.addTriggerTask(() -> {
//put your code here that to be scheduled
}, triggerContext -> {
final Calendar nextExecutionTime = new GregorianCalendar();
final Date lastActualExecutionTime = triggerContext.lastActualExecutionTime();
if (lastActualExecutionTime == null) {
nextExecutionTime.setTime(new Date());
} else {
nextExecutionTime.setTime(lastActualExecutionTime);
nextExecutionTime.add(Calendar.MILLISECOND, env.getProperty("scheduler.interval", Integer.class));
}
return nextExecutionTime.getTime();
});
}
}
Run Code Online (Sandbox Code Playgroud)
| 归档时间: |
|
| 查看次数: |
7286 次 |
| 最近记录: |