# Spring应用与源码分析
# Spring初始化
# Bean生命周期与循环依赖
用以下语句启动ioc容器,研究一下代码内部逻辑?
AnnotationConfigApplicationContext ac = new AnnotationConfigApplicationContext(AppConfig.class);
AnnotationConfigApplicationContext 类图:
构造函数:
public AnnotationConfigApplicationContext(Class<?>... componentClasses) {
this();
register(componentClasses);
refresh();
}
2
3
4
5
# 1.this()
首先会执行父类的构造方法:
//初始化一个工厂类,用于创建bean对象
public GenericApplicationContext() {
this.beanFactory = new DefaultListableBeanFactory();
}
2
3
4
TIP
DefaultListableBeanFactory工厂类重要属性:
1.beanDefinitionMap 存放BeanDefinition (所有交给spring管理的类/依赖注入的类,都会交给BeanDefinition)
2.beanDefinitionNames 存放bean name
父类构造完成之后,那么来看子类(AnnotationConfigApplicationContext)中的初始化。
public AnnotationConfigApplicationContext() {
/**
* 初始化一个AnnotatedBeanDefinition读取器,用于读取被注解标注的bean,
* 读取的信息存放入AnnotatedBeanDefinition
*/
this.reader = new AnnotatedBeanDefinitionReader(this);
/**
* 初始化一个扫描器,用于扫描类或者包下的所有类,将被注解标注的bean生成对应的AnnotatedBeanDefinition
*/
this.scanner = new ClassPathBeanDefinitionScanner(this);
}
2
3
4
5
6
7
8
9
10
11
12
13
# 2.register(componentClasses) 注册配置类
首先会循环注册bean
public void register(Class<?>... componentClasses) {
//循环注册bean
for (Class<?> componentClass : componentClasses) {
registerBean(componentClass);
}
}
2
3
4
5
6
# 3.refresh()
首先进入AbstractApplicationContext.java的refresh():
....
//完成扫描,把beanDefinition对象存储到beanDefinitionMap
invokeBeanFactoryPostProcessors(beanFactory);
....
//准备走Bean的生命周期
finishBeanFactoryInitialization(beanFactory);
2
3
4
5
6
7
8
接着进入finishBeanFactoryInitialization():
...
//实例化所有的单例,非懒加载
beanFactory.preInstantiateSingletons();
2
3
4
接着进入ConfigurableListableBeanFactory抽象类的DefaultListableBeanFactory#preInstantiateSingletons()
//得到所有的beanDefinition的名字
List<String> beanNames = new ArrayList<>(this.beanDefinitionNames);
.... 省略部分:遍历验证beanDefinition
//便利beanNames,开始getBean (重点开始)
2
3
4
5
6
7
8
doGetBean用到的重要缓存池对象介绍
1.Map<String, Object> singletonObjects = new ConcurrentHashMap<>(256)
单例缓存池,生产好的单例bean都放在这里,getBean就是从这里拿的
2.Map<String, ObjectFactory<?>> singletonFactories = new HashMap<>(16)
二级缓存池,用于存工厂对象,在解决循环依赖里,用来存bean工厂对象
3.Map<String, Object> earlySingletonObjects = new HashMap<>(16)
三级缓存池,用于解决循环依赖
4.set<> singletonsCurrentlyInCreation
表示当前对象是否在创建当中
doGetBean来到了AbstractBeanFactory#doGetBean()
....
//重点方法: 尝试从缓存池中获取对象
Object sharedInstance = getSingleton(beanName);
if (sharedInstance != null && args == null) {
...
}else{
//判断这个类是不是在创建过程中,若出现循环依赖,判断bean是不是单例的,不是就抛异常,与sharedInstance有联系
if (isPrototypeCurrentlyInCreation(beanName)) {
throw new BeanCurrentlyInCreationException(beanName);
}
..... 各种验证
//准备开始创建bean了
if (mbd.isSingleton()) {
//getSingleton : 标识当前的bean正在被创建
sharedInstance = getSingleton(beanName, () -> {
try {
//完成了目标对象的创建
//真正开始创建bean,前面都是扫描与验证过程
return createBean(beanName, mbd, args);
}
catch (BeansException ex) {
// Explicitly remove instance from singleton cache: It might have been put there
// eagerly by the creation process, to allow for circular reference resolution.
// Also remove any beans that received a temporary reference to the bean.
destroySingleton(beanName);
throw ex;
}
});
bean = getObjectForBeanInstance(sharedInstance, name, beanName, mbd);
}
}
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
注意:上面代码片段中getSingleton()方法是循环依赖的核心方法
举例解释:
当前有一个A类,在A类中依赖了B类,也可以说自动注入了B类
当前有一个B类,在B类中依赖了A类
首先注意,getSingleton()是一个重载方法
spring扫描到A类需要被实例化,第一次调用getSingleton(beanName),尝试去缓存池去拿对象,第一次拿是空的,这个先记着
接着在创建bean前面一步,再次调用了getSingleton(),这次注意调用的是getSingleton(String beanName, ObjectFactory<?> singletonFactory)
这次会在singletonsCurrentlyInCreation这个Set集合中记录当前类正在被创建
接下来会开始调用createBean()
首先spring会讲我们的A对象给new出来
如果支持循环依赖,则会把Bean工厂对象缓存到第二级缓存里去
接下来会执行到populateBean()方法,这个方法主要做的事情就是填充属性,注意了!当前正在执行A类的创建流程,现在要给A类填充属性了,而A类
依赖了B类,因此发现了B类,接下来就会去getBean(B类),于是又走了一遍A类一样的流程
继续完成B类的生命周期,此使缓存池状态如下:
Set集合此使存了A,B
二级缓存存了A,B
接着B对象继续生命周期,当B对象的属性填充的时候发觉B对象又依赖与A
于是又去getBean(A),这时候依然还是get不到A的,因为A还不是一个完整的Bean,此使还只是存在二级缓存内
然后继续A的生命周期,到getSingleton(beanName)的时候,这次拿就不是空的了,这次能拿到一个A对象,为什么呢?
这时候可以讲讲getSingleton(beanName)的具体逻辑了:
先会从单例池里去拿,这时候拿不到是因为A对象还不是一个完整的bean,只是还正在创建当中
里面有个判断,如果当前对象正在创建中,就会从三级缓存里去拿,三级缓存拿不到,然后再去二级缓存去拿,
上面说到当前二级缓存里存了A,B,目前正在get(A),那么就能拿到了A的工厂对象,接着再从工厂对象里面拿出一个对象放到三级缓存里面,
然后再把二级缓存删掉
当前缓存池状态如下:
Set集合此使存了A,B
二级缓存存了B
三级缓存存了A
此时在给B填充A的时候,A能返回回去,那么被依赖的B类就是一个完整的bean了
B现在是个bean对象,也就能给A填充了
循环依赖就完美被解决
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
开始准备创建Bean,来到了AbstractAutowireCapableBeanFactory#createBean()
...
//要开始创建bean了!! 在真正要干活前,spring通常会在名字前面加个do
Object beanInstance = doCreateBean(beanName, mbdToUse, args);
2
3
4
5
6
doCreateBean():
if (instanceWrapper == null) {
/**
* 实例化对象,调用我们的构造方法,里面第二次调用后置处理器 (早期对象)
*/
instanceWrapper = createBeanInstance(beanName, mbd, args);
}
....
//判断是否允许循环依赖
//1.bean是否是单例
//2.系统配置是否允许循环依赖
//3.当前bean是否正在创建
boolean earlySingletonExposure = (mbd.isSingleton() && this.allowCircularReferences &&
isSingletonCurrentlyInCreation(beanName));
if (earlySingletonExposure) {
if (logger.isTraceEnabled()) {
logger.trace("Eagerly caching bean '" + beanName +
"' to allow for resolving potential circular references");
}
//第四次调用后置处理器,判断是否需要AOP||| 暴露早期对象到三级缓存中
addSingletonFactory(beanName, () -> getEarlyBeanReference(beanName, mbd, bean));
}
...
/**
* 填充属性,完成自动注入
* 里面会完成第五次和第六次后置处理器的调用
*/
populateBean(beanName, mbd, instanceWrapper);
//初始化spring
//里面会进行第七次和第八次后置处理器的调用
exposedObject = initializeBean(beanName, exposedObject, mbd);
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37