为什么Spring 4.0.9 applicationContext初始化被卡住而不是3.2.1?

时间:2016-11-07 18:01:01

标签: spring applicationcontext

我的applicationContext初始化在Spring 3.2.1中运行良好。

但是当我在不更改任何代码或bean定义的情况下升级到4.0.9时,初始化卡住了。以下声明继续发生。但是没有明显的循环引用。

Requested bean is currently in creation: Is there an unresolvable circular reference?

我继续调查。我故意删除了一个bean定义。

  • Spring 3.2.1有预期的结果:几乎立即发生致命错误。
  • Spring 4.0.9仍然进入这个无限循环,试图找到一个不同的种子bean定义来使事情​​有效。

这是继续发生的日志声明。

[factory.support.DefaultListableBeanFactory.getTypeForFactoryBean()] - Ignoring bean creation exception on FactoryBean type check:
org.springframework.beans.factory.BeanCreationException: 
Error creating bean with name 'someSeedBean-which-is-different-in-every-instance-of-this-log' defined in the class path resource ........ ; 
nested exception is org.springframework.beans.factory.NoSuchBeanDefinitionException: No bean named 'someDataSource' is defined 

改变了什么?任何想法都会有所帮助。

适用于Spring 3.x和4.x

的Bean定义
<bean id="abstractDataSource" class="com.mchange.v2.c3p0.ComboPooledDataSource"
        destroy-method="close" abstract="true" scope="singleton">
        <property ....>
</bean>

<bean id="someDataSource" class="com.mchange.v2.c3p0.ComboPooledDataSource"
        destroy-method="close" scope="singleton" parent="abstractDataSource">
        <property name="driverClass" .... />   
</bean>

<bean id="someSessionFactory"
    class="org.springframework.orm.hibernate3.annotation.AnnotationSessionFactoryBean">
    <property name="dataSource"> <ref bean="someDataSource" />  </property>
    <property name="packagesToScan"> <list>......</list> </property>
    ....

Bean定义适用于Spring 3.x但不适用于4.0.9。

@Configuration
public class SomeSpringConfiguration{

    // Moving this beanDef to Java for features not available in XML
    @Bean(destroyMethod = "close")
    public DataSource someDataSource() { // also tried setting this to ComboPooledDataSource
        // verified that this beanDefinition is recognized by Spring
        // but this bean is never created / this method is never executed
        ...
        return datasource;
    }
}     

<bean class="SomeSpringConfiguration" />

<bean id="someSessionFactory"
    class="org.springframework.orm.hibernate3.annotation.AnnotationSessionFactoryBean">
    <property name="dataSource"> <ref bean="someDataSource" />  </property>
    <property name="packagesToScan"> <list>......</list> </property>
    ....
</bean>   

我在Spring 4.0.9中遇到的错误是

Cannot resolve reference to bean 'someSessionFactory' while setting constructor argument; 
nested exception is org.springframework.beans.factory.BeanCurrentlyInCreationException: 
Error creating bean with name 'someSessionFactory': 
Requested bean is currently in creation: Is there an unresolvable circular reference?

请注意,该应用程序在/ xml,@ Component和@Configuration中定义了数千个bean。我不得不将bean从xml移到@Configuration类以执行复杂的bean构建过程。

----------------------- UPDATE

我发现了问题:&#39;吨MethodInvokingFactoryBean [MIB]用法&#39;。出于某种原因,Spring 4在存在大量MIB时感到困惑。完全相同的代码库在Spring 3中运行良好。我将各种MIB执行的所有逻辑迁移到ApplicationListener。请注意,ApplicationListener不是MIB的预期替代品,但在我的情况下,我可以在监听器中重现逻辑,因为MIB只是将Spring bean静态注入到不由Spring管理的类中。它不仅解决了这个问题,而且将Spring启动时间从~300秒减少到约200秒。

不幸的是,我既不能在Spring中找出根本原因,也不能在较小的代码库中重现这个问题(在这里分享)。

3 个答案:

答案 0 :(得分:3)

删除

<bean class="SomeSpringConfiguration" />

来自XML,它已经使用@Configuration进行了注释。如果它被扫描,它可能会被创建两次。你应该把所有东西都搬到Javaconfig。

答案 1 :(得分:1)

循环引用在开发过程中很常见,当你有很多bean并且在将它们一起自动装配时不小心。堆栈跟踪应包含完整的bean列表,告诉您循环引用的开始和结束位置。

我从未见过随机循环引用(我在过去7年中多次遇到循环引用)!据我所知,构建依赖树并实例化/连接bean的代码是确定性的。因此,每次运行时都应该始终获得相同的循环引用。如果你不这样做,我只能有两个原因

  • 您正在使用的Spring版本中存在一个错误(我99%肯定会对此进行单元测试)
  • 你有一个或多个bean作为bean实例化的一部分启动一个线程,并且线程使用applicationContext来懒惰地加载另一个bean(当上下文仍在加载时)。

当我教Spring类时,我建议构造函数应该只包含字段赋值,如果需要启动线程(或生命周期中的任何其他内容),则应使用生命周期方法。我个人更喜欢实现SmartLifeCycle(通过InitializingBean / DisposableBean,@ PostConstruct / @ PreDestroy),因为这样可以确保在所有bean实例化并连接在一起之后不会启动任何内容。

答案 2 :(得分:1)

它的核心是Strelok所说的,你正在混合注释和xml配置。

@Configuration注释的要点是避免使用xml。从xml中删除SomeSpringConfiguration后添加组件扫描时。

您将开始创建someDataSource的倍数,因为它在多个位置定义(@Bean注释和xml)。

请避免混合注释和xml,只使用其中一个并坚持下去,如果不解决这个问题,至少会更容易发现。

如果你可以创建一个示例项目并将其上传到某个地方,我可以仔细查看你是否还有这个问题。