前言
- 你可能会有如下问题:
- 1、想看Spring源码,但是不知道应当如何入手去看,对整个Bean的流程没有概念,碰到相关问题也没有头绪如何下手
- 2、看过几遍源码,没办法彻底理解,没什么感觉,没过一阵子又忘了
- 本文将结合实际问题,由问题引出源码,并在解释时会尽量以图表的形式让你一步一步彻底理解Spring Bean的IOC、DI、生命周期、作用域等。
先看一个循环依赖问题
现象
-
循环依赖其实就是循环引用,也就是两个或则两个以上的bean互相持有对方,最终形成闭环。比如A依赖于B,B依赖于C,C又依赖于A。如下图:
image
如何理解"依赖"呢,在Spring中有:
- 构造器循环依赖
- field属性注入循环依赖
直接上代码:
1.构造器循环依赖
@Service
public class A {
public A(B b) { }
}
@Service
public class B {
public B(C c) {
}
}
@Service
public class C {
public C(A a) { }
}
-
结果:项目启动失败,发现了一个cycle。
image
2.field属性注入循环依赖
@Service
public class A1 {
@Autowired
private B1 b1;
}
@Service
public class B1 {
@Autowired
public C1 c1;
}
@Servicejava
public class C1 {
@Autowired public A1 a1;
}
-
结果:项目启动成功
image
3.field属性注入循环依赖(prototype)
@Service
@Scope("prototype")
public class A1 {
@Autowired
private B1 b1;
}
@Service
@Scope("prototype")
public class B1 {
@Autowired
public C1 c1;
}
@Service
@Scope("prototype")
public class C1 {
@Autowired public A1 a1;
}
- 结果:项目启动失败,发现了一个cycle。
- 现象总结:同样对于循环依赖的场景,构造器注入和prototype类型的属性注入都会初始化Bean失败。因为@Service默认是单例的,所以单例的属性注入是可以成功的。
分析原因
- 分析原因也就是在发现SpringIOC的过程,如果对源码不感兴趣可以关注每段源码分析之后的总结和循环依赖问题的分析即可。
SpringBean的加载流程(源码分析)
- 简单一段代码作为入口
ApplicationContext ac = new ClassPathXmlApplicationContext("spring.xml");
ac.getBean(XXX.class);
- ClassPathXmlApplicationContext是一个加载XML配置文件的类,与之相对的还有AnnotationConfigWebApplicationContext,这两个类大差不差的,只是ClassPathXmlApplicationContext的Resource是XML文件而AnnotationConfigWebApplicationContext是Scan注解获得的。
- 看到第二行就已经可以直接获取bean的实例了,所以第一行构造方法时,就已经完成了对所有bean的加载。
-
ClassPathXmlApplicationContext举例,他里面储存的东西如下:
image
网友评论