【spring源码】spring中bean的创建流程,三级缓

这是我参与更文挑战的第1天,活动详情查看: 更文挑战

前面的文章主要写了spring源码工厂后置处理器所干的事情,即spring工程的扫描,解析,得到beanDefinition以及所有的beanName,还有注解@Import的原理,以及引入ImportSelectorImportBeanDefinitionRegistrar的应用,有兴趣的可以看看前面的文章。

这篇文章开始写bean的实例化过程,读源码比较枯燥,相关的文章也比较枯燥,我尽量写简单明了点。

1.概述

bean创建过程.png

上面的图大概画了整个bean的创建流程,spring在创建bean之前首先从缓存池中去getBean,当从缓存池中获取不到bean时,才会去创建bean。了解spring源码的同学知道,spring中有三级缓存:

  • 一级缓存:singletonObjects —> 存放完整bean的单例池
  • 二级缓存:earlySingletonObjects —> 存放非完整bean的单例池,存放早期暴露的bean
  • 三级缓存:singletonFactories —> 存放可以创建bean的factory,这里的factory主要是去创建bean的代理对象

在创建bean的过程中,会通过bean后置处理去拿到bean的构造方法,对bean进行创建,然后对bean进行包装代理,如果bean不需要进行包装代理,就会返回一个早期暴露的对象,并放入二级缓存中,如果需要进行包装代理,就会返回一个factory,并放入三级缓存中。

然后会组装bean,这个过程就是去装配bean的属性,当bean装配完成后,bean就算是一个完整的bean了,最后会把这个完整的bean放入单例池中,即一级缓存中。

这就是bean创建的整个过程,这里概述了一下,也是想读到这篇文章的同学心里有一个大概,后面不至于晕乎乎的,下面就进入源码阅读阶段吧。

2.从缓存池中getBean

我们直接看doGetBean()这个方法,方法路径:AbstractBeanFactory#doGetBean(),在该方法最开始的时候就是去从单例池获取bean:

缓存getBean.png

接下来就点进这个方法看看是怎么从缓存中获取bean的:

getBean.png

可以看到代码中,首先是从一级缓存中去拿bean,当拿不到bean时,且当前bean正在被创建,就会从二级缓存中去获取,当二级拿不到时,从三级缓存中获取factory对象,如果拿到了factory对象,会从factory中去获取bean,最后将该bean放入二级缓存中。

由于spring工程在启动时,缓存里肯定没有bean对象,于是就需要去创建bean,接下来看bean是如何创建的。

3.bean的创建

还是doGetBean()方法,看一下最重要的代码片段:

getSingleton2.png

这里有两个方法,先看方法1,即createBean(beanName, mbd, args);点进这个方法去看看,这里省略了一些不重要的代码:

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
java复制代码protected Object createBean(String beanName, RootBeanDefinition mbd, @Nullable Object[] args)
throws BeanCreationException {

//... ...

// Prepare method overrides.
try {
/**
* 处理lookup-Method 和replace-Method,统称为overrides
*/
mbdToUse.prepareMethodOverrides();
}
//... ...

try {
// Give BeanPostProcessors a chance to return a proxy instead of the target bean instance.
/**
* 里面有个后置处理器,如果这个后置处理器能返回一个bean,就直接返回了,不再进行后面的装配,不理会里面的依赖
* InstantiationAwareBeanPostProcessor
*/
Object bean = resolveBeforeInstantiation(beanName, mbdToUse);
if (bean != null) {
return bean;
}
}
//... ...

try {
/**
* 创建对象
*/
Object beanInstance = doCreateBean(beanName, mbdToUse, args);
if (logger.isTraceEnabled()) {
logger.trace("Finished creating instance of bean '" + beanName + "'");
}
return beanInstance;
}
//... ...
}

可以看到这段代码片段里,首先是去处理overrides,然后去调用一个bean后置处理(InstantiationAwareBeanPostProcessor)的方法,如果该方法返回了一个对象,则返回该对象,不进行后面的bean创建流程。

接下来看看创建对象这个方法:Object beanInstance = doCreateBean(beanName, mbdToUse, args);

在这个方法里,我们一部分一部分的来看,第一部分就是去创建bean对象:

createBean1.png

来看看创建包装对象的部分,点进这个方法中:instanceWrapper = createBeanInstance(beanName, mbd, args); 依然省略一部分不重要的代码:

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
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
java复制代码protected BeanWrapper createBeanInstance(String beanName, RootBeanDefinition mbd, @Nullable Object[] args) {
//... ...
/**
* supplier的方式实例化对象
*/
Supplier<?> instanceSupplier = mbd.getInstanceSupplier();
if (instanceSupplier != null) {
return obtainFromSupplier(instanceSupplier, beanName);
}

/**
* 如果 FactoryMethodName 不为空,通过 instantiateUsingFactoryMethod() 去实例化对象
* 通过xml去指定 FactoryMethodName
* @Bean 当是static的时候,相当于是给对象配置了一个 FactoryMethodName
* 不是static的时候, 是uniqueFactoryMethodName
* 具体看ConfigurationClassPostProcessor
*/
if (mbd.getFactoryMethodName() != null) {
return instantiateUsingFactoryMethod(beanName, mbd, args);
}

// Shortcut when re-creating the same bean...
/**
* 从Spring的原始注释中,可以知道这是一个Shortcut(快捷方式),什么意思呢?
* 当多次构建同一bean时,可以使用这个 Shortcut
* 也就是不需要再次推断使用哪种方式构造bean
*/
boolean resolved = false;
boolean autowireNecessary = false;
if (args == null) {
synchronized (mbd.constructorArgumentLock) {
if (mbd.resolvedConstructorOrFactoryMethod != null) {
resolved = true;
autowireNecessary = mbd.constructorArgumentsResolved;
}
}
}
if (resolved) {
if (autowireNecessary) {
return autowireConstructor(beanName, mbd, null, null);
}
else {
return instantiateBean(beanName, mbd);
}
}

// Candidate constructors for autowiring?
/**
* 由后置处理器(SmartInstantiationAwareBeanPostProcessor)决定 返回 有参数的 构造方法
* 如果只有一个无参构造方法,这里返回为 null
*/
Constructor<?>[] ctors = determineConstructorsFromBeanPostProcessors(beanClass, beanName);
/**
* 自动装配模型 != 自动装配技术
* 自动装配模型 默认为 0
*/
if (ctors != null || mbd.getResolvedAutowireMode() == AUTOWIRE_CONSTRUCTOR ||
mbd.hasConstructorArgumentValues() || !ObjectUtils.isEmpty(args)) {
return autowireConstructor(beanName, mbd, ctors, args);
}

// Preferred constructors for default construction?
ctors = mbd.getPreferredConstructors();
if (ctors != null) {
return autowireConstructor(beanName, mbd, ctors, null);
}

// No special handling: simply use no-arg constructor.
/**
* 通过默认的无参构造方法进行初始化
*/
return instantiateBean(beanName, mbd);
}

该方法主要是讲如何去创建bean,首先是通过supplier的方式实例化对象,其次是通过FactoryMethodName的方式去实例化对象(这种方式好像没用过,有大神知道吗),再然后是通过bean后置处理器去找到bean的构造方法,如果bean中定义了有参构造方法,就返回有参构造方法,determineConstructorsFromBeanPostProcessors(beanClass, beanName);这里面有一些逻辑,感兴趣的同学可以自己去看一看,如果没有找到有参构造方法,就返回默认的无参构造方法。到这里就返回了一个BeanWrapper对象。

4.代理bean,放入三级缓存

前面bean已经被实例化出来了,因为spring中有些对象需要被代理,来看看这段代码:

addSingleton.png

getEarlyBeanReference(beanName, mbd, bean));这个方法里,实际上就是去执行bean后置处理器中的方法,对bean进行代理:

1
2
java复制代码Object proxy = createProxy(
bean.getClass(), beanName, specificInterceptors, new SingletonTargetSource(bean));

最后会调用 ProxyFactory#getProxy 方法:

代理.png

这里是不是就是我们熟悉的JDK代理和Cglib代理~

然后看 addSingletonFactory() 这个方法:

1
2
3
4
5
6
7
8
9
10
java复制代码protected void addSingletonFactory(String beanName, ObjectFactory<?> singletonFactory) {
Assert.notNull(singletonFactory, "Singleton factory must not be null");
synchronized (this.singletonObjects) {
if (!this.singletonObjects.containsKey(beanName)) {
this.singletonFactories.put(beanName, singletonFactory);
this.earlySingletonObjects.remove(beanName);
this.registeredSingletons.add(beanName);
}
}
}

这里就是将factory对象放入三级缓存中。

5.组装bean,循环依赖问题

这里就不贴代码了,感兴趣的同学下来再研究吧。这里就是对bean的属性进行填充,比如A依赖B,这里就是去填充B.

这里涉及到一个很经典的问题,就是spring中的循环依赖问题,spring到底是怎么解决循环依赖问题的呢?

我在读spring源码后,画了一张图,来清晰的表示:

循环依赖.png

假设A和B相互依赖,当创建A到了组装这一步骤时,需要去组装B,这个时候就会去getB,但是get不到,就会去创建B,当创建B到组装这一步骤时,需要去组装A,而A这个bean已经创建过了,并且在缓存中,可以得到A,这个时候B就组装完成了,而当B组装完成了,相应的A也组装完成。

最后A和B都是一个完整的bean,然后被放入一级缓存中,即单例池中。

到这里bean的整个创建过程和spring的循环依赖问题就讲完了,希望看到这篇文章的同学有所收获。

本文转载自: 掘金

开发者博客 – 和开发相关的 这里全都有

0%