Spring Web アプリケーションには、複数の DAO およびサービス レイヤー Bean があります。1 つのサービス レイヤー Bean には、@Async / @Scheduled メソッドがアノテーションされています。これらのメソッドは、他の (自動接続された) Bean に依存します。XML で 2 つのスレッド プールを構成しました。
<bean id="taskExecutor" class="org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor">
<property name="corePoolSize" value="2" />
<property name="maxPoolSize" value="5" />
<property name="queueCapacity" value="5" />
<property name="waitForTasksToCompleteOnShutdown" value="true" />
<property name="rejectedExecutionHandler">
<bean class="java.util.concurrent.ThreadPoolExecutor$CallerRunsPolicy"/>
</property>
</bean>
<bean id="taskScheduler" class="org.springframework.scheduling.concurrent.ThreadPoolTaskScheduler">
<property name="poolSize" value="10" />
<property name="waitForTasksToCompleteOnShutdown" value="true" />
<property name="rejectedExecutionHandler">
<bean class="java.util.concurrent.ThreadPoolExecutor$CallerRunsPolicy"/>
</property>
</bean>
<task:annotation-driven executor="taskExecutor" scheduler="taskScheduler"/>
すべて期待どおりに動作します。問題は、タスク プールを正常にシャットダウンできないことです。タスクはデータベースとファイル システムで動作します。Web アプリケーションを停止すると、停止するまでにしばらく時間がかかります。これは、プロパティがwaitForTasksToCompleteOnShutdown
動作していることを示しています。ただし、ログには IllegalStateExceptions が表示され、一部の Bean はすでに破棄されているものの、一部のワーカー タスク スレッドはまだ実行中であり、依存関係が破棄されたために失敗していることを示しています。
関連する可能性のある JIRA の問題があります:5387 円
私の質問は、Spring にタスク エグゼキュータ/スケジューラ Bean を最後に初期化するように指示する方法はありますか、それとも、Spring に最初にそれらを破棄するように指示する方法はありますか?
私の理解では、破棄は init の逆順に行われます。したがって、最後に init された Bean が最初に破棄されます。スレッド プール Bean が最初に破棄された場合、現在実行中のすべてのタスクが終了し、依存する Bean に引き続きアクセスできます。
また、@Async および @Scheduled アノテーションを持つサービス Bean を参照するスレッド プールで、depends-on 属性を使用することも試みました。その場合、それらは実行されないようで、コンテキスト初期化エラーは発生しません。アノテーション付きサービス Bean では、何らかの理由でこれらのスレッド プールを最初に初期化する必要があると想定しており、depends-on を使用すると順序が逆になり、機能しなくなります。
ベストアンサー1
ふたつのやり方:
Bean を実装します
ApplicationListener<ContextClosedEvent>
。onApplicationEvent()
コンテキストの前に呼び出され、すべての Bean が破棄されます。豆の道具を持っているライフサイクルまたはスマートライフサイクル. は
stop()
コンテキストの前に呼び出され、すべての Bean が破棄されます。
どちらの方法でも、Bean 破棄メカニズムが実行される前にタスクの処理をシャットダウンできます。
例えば:
@Component
public class ContextClosedHandler implements ApplicationListener<ContextClosedEvent> {
@Autowired ThreadPoolTaskExecutor executor;
@Autowired ThreadPoolTaskScheduler scheduler;
@Override
public void onApplicationEvent(ContextClosedEvent event) {
scheduler.shutdown();
executor.shutdown();
}
}
(編集: メソッド シグネチャを修正)