当使用Spring并将ProxyFactoryBean和@Inject Provider<>结合使用时,最终会在启动时创建大量对象。
我已将原因确定为DefaultListableBeanFactory.doGetBeanNamesForType方法。 " @Inject Provider<>"通过迭代所有bean定义并搜索可满足提供者泛型参数的bean定义来满足。遇到FactoryBean时,它首先完全初始化,然后才查询getObjectType()。但是,ProxyFactoryBean通常在applicationContext.xml中设置,并依赖于它们代理的bean。完全初始化ProxyFactoryBean会导致内部bean的实例化。
所有这一切都很好,除非当时内部bean无法实例化 - 例如因为它依赖于一些其他bean,直到原始bean(具有Provider的那个)之前无法初始化。没有循环依赖,只有过度的初始化。
示例:
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>
在上面的例子中,流程是(完全由Spring管理):
bean1
。尝试初始化bean1
并发现它有Provider<X>
。
BeanDefinition
。每个:
FactoryBean
,请尝试实例化并初始化FactoryBean
以查看&#34; getObjectType()
&#34;会回来的。
bean2Factory
,需要使用bean2
的实例。所以Spring尝试实例化并初始化bean2
。
bean2
无法初始化,因为它依赖于bean1
- 导致Spring抛出循环依赖性错误。FactoryObject
被正确创建,Spring现在要求输入类型并缓存响应(&#34;良好路径&#34;)。有关完整说明和示例,请参阅https://github.com/bironran/spring_issues_proxy_factory。
我观察到实际应用程序有大约500个已定义的bean实例化,并尝试初始化超过300,000个对象(一次又一次地使用相同的bean),因为这个问题。启动时间延迟了几分钟,GC峰值。
此外,这个问题呈指数级增长 - 任何无法解决的新依赖关系都会使应用程序加载的时间加倍。
很想听听有关如何解决的建议(参见github项目)。
答案 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实例的情况下初始化工厂。