问题描述
我正在尝试使用版本2.3中引入的new options to do graceful shutdown with spring,但是我正努力使计划任务的行为相同。
由于在计划任务执行过程中需要上下文中的有效用户,因此我正在使用DelegatingSecurityContextscheduledexecutorservice
来实现此目标。
以下是我的SchedulingConfigurer
实现示例:
@Configuration
@EnableScheduling
public class ContextSchedulingConfiguration implements SchedulingConfigurer {
@Override
public void configureTasks(ScheduledTaskRegistrar taskRegistrar) {
taskRegistrar.setScheduler(taskExecutor());
}
@Bean
public TaskSchedulerCustomizer taskSchedulerCustomizer() {
return taskScheduler -> {
taskScheduler.setAwaitTerminationSeconds(120);
taskScheduler.setWaitForTasksToCompleteOnShutdown(true);
taskScheduler.setPoolSize(2);
};
}
@Bean
public Executor taskExecutor() {
ThreadPoolTaskScheduler threadPool = new ThreadPoolTaskScheduler();
taskSchedulerCustomizer().customize(threadPool);
threadPool.initialize();
threadPool.setThreadNamePrefix("XXXXXXXXX");
SecurityContext schedulerContext = createSchedulerSecurityContext();
return new DelegatingSecurityContextscheduledexecutorservice(threadPool.getScheduledExecutor(),schedulerContext);
}
private SecurityContext createSchedulerSecurityContext() {
//This is just an example,the actual code makes several changes to the context.
return SecurityContextHolder.createEmptyContext();
}
@Scheduled(initialDelay = 5000,fixedDelay = 15000)
public void run() throws InterruptedException {
System.out.println("Started at: " + LocalDateTime.Now().toString());
long until = System.currentTimeMillis() + TimeUnit.SECONDS.toMillis(30);
while (System.currentTimeMillis() < until) {}
System.out.println("Ended at: " + LocalDateTime.Now().toString());
}
}
但是当我在任务任务正在运行时发送终止信号时,应用程序不会等待任务。
如果在我的bean taskExecutor
中替换最后两行,不带上下文返回ThreadPoolTaskScheduler
,则一切正常。仅当我返回DelegatingSecurityContextscheduledexecutorservice
时它才起作用。
如何设置taskExecutor
的上下文并同时配置为等待任务在关闭时完成?
我已经尝试使用TaskScheduler和TaskExecutor接口的另一种实现方式尝试了此代码的几种变体,但没有成功。
解决方法
对于初学者来说,清理代码并在bean方法中使用正确的返回类型(具体而言),并将两者都公开为bean(将一个标记为@Primary
!)。
@Configuration
@EnableScheduling
public class ContextSchedulingConfiguration implements SchedulingConfigurer {
@Override
public void configureTasks(ScheduledTaskRegistrar taskRegistrar) {
taskRegistrar.setScheduler(securitytaskScheduler());
}
@Bean
public ThreadPoolTaskScheduler taskScheduler() {
ThreadPoolTaskScheduler taskScheduler= new ThreadPoolTaskScheduler();
taskScheduler.setAwaitTerminationSeconds(120);
taskScheduler.setWaitForTasksToCompleteOnShutdown(true);
taskScheduler.setPoolSize(2);
taskScheduler.setThreadNamePrefix("XXXXXXXXX");
return taskScheduler;
}
@Bean
@Primary
public DelegatingSecurityContextScheduledExecutorService securitytaskScheduler() {
SecurityContext schedulerContext = createSchedulerSecurityContext();
return new DelegatingSecurityContextScheduledExecutorService(taskScheduler().getScheduledExecutor(),schedulerContext);
}
private SecurityContext createSchedulerSecurityContext() {
//This is just an example,the actual code makes several changes to the context.
return SecurityContextHolder.createEmptyContext();
}
@Scheduled(initialDelay = 5000,fixedDelay = 15000)
public void run() throws InterruptedException {
System.out.println("Started at: " + LocalDateTime.now().toString());
long until = System.currentTimeMillis() + TimeUnit.SECONDS.toMillis(30);
while (System.currentTimeMillis() < until) {}
System.out.println("Ended at: " + LocalDateTime.now().toString());
}
}
重要的是要尽可能明确您的返回类型。尽早检测到配置类,并检查返回类型以确定要进行的回调。现在ThradPoolTaskScheduler
是DisposableBean
,而Executor
不是,也不会收到回调!!