Преобразование Spring задачи XML-конфигурации в конфигурацию кода

Я пытаюсь преобразовать конфигурацию XML для использования инфраструктуры задач Spring в чисто конфигурацию кода. Я могу воспроизвести функциональность, но всякий раз, когда я закрываю войну на сервере Tomcat, планировщик задач живет, он зависает (он не зависает с конфигурацией 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) в конфигурации кода, он закрывается, но я беспокоюсь, что может иметь неблагоприятные последствия, поскольку это значение true, когда выполняется через конфигурацию XML. Кроме того, я должен отметить, что класс QueueProcessor выполняет работу, которую я хочу, и я не возражаю, если отсроченные исполнения будут отменены - я просто не хочу, чтобы в настоящее время выполнение потоков было отменено.

Это сообщение, которое я получаю, когда оно зависает:

SEVERE: веб-приложение [/pix-queue-processor] похоже начал поток с именем [ThreadPoolTaskExecutor-1], но не смог остановить его. Вероятно, это приведет к утечке памяти.

Любые идеи о том, что может вызвать повешение? Или, используя этот метод с комментариями, позвольте мне сделать то, что я хочу (не будет убивать запущенную задачу, но отменит отложенные задачи)?

Ответ 1

Ваша конфигурация на основе Java на самом деле не представляет собой конфигурацию XML. Есть как минимум 2 вещи, которые отличаются.

  • Ваш TaskExecutor имеет другой TaskExecutor проводной как ThreadFactory, это не относится к XML, а также запускает другой TaskExecutor.
  • Ваш TaskScheduler использует новый TaskExecutor, тогда как в конфигурации xml используется сконфигурированный.

Если ваша задача завершена при завершении работы, вы можете установить свойство waitForTasksToCompleteOnShutdown на TaskExecutor на 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;
}