2015-05-13 8 views
11

Ich versuche, die XML-Konfiguration für die Verwendung des Spring-Aufgaben-Frameworks in eine reine Code-Konfiguration zu konvertieren. Ich bin in der Lage, die Funktionalität zu reproduzieren, aber jedes Mal, wenn ich den Krieg auf dem Tomcat-Server herunterfahre, auf dem der Task-Scheduler läuft, bleibt er hängen (er hängt nicht mit der XML-Konfiguration). Ich habe getestet, um die Instanzen von Scheduler und Executor zu überprüfen, aber ich sehe keinen Unterschied, so dass ich nicht sicher bin, was es verursachen könnte. HierUmwandlung der Spring-Task-XML-Konfiguration in Code-Konfiguration

ist die XML-Konfiguration, die funktioniert:

<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> 

Hier ist der Code-Konfiguration:

@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(); 
    } 
} 

Wenn ich setExecuteExistingDelayedTasksAfterShutdownPolicy(false) in Code-Konfiguration verwenden, wird es heruntergefahren, aber ich mache mir Sorgen, dass Macht nachteilige Auswirkungen haben, wenn dies über die XML-Konfiguration geschieht. Außerdem sollte ich anmerken, dass die QueueProcessor-Klasse die Arbeit macht, die ich möchte, und es macht mir nichts aus, wenn verzögerte Ausführungen abgebrochen werden - ich möchte gerade nicht, dass die Ausführung von Threads abrupt abgebrochen wird.

Dies ist die Botschaft, die ich erhalten, wenn es hängt:

SCHWEREN: Die Web-Anwendung [/ pix-Queue-Prozessor] begann einen Thread namens [ThreadPoolTaskExecutor-1] aber hat es versäumt zu haben scheint Hör auf. Dies führt sehr wahrscheinlich zu einem Speicherleck.

Irgendwelche Ideen auf, was das Hängen verursachen könnte? Oder würde ich mit dieser auskommentierten Methode tun, was ich will (wird eine laufende Aufgabe nicht töten, aber verzögerte Aufgaben abbrechen)?

+0

Eines der Probleme, die ich sehe, ist dass Sie einen neuen 'ThreadPoolTaskExecutor 'als' ThreadFactory' setzen? Warum? Sie haben jetzt im Grunde zwei Task Executors, von denen einer kontrolliert wird und der andere nicht wirklich. –

+0

Ein anderer Grund ist, warum Sie Ihren 'TaskExecutor' nicht an Ihren 'TaskScheduler'? Das verwendet einen weiteren nicht verwalteten' TaskExecutor'. –

Antwort

4

Ihre Java-basierte Konfiguration ist nicht wirklich eine Darstellung der XML-Konfiguration. Es gibt mindestens zwei Dinge, die anders sind.

  1. Ihre TaskExecutor hat eine andere TaskExecutor als ThreadFactory verdrahtet dies nicht der Fall in XML ist und startet auch eine andere TaskExecutor.
  2. Ihre TaskScheduler verwendet eine neue TaskExecutor, während die XML-Konfiguration die konfigurierte verwenden.

Die haben Ihre Aufgabe beim Herunterfahren abgeschlossen Sie die waitForTasksToCompleteOnShutdown Eigenschaft auf dem TaskExecutor zu true dann alle anstehenden Aufgaben abgeschlossen sein wird und keine neuen Aufgaben werden akzeptiert einstellen.

Auch der Aufruf an initialize sollte nicht benötigt werden, da die afterPropertiesSet-Methode von Spring aufgerufen wird, die ihrerseits initialize aufruft.

Die folgenden 2 Bohne Definitionen sind mehr im Einklang mit der XML-Konfiguration (und Sie haben jetzt eine einzelnes TaskExecutor statt 3 und es wird zuerst vor dem Herunterfahren Aufgaben beenden.

@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; 
} 
+0

Entschuldigung, ich habe noch nicht geantwortet, da ich nicht in der Stadt war. Sieht vielversprechend aus und sollte es bald testen können. Es macht Sinn, was du sagst. – AHungerArtist

+0

Das scheint zu funktionieren, aber noch eine Frage: Im XML kann ich sowohl dem Executor als auch dem Scheduler einen Namen/eine ID geben. Wie könnte ich das über Code machen? Der ThreadPoolTaskExecutor scheint eine Methode zu haben, aber nicht die Geplante Methode. Dies würde wirklich helfen herauszufinden, welche Threads beim Debuggen daraus kommen. – AHungerArtist

+0

Nein, es wird nicht, weil es nur einen einzigen Thread-Pool gibt. Für den 'ThreadPoolTaskExecutor' können Sie das' threadNamePrefix' verwenden, um ein Präfix hinzuzufügen. Der Scheduler ist jedoch nur ein Scheduler, der den einzelnen ThreadPoolTaskExecutor zum Starten von Tasks verwendet. Wenn Sie das nicht möchten, müssen Sie einen anderen Task Executor hinzufügen, aber das ist nicht das, was Sie in Ihrer XML-Konfiguration haben (oder hatten). –