Spring Bean的初始化是首先调用Bean的默认构造器,然后调用set方法对属性进行注入。
如果:
A包含属性B,B包含了属性A。
例子:
@Component public class A { @Autowired private B b; public void aHello(){ System.out.println("aHello!"); } public void bothHello(){ aHello(); b.bHello(); } }
@Component public class B { @Autowired private A a; public void bHello(){ System.out.println("bHello!"); } }
public class HelloApp { public static void main(String[] args) { ApplicationContext context = new ClassPathXmlApplicationContext("spring-config.xml"); A a = context.getBean(A.class); a.bothHello(); } }
输出:
aHello!
bHello!
A和B循环引用,程序正常运行。请问Spring是怎么解决类似的循环引用问题的?
楼上说的对:在容器启动的时候,会把bean实例都初始化好的,你可以试试这样的一种情形,你使用了@Autowired注入一个java bean,但是不配置<bean id="" class="">,你会发现容器在启动的时候会报错,所以说明了,即使是循环依赖的关系,也是:在容器启动的时候,就会初始化好java bean,。。
public class A { private B b; public A(B b) { this.b = b; } public void say(){ System.out.println("A"); } } public class B { private A a; public B(A a) { this.a = a; } public void say(){ System.out.println("A"); } }
肯定有先后顺序,你可以试试在构造方法中对对象赋值。这样spring就会卡在两个对象相互引用上。
如果只是在属性中引用,spring应该会以获取类的顺序先初始化对象,然后根据对象的属性再做赋值,这样就不会出现卡在对象相互引用上了。
你遇到这种问题会怎么做?总有个先后吧。。。肯定是先把对象构造出来,在解决依赖问题啊。
你可以覆盖默认的构造器,在里面打断点,看看具体的执行顺序呀。
循环依赖只会在构造器中产生,spring会抛出UnsatisfiedDependencyException异常
ublic class Test { public static void main(String[] args) { ApplicationContext context = new ClassPathXmlApplicationContext("Test.xml"); System.out.println(context.getBean("a")); System.out.println(context.getBean("b")); } } @Component class A{ @Autowired public A(B b) { } } @Component class B{ @Autowired public B(A a) { } }
先创建基本的Bean,再依赖注入(DI)。这样就没什么问题,解释得通。
比如顺序如下:
new出A的实例,
new出B的实例,
A Bean中的b字段赋值B的实例,
B bean中的a字段赋值A的实例。