我在这里有一个简单的示例程序:
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定义的对象图?
答案 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
属性。