2017-07-08 38 views
1

當使用Spring並結合ProxyFactoryBean和@Inject Provider <>時,會在啓動過程中創建大量對象。Spring BeanFactory和類型搜索

我已經確定原因爲DefaultListableBeanFactory.doGetBeanNamesForType方法。通過迭代所有的bean定義並搜索可以滿足提供程序泛型參數的定義,可以滿足「@Inject Provider <>」。當遇到FactoryBean時,它首先被完全初始化,然後才被查詢getObjectType()。但是,ProxyFactoryBean通常在applicationContext.xml中設置,並依賴於它們代理的bean。完全初始化ProxyFactoryBean會導致內部bean的實例化。

所有這一切都很好,除非內部bean在那個時候不能被實例化 - 例如,因爲它依賴於一些其他的bean,直到原始的bean(提供者的那個)才能被初始化。沒有循環依賴性,只有過度渴望的初始化。

實施例:

class Bean1 { @Inject Provider<X> provider;} 
class Bean2 { @Inject Bean1 bean1;} 

applicationContext.xml: 
<bean id="bean1" class="com.rb.springissues.sample.Bean1"/> 
<bean id="bean2" class="com.rb.springissues.sample.Bean2"/> 
<bean id="bean2Factory" class="org.springframework.aop.framework.ProxyFactoryBean"> 
    <property name="target" ref="bean2"/> 
    <property name="proxyTargetClass" value="true"/> 
</bean> 

在上述例子中的流動是(由彈簧完全管理):

  • 實例化bean1。嘗試初始化bean1並發現它有Provider<X>
    • 在上下文中遍歷所有BeanDefinition。對於每個人:
      • 如果它是「普通」bean,請評估類以查看它是否合適。
      • 如果它是FactoryBean,請嘗試實例化並初始化FactoryBean以查看「getObjectType()」將返回的內容。
        • 爲了初始化bean2Factory,需要給它提供一個bean2的實例。所以Spring試圖實例化並初始化bean2
          • 但是 - bean2無法初始化,因爲它依賴於bean1 - 導致Spring引發循環依賴性錯誤。
      • 如果FactoryObject已正確創建,現在春天請求的類型和緩存響應(「好路」)。
      • 如果我們遇到了一個異常(循環依賴錯誤),它會被捕獲並被忽略,但結果不會被緩存 - 所以如果我們得到另一個bean,它會再次做同樣的事情(並且一次又一次...)

參見https://github.com/bironran/spring_issues_proxy_factory爲全面描述和樣品。

我觀察到約500個定義的bean實例化並嘗試初始化超過300,000個對象(同一個bean一次又一次)由於此問題的實際應用程序。該創業公司被分鐘推遲和GC高峯。

此外,此問題呈指數級增長 - 任何無法解決的新依賴項都可能使應用程序加載的時間加倍。

很想聽聽關於如何解決的建議(參見github項目)。

+0

你可以陳述你的商業案例,那就是你想要解決的問題嗎?我沒有看到它在這裏或你的GitHub頁面。在嘗試解決它帶來的問題之前,也許我們可以退後一步並質疑ProxyFactoryBean的用法。當然,除非這純粹是一項學術活動。 –

+1

我們使用ProxyFactoryBean來應用性能監控,限制,事務管理,客戶選擇(作爲多客戶SaaS產品)並應用權限(在特定情況下)。 –

+0

那麼基本上,爲了交叉的關切?我猜想還有其他的方法可以做,但是可以。 –

回答

1

解決方案竟然是容易 - 更換<property name="target" ref="bean2"/>有: <property name="targetName"> <idref bean="bean2"/> </property> <property name="targetClass" value="com.rb.springissues.sample.Bean2"/>

這導致bean2的延遲綁定 - 這樣的工廠可以在沒有Bean2實例進行初始化。

+0

感謝您發佈更新。對不起,我幫不了你;不再有調試XML配置的慾望了。似乎回到過去。 –