# Spring应用与源码分析

# Spring初始化

# Bean生命周期与循环依赖

用以下语句启动ioc容器,研究一下代码内部逻辑?

AnnotationConfigApplicationContext ac = new AnnotationConfigApplicationContext(AppConfig.class);
1

AnnotationConfigApplicationContext 类图: An image

构造函数:

public AnnotationConfigApplicationContext(Class<?>... componentClasses) {
    this();
    register(componentClasses);
    refresh();
}
1
2
3
4
5

# 1.this()

首先会执行父类的构造方法:

//初始化一个工厂类,用于创建bean对象
public GenericApplicationContext() {
    this.beanFactory = new DefaultListableBeanFactory();
}
1
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);
}
1
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);
    }
}
1
2
3
4
5
6

# 3.refresh()

首先进入AbstractApplicationContext.java的refresh():

....
//完成扫描,把beanDefinition对象存储到beanDefinitionMap
invokeBeanFactoryPostProcessors(beanFactory);

....
//准备走Bean的生命周期
finishBeanFactoryInitialization(beanFactory);

1
2
3
4
5
6
7
8

接着进入finishBeanFactoryInitialization():

...
//实例化所有的单例,非懒加载
beanFactory.preInstantiateSingletons();

1
2
3
4

接着进入ConfigurableListableBeanFactory抽象类的DefaultListableBeanFactory#preInstantiateSingletons()


//得到所有的beanDefinition的名字
List<String> beanNames = new ArrayList<>(this.beanDefinitionNames);

.... 省略部分:遍历验证beanDefinition

//便利beanNames,开始getBean  (重点开始)

1
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);
    }
    
}


1
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,只是还正在创建当中
里面有个判断,如果当前对象正在创建中,就会从三级缓存里去拿,三级缓存拿不到,然后再去二级缓存去拿,
上面说到当前二级缓存里存了AB,目前正在get(A),那么就能拿到了A的工厂对象,接着再从工厂对象里面拿出一个对象放到三级缓存里面,
然后再把二级缓存删掉
当前缓存池状态如下:
Set集合此使存了A,B
二级缓存存了B
三级缓存存了A
此时在给B填充A的时候,A能返回回去,那么被依赖的B类就是一个完整的bean了
B现在是个bean对象,也就能给A填充了
循环依赖就完美被解决

1
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);

1
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);


1
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
Last Updated: 3/4/2019, 4:34:52 PM