在bean被加载之前, 需要创建spring上下文, 之后才能加载bean. 创建上下文的过程就是创建ICO容器的部分.
如果细分的话, 可以分为三步
- 创建IOC容器
- 从注解和xml, 解析并注册bean
- 开始创建bean
对于BeanFactory来说,对象实例化默认采用延迟初始化。通常情况下,当对象A被请求而需要第一次实例化的时候,如果它所依赖的对象B之前同样没有被实例化,那么容器会先实例化对象A所依赖的对象。这时容器内部就会首先实例化对象B,以及对象 A依赖的其他还没有实例化的对象。这种情况是容器内部调用getBean(),对于本次请求的请求方是隐式的。
ApplicationContext启动之后会实例化所有的bean定义,但ApplicationContext在实现的过程中依然遵循Spring容器实现流程的两个阶段,只不过它会在启动阶段的活动完成之后,紧接着调用注册到该容器的所有bean定义的实例化方法getBean()。这就是为什么当你得到ApplicationContext类型的容器引用时,容器内所有对象已经被全部实例化完成。
- AbstractApplicationContext.refresh 方法, 在其中会实例化所有bean.
- 实例化bean是调用 AbstractBeanFactory.doGetBean 方法实现的.
- 首先要转换beanName, 因为可能是别名也可能是FactoryBean
- 会尝试从第一个map中获取bean, 如果没有就创建.
- 单例会在实例化但未初始化的时候将Bean包装后的ObjectFactory加入第二个map.
- 这样, 可以先返回未初始化完成的类, 而不是每次都重新创建. 避免循环依赖问题.
- 其实还有第三个map, 会在使用到第二个map的时候将其取出加入第三个map中. 注意第二个map是包装后的, 而这个map是实例化对象.
- 原型bean, 如果发现循环依赖就直接抛出异常
- 在创建bean之前会记录正在创建, 用来判断循环引用
- 之后就是创建实例, 并缓存实例化但未初始化的bean, 之后再注入属性
- 还有一种bean叫做FactoryBean, 用于扩展beanFactory, 实现定制化的bean实例创建逻辑
源码
加载bean, 需要先从注解或者xml解析bean. 之后就是创建bean的过程.
doGetBean
首先初始化bean的入库是getbean方法, 其中调用了doGetBean方法.
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
protected T doGetBean(final String name, @Nullable final Class requiredType,
@Nullable final Object[] args, boolean typeCheckOnly) throws BeansException{
// 首先是转换格式化beanName
final String beanName = transformedBeanName(name);
Object bean;
// 尝试通过bean名称获取目标bean对象
Object sharedInstance = getSingleton(beanName);
// 尝试加载工厂bean
if (sharedInstance != null && args == null) {
// log...
bean = getObjectForBeanInstance(sharedInstance, name, beanName, null);
}
else{
// 如果不是单例模式(原型模式) 并发送循环依赖 则直接抛异常
if (isPrototypeCurrentlyInCreation(beanName)) {
throw new BeanCurrentlyInCreationException(beanName);
}
//... 省略部分代码 看单例部分的实现
// 单例
if (mbd.isSingleton()) {
// 这里就尝试创建目标对象,第二个参数传的就是一个ObjectFactory类型的对象,
// 这里是使用Java8的lamada
// 表达式书写的,只要上面的getSingleton()方法返回值为空,
// 则会调用这里的getSingleton()方法来创建目标对象
sharedInstance = getSingleton(beanName, () -> {
try {
// 尝试创建目标对象
return createBean(beanName, mbd, args);
} catch (BeansException ex) {
throw ex;
}
});
}
// ... 省略了部分代码
}
// 检查需要的类型是否符合bean的实际类型,对应getBean时指定的requireType
if (requiredType != null && bean != null && !requiredType.isAssignableFrom(bean.getClass())) {
try {
// 执行类型转换,转换成期望的类型
return this.getTypeConverter().convertIfNecessary(bean, requiredType);
} catch (TypeMismatchException ex) {
if (logger.isDebugEnabled()) {
logger.debug(“Failed to convert bean ‘” + name + “’ to required type ‘” + ClassUtils.getQualifiedName(requiredType) + “’”, ex);
}
throw new BeanNotOfRequiredTypeException(name, requiredType, bean.getClass());
}
}
return (T) bean;
}
上面的代码是省略了一部分. 重点展示了主流程. 我们先来看第一个getSingleton方法.
getSingleton 缓存
我们需要知道这三个Map
- singletonFactories: Map<String, ObjectFactory<?» 类型,用于记录创建bean的工厂
- singletonObjects: Map<String, Object> 类型,用于记录bean实例
- earlySingletonObjects: Map<String, Object> 类型,用于记录原始bean实例(未创建完成的)
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
protected Object getSingleton(String beanName, boolean allowEarlyReference) {
// 首先尝试从singletonObjects获取是否存在以及初始化好的bean
Object singletonObject = this.singletonObjects.get(beanName);
// 如果为空, 且发现已经在初始化
if (singletonObject == null && isSingletonCurrentlyInCreation(beanName)) {
synchronized (this.singletonObjects) {
// 从未初始化好的map中查询
singletonObject = this.earlySingletonObjects.get(beanName);
// 如果为空, 且允许早期依赖
if (singletonObject == null && allowEarlyReference) {
// 获取创建对象的工厂
ObjectFactory<?> singletonFactory = this.singletonFactories.get(beanName);
if (singletonFactory != null) {
// 获取对象实例(可能是没加载好的)
singletonObject = singletonFactory.getObject();
// 将其提前暴露, 放入为初始化好的map中
this.earlySingletonObjects.put(beanName, singletonObject);
this.singletonFactories.remove(beanName);
}
}
}
}
return singletonObject;
}
// 这里会在执行创建之前将beanName加入set中
public boolean isSingletonCurrentlyInCreation(String beanName) {
return this.singletonsCurrentlyInCreation.contains(beanName);
}
这里的思路其实很简单, 就是先查询已经创建好的缓存(singletonObjects
), 如果查到就直接返回; 如果没有已经创建好的对象, 则在未创建好的对象缓存(earlySingletonObjects
)中查找; 如果其中还没有对象则会取其对应的创建工厂, 从创建工厂(singletonFactories
)中取出还没有创建好的缓存并插入刚刚的 earlySingletonObjects
缓存中.
这里如果allowEarlyReference为true且是单例模式, 则会使用上述的方法. 在对象实例创建完成但没有初始化其中field的时候, 将这个半成品的封装到 singletonFactories
中. 这样在之后尝试获取的时候就会发现其中在创建bean了. 将半成品取出放到半成品Map中. 可以先将半成品设置为其他类的属性.
核心点如下
- 这里的创建工厂其实就像对于未完全创建好的bean的封装.
- 未完全创建好的bean, 这个半成品其实是实例化了但没有初始化其中的field.
- 这样的意义是, 可以在让A中的field赋值未初始化的B. 这样如果A/B循环引用, 都可以先引用未初始化完成的bean, 就不会无限循环其初始化了.
- 只有单例可以使用这个逻辑, 也就是只有单例可以解决循环依赖问题.
这样大致的思路就有了, 之后我们再看下怎么去创建bean的.
createBean
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
protected Object createBean(String beanName, RootBeanDefinition mbd, @Nullable Object[] args) throws BeanCreationException {
//... 校验是否可以被classLoader加载
try {
// bean加载记录, 用以判断循环引用和是否已经被加载
mbdToUse.prepareMethodOverrides();
}
catch (BeanDefinitionValidationException ex) {
throw new BeanDefinitionStoreException(mbdToUse.getResourceDescription(),
beanName, “Validation of method overrides failed”, ex);
}
try {
// 创建bean
Object beanInstance = doCreateBean(beanName, mbdToUse, args);
if (logger.isTraceEnabled()) {
logger.trace("Finished creating instance of bean '" + beanName + "'");
}
return beanInstance;
}
catch (BeanCreationException | ImplicitlyAppearedSingletonException ex) {
throw ex;
}
catch (Throwable ex) {
throw new BeanCreationException(
mbdToUse.getResourceDescription(), beanName, "Unexpected exception during bean creation", ex);
}
}
所以说, 具体实现还要看doCreateBean方法.
doCreateBean
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
protected Object doCreateBean(final String beanName, final RootBeanDefinition mbd, final @Nullable Object[] args)
throws BeanCreationException {
// 实例化当前尝试获取的bean对象,比如A对象和B对象都是在这里实例化的
BeanWrapper instanceWrapper = null;
if (mbd.isSingleton()) {
instanceWrapper = this.factoryBeanInstanceCache.remove(beanName);
}
if (instanceWrapper == null) {
// 创建实例
instanceWrapper = createBeanInstance(beanName, mbd, args);
}
// 调用所有的bean后置处理器
synchronized (mbd.postProcessingLock) {
if (!mbd.postProcessed) {
try {
applyMergedBeanDefinitionPostProcessors(mbd, beanType, beanName);
}
catch (Throwable ex) {
throw new BeanCreationException(mbd.getResourceDescription(), beanName,
“Post-processing of merged bean definition failed”, ex);
}
mbd.postProcessed = true;
}
}
// 判断Spring是否配置了支持提前暴露目标bean,也就是是否支持提前暴露半成品的bean
boolean earlySingletonExposure = (mbd.isSingleton() && this.allowCircularReferences
&& isSingletonCurrentlyInCreation(beanName));
if (earlySingletonExposure) {
// 如果支持,这里就会将当前生成的半成品的bean放到singletonFactories中,这个singletonFactories
// 就是前面第一个getSingleton()方法中所使用到的singletonFactories属性,也就是说,这里就是
// 封装半成品的bean的地方。而这里的getEarlyBeanReference()本质上是直接将放入的第三个参数,也就是目标bean直接返回
addSingletonFactory(beanName, () -> getEarlyBeanReference(beanName, mbd, bean));
}
try {
// 在初始化实例之后,这里就是判断当前bean是否依赖了其他的bean,如果依赖了,
// 就会递归的调用getBean()方法尝试获取目标bean
populateBean(beanName, mbd, instanceWrapper);
// 调用 init-method
exposedObject = initializeBean(beanName, exposedObject, mbd);
} catch (Throwable ex) {
// 省略...
}
return exposedObject;
}
这里首先是创建实例, 将BeanDefinition转换为BeanWrapper。
- 如果存在工厂方法则使用工厂方法进行初始化
- 一个类有多个构造函数,每个构造函数都有不同的参数,所以需要根据参数锁定构造函数进行 bean 的实例化
- 如果即不存在工厂方法,也不存在带有参数的构造函数,会使用默认的构造函数进行 bean 的实例化
接着调用所有的bean后置处理器, 其中就有@Autowired的实现
之后处理了循环依赖问题, 就是我们之前说过的提前暴露实例化但未初始化半成品的策略
开始属性注入
- autowireByName 通过名字加载bean
- autowireByType 加载同一类型的所有bean (加载出来一个list)
最后还会调用客户设定的初始化方法, 以及注册DisposableBean
getSingleton 创建
这样在来看一下调用创建bean的代码
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
public Object getSingleton(String beanName, ObjectFactory<?> singletonFactory) {
Assert.notNull(beanName, "Bean name must not be null");
// 加锁
synchronized (this.singletonObjects) {
// 检查是否已经被加载了,单例模式就是可以复用已经创建的 bean
Object singletonObject = this.singletonObjects.get(beanName);
if (singletonObject == null) {
// 初始化前操作,校验是否 beanName 是否有别的线程在初始化,并加入初始化状态中
beforeSingletonCreation(beanName);
boolean newSingleton = false;
boolean recordSuppressedExceptions = (this.suppressedExceptions == null);
if (recordSuppressedExceptions) {
this.suppressedExceptions = new LinkedHashSet<>();
}
// 初始化 bean,这个就是刚才的回调接口调用的方法,实际执行的是 createBean 方法
singletonObject = singletonFactory.getObject();
newSingleton = true;
if (recordSuppressedExceptions) {
this.suppressedExceptions = null;
}
// 初始化后的操作,移除初始化状态
afterSingletonCreation(beanName);
if (newSingleton) {
// 加入缓存
addSingleton(beanName, singletonObject);
}
}
return singletonObject;
}
}
这里就是加锁并调用 createBean 方法.
getObjectForBeanInstance
一般情况下Spring通过bean中的class属性,通过反射创建Bean的实例。但在某些情况下,实例化Bean的过程比较复杂,如果按照传统的方式,则需要在bean标签中提供大量的配置信息,配置方式的灵活性是受限的,这时采用编码的方式可能会得到一个简单的方案。Spring为此提供了一个 FactoryBean
的接口。用户可以实例化该接口,实现定制化bean实例创建逻辑
FactoryBean接口对应Spring框架来说占有重要的地位,Spring本身就提供了70多个FactoryBean的实现。他们隐藏了实例化一些复杂的细节,给上层应用带来了便利。从Spring3.0开始,FactoryBean开始支持泛型。
比如 Dubbo 的服务导入就是实现了 FactoryBean 接口, 在 getObject 方法中实现了服务导入.
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
protected Object getObjectForBeanInstance(
Object beanInstance, String name, String beanName, @Nullable RootBeanDefinition mbd) {
// 校验...
// 如果不是FactoryBean 或者带有&前缀 返回类本身
if (!(beanInstance instanceof FactoryBean) || BeanFactoryUtils.isFactoryDereference(name)) {
return beanInstance;
}
Object object = null;
if (mbd == null) {
// 尝试缓存中获取
object = getCachedObjectForFactoryBean(beanName);
}
if (object == null) {
// 这里就确定是FactoryBean了
FactoryBean<?> factory = (FactoryBean<?>) beanInstance;
// 再次尝试从缓存中获取
if (mbd == null && containsBeanDefinition(beanName)) {
mbd = getMergedLocalBeanDefinition(beanName);
}
boolean synthetic = (mbd != null && mbd.isSynthetic());
object = getObjectFromFactoryBean(factory, beanName, !synthetic);
}
return object;
}
需要注意的是, 这个方法返回的是 FactoryBean.getObject()
, 而不是FactoryBean本身. 如果想要获取的是FactoryBean则需要加上’&’符, 这样就会返回FactoryBean本身了.