2016-09-30 25 views
1

所以我有這個非常奇怪和令人不安的問題。在我們的低性能計算機上,我們的一些singleton bean在Spring Context初始化期間被複制。這隻發生在硬件性能低下的計算機上,並且一直髮生。低性能計算機上的Spring bean singleton複製

到目前爲止,我所知道的是它似乎正發生在一堆循環依賴的類中,我懷疑它可能與bean init方法有關。通過init方法而不是構造函數將LockScreen注入到MainContentPane中來解決循環依賴問題。

我有兩個日誌,一個來自正常的性能計算機,另一個來自低性能計算機。日誌顯示了差異和問題。行尾的數字是來自方法System.identityHashCode(object)的實例ID。日誌格式爲:

LOGLEVEL [Thread ID] LoggingClass Message 

在正常的性能計算機上發生以下打印輸出。

INFO [JavaFX Application Thread] MainContentPane  Constructor: 869589588 
INFO [JavaFX Application Thread] MainContentPane  Getting LockScreen In Spring Init.... 

INFO [JavaFX Application Thread] SessionHandler  Constructor: 939274676 
INFO [JavaFX Application Thread] SessionHandler  Injected MainContentPane Instance: 869589588 
INFO [JavaFX Application Thread] UserStateBinder  Constructor: 2010765576 
INFO [JavaFX Application Thread] UserStateBinder  Injected SessionHandler Instance: 939274676 
INFO [JavaFX Application Thread] LockScreenLockedController Constructor: 1866179042 
INFO [JavaFX Application Thread] LockScreenLockedController Injected UserStateBinder Instance: 2010765576 
INFO [JavaFX Application Thread] LockScreen   Constructor: 204176749 
INFO [JavaFX Application Thread] LockScreen   Injected LockScreenLockedController Instance: 1866179042 
INFO [JavaFX Application Thread] LockScreen   This instance: 204176749 
INFO [JavaFX Application Thread] LockScreen   Bean Factory instance: 1371189401 
INFO [JavaFX Application Thread] MainContentPane  Injected LockScreen Instance: 204176749 

這裏沒有重複。

但是,如果我們查看低性能計算機的日誌,我們可以看到在初始化之後創建了與上述類似的重複項。

INFO [JavaFX Application Thread] MainContentPane  Constructor: 22324067 
INFO [JavaFX Application Thread] MainContentPane  Getting LockScreen In Spring Init.... 

INFO [JavaFX Application Thread] SessionHandler  Constructor: 32463502 
INFO [JavaFX Application Thread] SessionHandler  Injected MainContentPane Instance: 22324067 
INFO [JavaFX Application Thread] UserStateBinder  Constructor: 19793387 
INFO [JavaFX Application Thread] UserStateBinder  Injected SessionHandler Instance: 32463502 
INFO [JavaFX Application Thread] LockScreenLockedController Constructor: 29065840 
INFO [JavaFX Application Thread] LockScreenLockedController Injected UserStateBinder Instance: 19793387 
INFO [JavaFX Application Thread] LockScreen   Constructor: 12729388 
INFO [JavaFX Application Thread] LockScreen   Injected LockScreenLockedController Instance: 29065840 
INFO [JavaFX Application Thread] LockScreen   This instance: 12729388 
INFO [JavaFX Application Thread] LockScreen   Bean Factory instance: 30716643 
INFO [JavaFX Application Thread] MainContentPane  Injected LockScreen Instance: 12729388 

INFO [JavaFX Application Thread] SessionHandler  Constructor: 11043228 
INFO [JavaFX Application Thread] SessionHandler  Injected MainContentPane Instance: 22324067 
INFO [JavaFX Application Thread] UserStateBinder  Constructor: 24902967 
INFO [JavaFX Application Thread] UserStateBinder  Injected SessionHandler Instance: 32463502 
INFO [JavaFX Application Thread] LockScreenLockedController Constructor: 17521714 
INFO [JavaFX Application Thread] LockScreenLockedController Injected UserStateBinder Instance: 19793387 
INFO [JavaFX Application Thread] LockScreen   Constructor: 16791356 
INFO [JavaFX Application Thread] LockScreen   Injected LockScreenLockedController Instance: 29065840 
INFO [JavaFX Application Thread] LockScreen   This instance: 16791356 
INFO [JavaFX Application Thread] LockScreen   Bean Factory instance: 30716643 

在這裏我們可以看到,有一個第二組除MainContentPane類的所有類創建的實例。新的一組類是依賴注入前一組實例(檢查id),並且bean工廠與以前是相同的實例。

所有這些消息都印在主線程(JavaFX Application Thread)上,所以似乎也沒有併發問題。

該項目還包括一個嵌入式Jetty http服務器。我不知道在Jetty中是否有可能導致低性能計算機出現此問題的問題。

版本:

JRE(incl. JavaFX): 1.8.0.101 
Spring: 4.3.3.RELEASE 
Jetty + Websocket: 9.3.6.v20151106 

我懷疑這個問題可能已經通過設置Spring上下文設置setAllowBeanDefinitionOverriding(假)解決。但那也沒有幫助。

AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(); 
     context.setAllowBeanDefinitionOverriding(false); 
     context.register(ClientContext.class, 
       MainContext.class, 
       CommonContext.class, 
       CciContext.class, 
       PersistenceContext.class, 
       SimulatorContext.class); 
     context.refresh(); 

請告訴我,如果有任何額外的信息,你需要,並感謝您在任何時候你幫助我。

編輯:

我現在已經證實,所有動初始化,所有的bean的訪問是由一個單獨的線程發生。 我只能在跟蹤日誌中找到兩個有趣的事實。首先,似乎所有的啓動都是以相同的順序發生的,即使它是完全相同的軟件版本(Spring是在paralell中初始化的嗎?)。 二,中等性能的電腦確實有重複!它們只在UserStateBinder類中有重複(或者可能是重新初始化?)。高性能的開發電腦完全沒有這個問題。

我們可能會從明天開始將項目從我們的項目中刪除,因爲我們一直無法找到解決此問題的解決方案。如果其他人希望我測試任何理論,我仍然可以使用當前版本的項目。

+0

那麼,當它在'MainContentPane'中設置'LockScreen'時,會發生循環bean引用?每臺計算機上的JVM版本是否相同? – Asoub

+0

循環引用是: LockScreen - > LockScreenLockedController - > UserStateBinder - > SessionHandler - > MainContentPane - > LockScreen,它通過讓MainContentPane獲取LockScreen bean的Spring init方法而不是它的構造函數來解決。關於JVM,是的,在所有的計算機上都是一樣的。 JRE與應用程序捆綁在一起以確保它。 – Flipbed

+0

這聽起來很晦澀。你可以在你慢速的慢電腦上試試debbugger(如果可能,用eclipse)? – Asoub

回答

0

因此經過大量的進一步測試後,我能夠解決問題,但沒有找到奇怪行爲的根本原因。

我懷疑這種行爲在某種程度上是由於Spring初始化bean的某種時間依賴性而改變了行爲。我不能肯定地說這是否是並行性的結果。

問題只發生在循環依賴LockScreen - > LockScreenLockedController - > UserStateBinder - > SessionHandler - > MainContentPane - > LockScreen。通過將MainContentPane中的構造函數依賴項移動到Spring init方法來打破循環依賴。代碼看起來像這樣。

@Bean(initMethod = "init") 
public MainContentPane mainContentPane() {...} 

@Bean 
public LockScreen lockScreen() {...} 

@Bean 
public LockScreenLockedController lockScreenLockedController() {...} 

@Bean 
public UserStateBinder userStateBinder() {...} 

@Bean 
public SessionHandler sessionHandler() {...} 

的解決方案是明確在春季與@DependsOn註釋這樣聲明依賴。

@Bean(initMethod = "init") 
public MainContentPane mainContentPane() {...} 

@Bean 
@DependsOn("lockScreenLockedController") 
public LockScreen lockScreen() {...} 

@Bean 
@DependsOn("userStateBinder") 
public LockScreenLockedController lockScreenLockedController() {...} 

@Bean 
@DependsOn("sessionHandler") 
public UserStateBinder userStateBinder() {...} 

@Bean 
@DependsOn("mainContentPane") 
public SessionHandler sessionHandler() {...} 

我希望這可以幫助任何人有同樣的問題,我還是真的想知道爲什麼春天行爲這種方式依賴於計算機的性能。