正在将 Spring 任务 XML 配置转换为代码配置
Converting Spring task XML configuration to code configuration
我正在尝试将使用 Spring 任务框架的 XML 配置转换为纯代码配置。我能够重现该功能,但每当我关闭任务调度程序所在的 Tomcat 服务器上的 war 时,它就会挂起(它不会因 XML 配置而挂起)。我已经调试以检查调度程序和执行程序的实例,但我没有看到任何区别,所以我不确定是什么导致它挂起。
这是有效的 XML 配置:
<beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:task="http://www.springframework.org/schema/task"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.1.xsd
http://www.springframework.org/schema/task http://www.springframework.org/schema/task/spring-task-3.1.xsd">
<task:executor id="com.work.gwx.pix.executor"
pool-size="${pix.job.executor.pool.size:1-40}"
queue-capacity="${pix.job.executor.queue.capacity:0}"
rejection-policy="CALLER_RUNS"/>
<task:scheduler id="com.work.gwx.pix.scheduler" pool-size="${pix.job.scheduler.pool.size:4}" />
<task:annotation-driven executor="com.work.gwx.pix.executor" scheduler="com.work.gwx.pix.scheduler" />
<bean id='queueProcessor' class="com.work.gwx.queueing.QueueProcessor" />
</beans>
代码配置如下:
@EnableAsync
@EnableScheduling
@Configuration
public class TaskConfiguration implements AsyncConfigurer, SchedulingConfigurer {
@Value("${pix.job.executor.max.pool.size:1}")
private int executorMaxPoolSize;
@Value("${pix.job.executor.queue.capacity:0}")
private int executorQueueCapacity;
@Value("${pix.job.scheduler.pool.size:4}")
private int schedulerPoolSize;
@Bean(destroyMethod = "shutdown")
public Executor pixTaskScheduler() {
final ScheduledThreadPoolExecutor ex = new ScheduledThreadPoolExecutor(schedulerPoolSize, new ThreadPoolTaskExecutor());
// ex.setExecuteExistingDelayedTasksAfterShutdownPolicy(false);
return ex;
}
@Bean
public Executor pixExecutor() {
final ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor();
executor.setCorePoolSize(executorMaxPoolSize);
executor.setQueueCapacity(executorQueueCapacity);
executor.setRejectedExecutionHandler(new ThreadPoolExecutor.CallerRunsPolicy());
executor.setThreadFactory(new ThreadPoolTaskExecutor());
executor.initialize();
return executor;
}
@Override
public void configureTasks(final ScheduledTaskRegistrar taskRegistrar) {
taskRegistrar.setScheduler(pixTaskScheduler());
}
@Override
public Executor getAsyncExecutor() {
return pixExecutor();
}
@Override
public AsyncUncaughtExceptionHandler getAsyncUncaughtExceptionHandler() {
return new SimpleAsyncUncaughtExceptionHandler();
}
}
当我在代码配置中使用 setExecuteExistingDelayedTasksAfterShutdownPolicy(false)
时,它确实会关闭,但我担心这可能会产生不利影响,因为在通过 XML 配置完成时它被设置为 true。另外,我应该注意,QueueProcessor class 正在做我想要的工作,我不介意延迟执行是否被取消——我只是不希望当前正在执行的线程被突然取消。
这是挂起时我收到的消息:
SEVERE: The web application [/pix-queue-processor] appears to have
started a thread named [ThreadPoolTaskExecutor-1] but has failed to
stop it. This is very likely to create a memory leak.
关于可能导致挂起的原因有什么想法吗?或者,使用那个注释掉的方法会让我做我想做的事吗(不会终止 运行 任务但会取消延迟的任务)?
您基于 Java 的配置并不是 XML 配置的真正代表。至少有两处不同。
- 您的
TaskExecutor
有另一个 TaskExecutor
连线为 ThreadFactory
这在 XML 中不是这种情况并且还启动了另一个 TaskExecutor
。
- 您的
TaskScheduler
使用新的 TaskExecutor
而 xml 配置使用配置的那个。
如果您的任务在关机时完成,您可以将 TaskExecutor
上的 waitForTasksToCompleteOnShutdown
属性 设置为 true
然后所有待处理的任务都将完成并且没有新任务将被接受。
也不需要调用 initialize
,因为 afterPropertiesSet
方法将由 Spring 调用,后者又调用 initialize
。
以下 2 个 bean 定义更符合 XML 配置(你现在有一个 TaskExecutor
而不是 3 个,它会在关闭前先完成任务。
@Bean(destroyMethod = "shutdown")
public Executor pixTaskScheduler() {
final ScheduledThreadPoolExecutor ex = new ScheduledThreadPoolExecutor(schedulerPoolSize, pixExecutor());
// ex.setExecuteExistingDelayedTasksAfterShutdownPolicy(false);
return ex;
}
@Bean
public Executor pixExecutor() {
final ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor();
executor.setCorePoolSize(executorMaxPoolSize);
executor.setQueueCapacity(executorQueueCapacity);
executor.setRejectedExecutionHandler(new ThreadPoolExecutor.CallerRunsPolicy());
executor.setWaitForTasksToCompleteOnShutdown(true);
return executor;
}
我正在尝试将使用 Spring 任务框架的 XML 配置转换为纯代码配置。我能够重现该功能,但每当我关闭任务调度程序所在的 Tomcat 服务器上的 war 时,它就会挂起(它不会因 XML 配置而挂起)。我已经调试以检查调度程序和执行程序的实例,但我没有看到任何区别,所以我不确定是什么导致它挂起。
这是有效的 XML 配置:
<beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:task="http://www.springframework.org/schema/task"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.1.xsd
http://www.springframework.org/schema/task http://www.springframework.org/schema/task/spring-task-3.1.xsd">
<task:executor id="com.work.gwx.pix.executor"
pool-size="${pix.job.executor.pool.size:1-40}"
queue-capacity="${pix.job.executor.queue.capacity:0}"
rejection-policy="CALLER_RUNS"/>
<task:scheduler id="com.work.gwx.pix.scheduler" pool-size="${pix.job.scheduler.pool.size:4}" />
<task:annotation-driven executor="com.work.gwx.pix.executor" scheduler="com.work.gwx.pix.scheduler" />
<bean id='queueProcessor' class="com.work.gwx.queueing.QueueProcessor" />
</beans>
代码配置如下:
@EnableAsync
@EnableScheduling
@Configuration
public class TaskConfiguration implements AsyncConfigurer, SchedulingConfigurer {
@Value("${pix.job.executor.max.pool.size:1}")
private int executorMaxPoolSize;
@Value("${pix.job.executor.queue.capacity:0}")
private int executorQueueCapacity;
@Value("${pix.job.scheduler.pool.size:4}")
private int schedulerPoolSize;
@Bean(destroyMethod = "shutdown")
public Executor pixTaskScheduler() {
final ScheduledThreadPoolExecutor ex = new ScheduledThreadPoolExecutor(schedulerPoolSize, new ThreadPoolTaskExecutor());
// ex.setExecuteExistingDelayedTasksAfterShutdownPolicy(false);
return ex;
}
@Bean
public Executor pixExecutor() {
final ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor();
executor.setCorePoolSize(executorMaxPoolSize);
executor.setQueueCapacity(executorQueueCapacity);
executor.setRejectedExecutionHandler(new ThreadPoolExecutor.CallerRunsPolicy());
executor.setThreadFactory(new ThreadPoolTaskExecutor());
executor.initialize();
return executor;
}
@Override
public void configureTasks(final ScheduledTaskRegistrar taskRegistrar) {
taskRegistrar.setScheduler(pixTaskScheduler());
}
@Override
public Executor getAsyncExecutor() {
return pixExecutor();
}
@Override
public AsyncUncaughtExceptionHandler getAsyncUncaughtExceptionHandler() {
return new SimpleAsyncUncaughtExceptionHandler();
}
}
当我在代码配置中使用 setExecuteExistingDelayedTasksAfterShutdownPolicy(false)
时,它确实会关闭,但我担心这可能会产生不利影响,因为在通过 XML 配置完成时它被设置为 true。另外,我应该注意,QueueProcessor class 正在做我想要的工作,我不介意延迟执行是否被取消——我只是不希望当前正在执行的线程被突然取消。
这是挂起时我收到的消息:
SEVERE: The web application [/pix-queue-processor] appears to have started a thread named [ThreadPoolTaskExecutor-1] but has failed to stop it. This is very likely to create a memory leak.
关于可能导致挂起的原因有什么想法吗?或者,使用那个注释掉的方法会让我做我想做的事吗(不会终止 运行 任务但会取消延迟的任务)?
您基于 Java 的配置并不是 XML 配置的真正代表。至少有两处不同。
- 您的
TaskExecutor
有另一个TaskExecutor
连线为ThreadFactory
这在 XML 中不是这种情况并且还启动了另一个TaskExecutor
。 - 您的
TaskScheduler
使用新的TaskExecutor
而 xml 配置使用配置的那个。
如果您的任务在关机时完成,您可以将 TaskExecutor
上的 waitForTasksToCompleteOnShutdown
属性 设置为 true
然后所有待处理的任务都将完成并且没有新任务将被接受。
也不需要调用 initialize
,因为 afterPropertiesSet
方法将由 Spring 调用,后者又调用 initialize
。
以下 2 个 bean 定义更符合 XML 配置(你现在有一个 TaskExecutor
而不是 3 个,它会在关闭前先完成任务。
@Bean(destroyMethod = "shutdown")
public Executor pixTaskScheduler() {
final ScheduledThreadPoolExecutor ex = new ScheduledThreadPoolExecutor(schedulerPoolSize, pixExecutor());
// ex.setExecuteExistingDelayedTasksAfterShutdownPolicy(false);
return ex;
}
@Bean
public Executor pixExecutor() {
final ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor();
executor.setCorePoolSize(executorMaxPoolSize);
executor.setQueueCapacity(executorQueueCapacity);
executor.setRejectedExecutionHandler(new ThreadPoolExecutor.CallerRunsPolicy());
executor.setWaitForTasksToCompleteOnShutdown(true);
return executor;
}