2013-08-29 91 views
9

我有一個使用多數民衆贊成由具有創建一個Java ExecutorService的Spring管理bean的一個命令行應用程序:如何用Spring正確關閉執行程序服務?

ExecutorService service = Executors.newFixedThreadPool(4); 

現在,我希望我的服務關閉時,我的應用程序關閉,所以我做了我的豆實現DisposableBean接口,並有破壞的方法,如:

public void destroy(){ 
    service.shutdown(); 
} 

然後,我可能會嘗試做一些像登記在Spring上下文關閉掛鉤。然而,我發現(難道,即在預生產版本中),這不起作用:在調用ExecutorService.shutdown()方法之前,關閉掛鉤不會被調用,導致經典的catch 22問題(它會得到呼籲中斷,即如果我在應用程序運行時按Ctrl-C)。這讓我的單元測試失敗了,因爲出於某種原因,它似乎在JUnit中運行良好,這仍然令我困惑:JUnit做了什麼不同?

到目前爲止,我發現的解決方案是在我退出主函數之前明確地調用ApplicationContext.close()。我想知道是否有更好的解決方案,以及由Spring管理靈活的線程池有哪些最佳實踐。另外,如果我的bean是由Spring直接管理的而不是,但是由Spring管理的bean創建?我應該將呼叫級聯到destroy()嗎?這不會很容易出錯嗎?

我很欣賞任何意見,建議,進一步閱讀,RTFMs,魔術食譜。

謝謝!

+0

PS:如果我想將命令行應用程序移動到諸如Tomcat之類的應用程序服務器,該怎麼辦?有什麼改變嗎? –

+0

包括標題和您的PS我計*七*(7!)問號。 :-)如果你只問一個具體問題,可能會得到更好的答覆。 – Keith

回答

24

你知道這個:

ExecutorService service = Executors.newFixedThreadPool(4); 

可以用這個來代替:

<bean id="service" class="java.util.concurrent.Executors" 
     factory-method="newFixedThreadPool" destroy-method="shutdown"> 
    <constructor-arg value="4"/> 
</bean> 

Spring上下文然後管理,更直接,你的執行服務的關閉 - 它可以更容易被重用。

+0

我知道這一點。但是在某些情況下,我寧願以編程方式而不是通過配置來創建我的bean,例如,如果我不知道在運行時需要多少bean,或者特定bean的定義將來自外部源,例如數據庫或消息隊列。 –

+0

算我累了,這是無效的。這不起作用,但在初始化Spring上下文時會導致'InvalidArgumentException'。 – Powerslave

1

%的官方Spring文檔,使用基於註解的配置時,爲@BeandestroyMethod領域,Spring的默認行爲是當應用程序上下文被關閉自動調用名爲closeshutdown公共,無參數的方法。

爲了方便用戶,容器將嘗試推斷從@Bean方法返回的對象的銷燬方法 。對於 示例,如果返回Apache Commons DBCP BasicDataSource的@Bean方法,容器將注意到該對象上可用的close()方法 ,並自動將其註冊爲destroyMethod 。這種「銷燬方法推理」目前僅限於檢測名爲「關閉」或「關閉」的公共非參數方法的 。 方法可以在繼承層次的任何級別聲明,並且將檢測到 ,而不管@Bean方法的返回類型爲 (即,,檢測在創建時反映在bean實例本身 上)。

再次重申,這是當滅法未明確設置註解驅動配置的默認行爲。如果這種行爲是不需要明確設定破壞方法爲空字符串將禁用此「功能」:

要禁用摧毀特定@Bean方法推斷,指定 空字符串作爲值,例如@Bean(=了destroyMethod 「」)。請注意, DisposableBean和Closeable/AutoCloseable接口仍將被檢測到,並調用相應的銷燬/關閉方法 。

在另一方面,使用XML配置的時候,這是不是默認行爲......爲了實現平價,destroy-method可以明確地設置爲(inferred)。有關詳細信息,請參閱官方文檔中的Destruction callbacksDefault initialization and destroy methods部分。

相關問題