Spring Bean对象编组取决于XML中给出的顺序?

时间:2014-09-17 20:19:51

标签: java xml spring

我在这里有一个简单的示例程序:

package com.test;

import org.springframework.beans.factory.InitializingBean;
import org.springframework.context.support.FileSystemXmlApplicationContext;

public class Main {

    public static void main(String[] args) throws InterruptedException {



        try {
            FileSystemXmlApplicationContext context = new FileSystemXmlApplicationContext("TestBeanFile.xml");
            Object o = context.getBean("AInstance");
        }
        catch (Throwable e) {
            e.printStackTrace();
        }
        Thread.sleep(Long.MAX_VALUE);
    }

    private static class A implements InitializingBean {
        private B myB;

        public A() {
            System.out.println("A constructor");
        }

        public void setB(B aB) {
            myB = aB;
        }

        @Override
        public void afterPropertiesSet() throws Exception {
            System.out.println("A aps");
        }
    }

    private static class B implements Runnable, InitializingBean {
        private C myC;
        private volatile boolean exit = false;

        public B() {
            System.out.println("B constructor");
        }

        public void setC(C aC) {
            myC = aC;
        }

        @Override
        public void afterPropertiesSet() throws Exception {
            System.out.println("B aps");
            if (myC == null) throw new IllegalArgumentException("C cannot be null");
            new Thread(this).start();           
        }

        public void exit() {
            exit = true;
        }

        @Override
        public void run() {
            while (!exit) {
                System.out.println(myC.getValue());
                try {
                    Thread.sleep(1000);
                }
                catch (InterruptedException e) {
                    // TODO Auto-generated catch block
                    e.printStackTrace();
                }
            }
        }


    }

    private static class C implements InitializingBean {
        private String value = "C's value";

        public C() {
            System.out.println("C constructor");
        }

        public String getValue() {
            return value;
        }

        @Override
        public void afterPropertiesSet() throws Exception {
            System.out.println("C aps");
        }
    }

}

这是一个简单的XML加载bean,它故意为A类提供一个不正确的完全限定名。这应该意味着C B和A不会被构造。

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:int="http://www.springframework.org/schema/integration"
    xmlns:int-stream="http://www.springframework.org/schema/integration/stream"
    xmlns:int-ip="http://www.springframework.org/schema/integration/ip"
    xsi:schemaLocation="
            http://www.springframework.org/schema/beans                 http://www.springframework.org/schema/beans/spring-beans-3.0.xsd
            http://www.springframework.org/schema/integration           http://www.springframework.org/schema/integration/spring-integration-2.1.xsd
            http://www.springframework.org/schema/integration/stream    http://www.springframework.org/schema/integration/stream/spring-integration-stream-2.1.xsd
            http://www.springframework.org/schema/integration/ip        http://www.springframework.org/schema/integration/ip/spring-integration-ip-2.1.xsd">


    <bean id="CInstance" class = "com.test.Main.C" />

    <bean id="BInstance" class = "com.test.Main.B">
        <property name="C" ref="CInstance" />
    </bean> 

    <bean id="AInstance" class = "com.test.Main.A1">
        <property name="B" ref="BInstance"/>
    </bean>

</beans>

使用上面的XML C和B运行此应用程序时,DO构造但是A不是。它将产生以下输出(抛出异常时省略堆栈跟踪,但我向你保证A不构造):

C constructor
C aps
B constructor
B aps
C's value
C's value
C's value
....... // one a second

如果您将XML修改为如下所示:

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:int="http://www.springframework.org/schema/integration"
    xmlns:int-stream="http://www.springframework.org/schema/integration/stream"
    xmlns:int-ip="http://www.springframework.org/schema/integration/ip"
    xsi:schemaLocation="
            http://www.springframework.org/schema/beans                 http://www.springframework.org/schema/beans/spring-beans-3.0.xsd
            http://www.springframework.org/schema/integration           http://www.springframework.org/schema/integration/spring-integration-2.1.xsd
            http://www.springframework.org/schema/integration/stream    http://www.springframework.org/schema/integration/stream/spring-integration-stream-2.1.xsd
            http://www.springframework.org/schema/integration/ip        http://www.springframework.org/schema/integration/ip/spring-integration-ip-2.1.xsd">

    <bean id="AInstance" class = "com.test.Main.A1">
        <property name="B" ref="BInstance"/>
    </bean>

    <bean id="BInstance" class = "com.test.Main.B">
        <property name="C" ref="CInstance" />
    </bean> 

    <bean id="CInstance" class = "com.test.Main.C" />
</beans>

您获得的唯一输出是堆栈跟踪,B和C对象根本不构造。

这似乎是春天的一个错误。我不明白为什么对象的编组以及运行的构造函数/ afterpropertiesSet方法取决于它们在XML中的出现顺序。这对我来说意味着,当我有在构造函数中构造线程的类/在属性集方法之后,如果我不小心我如何在XML中对元素进行排序,那么如果我唯一可能会泄漏资源在这个例子中,对它们的引用是A类。因为它在两种情况下都失败了。

那么,这是一个错误,还是这个我不理解的功能?如果这是一个特性,他们有什么理由使编组顺序依赖于XML文件,而不是bean定义的对象图?

1 个答案:

答案 0 :(得分:2)

Spring首先读取XML配置中的<bean>和其他元素,并创建定义它们的适当BeanDefinition个对象。

然后必须初始化它们。要做到这一点,它必须决定订单。初始化的顺序是未定义的,除非bean依赖于另一个或者@Order的混合,Ordered和其他一些实现(取决于具体情况)。

在您的第一个示例中,首先初始化CInstance。然后初始化BInstance。其初始化的一部分涉及调用其启动非守护程序线程的afterPropertiesSet()方法。然后Spring尝试初始化AInstance并失败。

在第二个示例中,Spring首先尝试初始化AInstance。它立即失败,无需更改即可启动第二个线程。

请注意,在

之类的声明中
<bean id="AInstance" class="com.example.Spring.A1">
    <property name="B" ref="BInstance" />
</bean>

虽然AInstance取决于BInstance,但在调用任何属性设置器以将BInstance分配给B之前,需要初始化实际实例。因此Spring通过实例化类来开始AInstance的初始化。如果失败,则整个上下文刷新失败。如果它通过,它将初始化BInstance bean并使用它来设置B属性。