2011-10-03 103 views
8

場景: 我們有一個在Websphere內運行的Spring託管Web應用程序。 (Spring 3.0.x,WAS 7) Web應用程序通過Spring的WorkManagerTaskExecutor(配置爲線程池大小爲10)利用Websphere的工作管理器來執行計算密集型數據庫讀取操作。所以基本上,一個請求來生成,可以說,10個不同的文件。要生成文檔,只需要db讀取來收集/處理數據。所以我們基本上產生了10個線程來處理10個文檔,最後收集10個工作人員返回的10個文檔,併合並它們,並向客戶端寫回一個大的響應。我們發現,雖然10個線程正在收集/處理數據,但還是有大量類似的db調用。所以我們想出的是圍繞最執行的數據庫方法創建一個方面來緩存響應。該方面被配置爲單例,並且該方面使用的緩存被自動裝配到方面,其範圍設置爲請求範圍,以便每個請求都有自己的緩存。在多線程Web應用程序中訪問請求範圍的bean

問題: 現在這種方法的問題是,當線程正在做他們的數據庫調用和方面是interjects我們得到java.lang.IllegalStateException: No thread-bound request found異常。我的理解是完全有效的,因爲線程在請求​​上下文之外執行。

有沒有辦法繞開這個問題?是否有可能將請求範圍緩存的方面應用於這些線程所調用的方法?

回答

5

我不認爲你可以直接做到這一點。即使你可以,它會有點難看。但是,您可以生成唯一的請求標識符(甚至可以使用會話標識符,但要注意多個標籤),並將其傳遞給每個處理線程。然後該方面可以使用該ID作爲緩存的關鍵。緩存本身也是單身人士,但會有Map<String, X>,其中String是ID,X是您的緩存結果。爲了使事情更容易處理,可以使用@Async方法(而不是手動產生線程),並且每個方法都可以將緩存ID作爲其第一個參數傳遞。

(當然,你的異步方法應該返回Future<Result>這樣就可以收集他們的請求線程結果)

+0

我想到的辦法,但有一個缺點,我覺得是,它會迫使我傳球在我想要緩存的所有方法調用的下游(在線程執行期間)的唯一請求標識符。另外,一段時間後緩存會不會很大?這會迫使我定期進行管理。也許我在這裏錯過了一些東西。 – r4j1v

+0

也許有一個「線程執行上下文」,我可以使用它來存儲我的唯一請求標識符並在方面檢索它,而不必自己傳遞它? – r4j1v

+5

我設法解決了這個問題。我開始使用'SimpleAsyncTaskExecutor'而不是'WorkManagerTaskExecutor'。好處是'SimpleAsyncTaskExecutor'永遠不會重用線程。這只是解決方案的一半。解決方案的另一半是使用'RequestContextFilter'而不是'RequestContextListener'。 'RequestContextFilter'有一個'setThreadContextInheritable()'方法,它基本上允許子線程繼承父上下文。 – r4j1v

相關問題