Bean 的创建与获取是一个比较复杂的过程,本文主要关注 bean 获取的过程。
代码
一个比较好的阅读源码的方法是 debug,可以跟踪到代码执行的每一步。如下是一段测试代码,可用于调试 getBean 方法的调用过程。
1 | // 定义 bean factory |
这里定义了一个 DefaultListableBeanFactory 作为 Spring 的 bean factory,然后为类型 A
创建了一个 RootBeanDefinition,将其 scope 设置为 singleton,并注入到 bean factory 中,最后通过 BeanFactory 接口的 getBean
方法获取该 bean 实例。
获取过程
在 IDE 中调试上面的代码,跟踪 getBean
方法的执行过程
首先看到的是 AbstractBeanFactory 的 getBean 方法,它的实现如下:
1 | public Object getBean(String name) throws BeansException { |
可以看到是交给 doGetBean 方法处理的,这个方法才是具体的执行者。
doGetBean
doGetBean 是 AbstractBeanFactory 类里的一个核心方法,它封装的获取 bean 的整个流程,也是我们要看的重点。它签名如下:
1 | /** |
转换 beanName
第一步要对 beanName 进行处理:如果是 factoryBean 则去掉前缀 &
,然后将别名转换为原始名
1 | protected String transformedBeanName(String name) { |
通过 BeanFactoryUtils.transformedBeanName(String name)
方法去掉 &
符号前缀
1 | public static String transformedBeanName(String name) { |
通过 SimpleAliasRegistry.canonicalName(String name)
方法获取原名
1 | public String canonicalName(String name) { |
尝试从 singleton 缓存中获取
拿到了 beanName 之后,先到 singleton 缓存中查询
1 | // DefaultSingletonBeanRegistry |
因为 bean 还未创建,也不在创建过程中,所以 isSingletonCurrentlyInCreation(beanName)
返回 false
,跳过后续处理,返回 null
若从 singleton 缓存中获取到
若从缓存获取到实例,并且参数为空,首先要判断下 bean 是否正在创建中(处理循环引用),然后对 bean 进行处理,获取实际需要的 bean(比如 sharedInstance 为 factoryBean,实际需要的是它对应的实例,则在这一步处理)
1 | // 已经注册过,并且参数为空 |
这里取到的是 null,即未获取到,所以继续走下面的获取 bean 流程。
若未从 singleton 缓存中获取到
第一次调 doGetBean 时,bean 还未创建,因此从缓存中取不到,会走到下面的流程
检测 Prototype 循环引用
对 prototype 的循环引用进行检测,如果是正在创建中,则说明有循环引用,则抛异常结束
1 | // 如果是 prototype 的,并且正在创建中,抛异常结束 |
委托给 parentBeanFactory
若 parentBeanFactory 不为空,并且当前 BeanFactory 不存在这个 bean,则需要交给 parentBeanFactory 处理
先要获取到原始的 bean name,用于后续 getBean
1 | /** |
- 如果 parentBeanFactory 是 AbstractBeanFactory 类型的实例,则直接调用 doGetBean 方法
- 否则,如果 args 不为空,则委托 BeanFactory 的
getBean(String name, Object... args)
方法 - 否则,如果 requiredType 不为空,则委托 BeanFactory 的 getBean(String name, Class
requiredType) 方法 - 否则,委托 BeanFactory 的 getBean(String name) 方法
1 | // 获取 parent bean factory |
标记 bean 已经创建
如果要创建的 bean 不是仅用于类型检查,那么需要标记 bean 的状态为已创建
1 | // 如果不是仅用于类型检查,则标记 bean 已经创建 |
获取 MergedBeanDefinition
所谓 MergedBeanDefinition,可以理解为合并后的 BeanDefinition。这是因为 BeanDefinition 可能存在继承关系,需要合并相关属性后才能得到完整的 BeanDefinition,进而用于创建 Bean。
获取注册的 BeanDefinition
首先要先根据 beanName 拿到已注册的 BeanDefinition
1 | /** |
具体是交给 DefaultListableBeanFactory 进行处理的
1 | public BeanDefinition getBeanDefinition(String beanName) throws NoSuchBeanDefinitionException { |
进行合并处理
已注册的 BeanDefinition 可能是 ChildBeanDefinition,还需要进一步处理
1 | protected RootBeanDefinition getMergedBeanDefinition(String beanName, BeanDefinition bd) |
先尝试从 mergedBeanDefinitions 缓存获取,若未获取到,则进行下面的操作
mbd = this.mergedBeanDefinitions.get(beanName);
若该 BeanDefinition 没有 parent,则直接构造 RootBeanDefinition
1
2
3
4
5
6if (bd instanceof RootBeanDefinition) {
mbd = ((RootBeanDefinition) bd).cloneBeanDefinition();
}
else {
mbd = new RootBeanDefinition(bd);
}否则,获取 parentBean 的名字
1
2// 获取 parentBean 的名字
String parentBeanName = transformedBeanName(bd.getParentName());若和当前的不是同一个 bean,则需要合并
1
2
3
4// 和当前的不是同一个,则需要合并
if (!beanName.equals(parentBeanName)) {
pbd = getMergedBeanDefinition(parentBeanName);
}1
2
3
4
5
6
7
8
9
10
11
12
13
14public BeanDefinition getMergedBeanDefinition(String name) throws BeansException {
// 拿到原始的beanName
String beanName = transformedBeanName(name);
// 不在当前的bean factory里,那么去parent bean factory里找找
// Efficiently check whether bean definition exists in this factory.
if (!containsBeanDefinition(beanName) && getParentBeanFactory() instanceof ConfigurableBeanFactory) {
return ((ConfigurableBeanFactory) getParentBeanFactory()).getMergedBeanDefinition(beanName);
}
// 自己解析吧
// Resolve merged bean definition locally.
return getMergedLocalBeanDefinition(beanName);
}否则,交给 parentBeanFactory 处理
1
2
3
4
5
6
7
8
9
10
11
12// 获取 parent BeanFactory
BeanFactory parent = getParentBeanFactory();
// 通过 parentBeanFactory 合并 bean definition
if (parent instanceof ConfigurableBeanFactory) {
pbd = ((ConfigurableBeanFactory) parent).getMergedBeanDefinition(parentBeanName);
}
else {
throw new NoSuchBeanDefinitionException(parentBeanName,
"Parent name '" + parentBeanName + "' is equal to bean name '" + beanName +
"': cannot be resolved without an AbstractBeanFactory parent");
}深拷贝。通过 4、5 获取到的 BeanDefintion 并不直接使用,而是返回深拷贝的结果
1
2
3// 深拷贝,并且覆盖属性值
mbd = new RootBeanDefinition(pbd);
mbd.overrideFrom(bd);到这里已经拿到了 MergedBeanDefinition,剩下的就是一些通用的设置
1
2
3
4
5
6
7
8
9
10// 如果未配置 scope,则设置为默认的 singleton scope
if (!StringUtils.hasLength(mbd.getScope())) {
mbd.setScope(RootBeanDefinition.SCOPE_SINGLETON);
}
// 如果一个 bean 被包含在非 singleton 的 bean 中,那么这个 bean 也不能是 singleton 的
// 这里会对其进行修正
if (containingBd != null && !containingBd.isSingleton() && mbd.isSingleton()) {
mbd.setScope(containingBd.getScope());
}最后,就是将处理好的 MergedBeanDefinition 放入到缓存中,以便后续使用
1
2
3
4// 放到缓存中
if (containingBd == null && isCacheBeanMetadata()) {
this.mergedBeanDefinitions.put(beanName, mbd);
}
进行必要的检查
若 bean 定义为 abstract 的,则直接抛出异常结束流程
1 | protected void checkMergedBeanDefinition(RootBeanDefinition mbd, String beanName, @Nullable Object[] args) |
DependsOn 处理
若定义了 DependOn (依赖的 bean),则注册依赖关系,并且通过 getBean 方法触发这些 bean 的注册
1 | String[] dependsOn = mbd.getDependsOn(); |
Singleton bean 获取
若为 Singleton Bean
1 | if (mbd.isSingleton()) |
则通过 getSingleton(String beanName, ObjectFactory<?> singletonFactory)
方法获取,这里会注册一个 ObjectFactory 用于获取 bean 实例,它的实质是调用 createBean(String beanName, RootBeanDefinition mbd, @Nullable Object[] args)
方法。
1 | sharedInstance = getSingleton(beanName, () -> { |
获取到的 bean 可能是一个 FactoryBean,而由 beanName 指定的、实际要获取的可能是由 FactoryBean 创建的 bean,因此还需要进一步处理
1 | // 如果 sharedInstance 不是 FactoryBean 就直接返回。否则,如果 beanName 表示要获取的就是 FactoryBean |
具体实现如下:
1 | protected Object getObjectForBeanInstance( |
Prototype bean 获取
创建前要设置正在创建的状态,防止循环引用时会用到
1 | protected void beforePrototypeCreation(String beanName) { |
与 singleton 类型不同的是,这里是直接调用 createBean 创建实例。这是因为不需要对 prototype 类型的 bean 进行缓存,每次调用都需要创建新的实例。
相关流程如下,这里也需要对 FactoryBean 进行处理
1 | // It's a prototype -> create a new instance. |
其他 scope 的 bean 获取
与 singeton 类型 bean 的获取类似,区别是创建不是交给 DefaultSingletonBeanRegistry 处理,而是交给对应的 Scope 处理
1 | String scopeName = mbd.getScope(); |
类型处理
若指定了 requiredType,并且获取到的 bean 实例类型不匹配,则需要对类型进行转换操作。
这里首先要拿到 TypeConverter
1 | public TypeConverter getTypeConverter() { |
然后尝试对类型进行转换
1 | T convertedBean = getTypeConverter().convertIfNecessary(bean, requiredType); |
整体代码如下:
1 | // 最后检查下类型是否匹配 |
时序图
流程图
获取 Spring bean 的主要流程如下: