死磕Spring之IoC篇 - 开启 Bean 的加载
该系列文章是本人在学习 Spring 的过程中总结下来的,里面涉及到相关源码,可能对读者不太友好,请结合我的源码注释 Spring 源码分析 GitHub 地址 进行阅读
Spring 版本:5.1.14.RELEASE
开始阅读这一系列文章之前,建议先查看《深入了解 Spring IoC(面试题)》这一篇文章
该系列其他文章请查看:《死磕 Spring 之 IoC 篇 - 文章导读》
开启 Bean 的加载
前面的一些列文章对面向资源(XML、Properties)、面向注解定义的 Bean 是如何被解析成 BeanDefinition(Bean 的“前身”),并保存至 BeanDefinitionRegistry 注册中心里面,实际也是通过 ConcurrentHashMap 进行保存。
Spring 底层 IoC 容器 DefaultListableBeanFactory,实现了 BeanFactory 和 BeanDefinitionRegistry 接口,这个时候它处于“就绪状态”,当我们显示或者隐式地调用 getBean(...)
方法时,会触发加载 Bean 阶段,获取对应的 Bean。在该方法中,如果是单例模式会先从缓存中获取,已有则直接返回,没有则根据 BeanDefinition 开始初始化这个 Bean。
BeanFactory 体系结构
先来看看 BeanFactory 接口的继承关系
简单描述这些接口:
org.springframework.beans.factory.BeanFactory
,Spring IoC 容器最基础的接口,提供依赖查找单个 Bean 的功能org.springframework.beans.factory.ListableBeanFactory
,继承 BeanFactory 接口,提供依赖查找多个 Bean 的功能org.springframework.beans.factory.HierarchicalBeanFactory
,继承 BeanFactory 接口,提供获取父 BeanFactory 的功能,具有层次性org.springframework.beans.factory.config.ConfigurableBeanFactory
,继承 HierarchicalBeanFactory 接口,提供可操作内部相关组件的功能,具有可配置性org.springframework.beans.factory.config.AutowireCapableBeanFactory
,继承 BeanFactory 接口,提供可注入的功能,支持依赖注入org.springframework.beans.factory.config.ConfigurableListableBeanFactory
,继承上面所有接口,综合所有特性,还提供可提前初始化所有单例 Bean 的功能
通过这些接口的名称可以大致了解其用意,接下来我们来看看它们的实现类的继承关系
简单描述这些实现类:
org.springframework.beans.factory.support.AbstractBeanFactory
抽象类,实现 ConfigurableBeanFactory 接口,基础实现类,Bean 的创建过程交由子类实现org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory
抽象类,继承 AbstractBeanFactory,实现 AutowireCapableBeanFactory 接口,完成 Bean 的创建org.springframework.beans.factory.support.DefaultListableBeanFactory
,Spring 底层 IoC 容器,依赖注入的底层实现
其他的接口和类和 BeanDefinition 注册中心,别名注册中心,单例 Bean 注册中心相关;右下角的 ApplicationContext 与 Spring 应用上下文有关,它的整个体系这里不做展述,在后面的文章进行分析
AbstractBeanFactory
org.springframework.beans.factory.support.AbstractBeanFactory
抽象类,实现 ConfigurableBeanFactory 接口,BeanFactory 的基础实现类,提供依赖查找方法,可获取 Bean 对象,接下来我们来看看依赖查找的实现
getBean 方法
getBean(String name)
方法,根据名称获取 Bean,当然还有许多重载方法,如下:
@Override
public Object getBean(String name) throws BeansException {
return doGetBean(name, null, null, false);
}
@Override
public <T> T getBean(String name, Class<T> requiredType) throws BeansException {
return doGetBean(name, requiredType, null, false);
}
@Override
public Object getBean(String name, Object... args) throws BeansException {
return doGetBean(name, null, args, false);
}
public <T> T getBean(String name, @Nullable Class<T> requiredType, @Nullable Object... args)
throws BeansException {
return doGetBean(name, requiredType, args, false);
}
最终都会调用 doGetBean(...)
这个方法
当我们显示或者隐式地调用这个方法时,会触发 Bean 的加载;你是否会有疑问,我们使用 Spring 的过程中并不会调用这个方法去获取 Bean,那这个方法会被谁调用呢?在 ConfigurableListableBeanFactory 接口中提供提前初始化所有单例 Bean 的功能,在 Spring 应用上下文(ApplicationContext)刷新阶段会提前初始化所有的单例 Bean,这个提前初始化也是调用 getBean 这个方法,这部分内容在后续分析 Spring 应用上下文的生命周期会讲到
【核心】doGetBean 方法
doGetBean(final String name, @Nullable final Class<T> requiredType, @Nullable final Object[] args, boolean typeCheckOnly)
方法,获取一个 Bean,方法如下:
protected <T> T doGetBean(final String name, @Nullable final Class<T> requiredType,
@Nullable final Object[] args, boolean typeCheckOnly) throws BeansException {
// <1> 获取 `beanName`
// 因为入参 `name` 可能是别名,也可能是 FactoryBean 类型 Bean 的名称(`&` 开头,需要去除)
// 所以需要获取真实的 beanName
final String beanName = transformedBeanName(name);
Object bean;
// <2> 先从缓存(仅缓存单例 Bean )中获取 Bean 对象,这里缓存指的是 `3` 个 Map
// 缓存中也可能是正在初始化的 Bean,可以避免**循环依赖注入**引起的问题
// Eagerly check singleton cache for manually registered singletons.
Object sharedInstance = getSingleton(beanName);
// <3> 若从缓存中获取到对应的 Bean,且 `args` 参数为空
if (sharedInstance != null && args == null) {
if (logger.isTraceEnabled()) {
if (isSingletonCurrentlyInCreation(beanName)) {
logger.trace("Returning eagerly cached instance of singleton bean '" + beanName +
"' that is not fully initialized yet - a consequence of a circular reference");
}
else {
logger.trace("Returning cached instance of singleton bean '" + beanName + "'");
}
}
// <3.1> 获取 Bean 的目标对象,`scopedInstance` 非 FactoryBean 类型直接返回
// 否则,调用 FactoryBean#getObject() 获取目标对象
bean = getObjectForBeanInstance(sharedInstance, name, beanName, null);
}
// 缓存中没有对应的 Bean,则开启 Bean 的加载
else {
// Fail if we're already creating this bean instance:
// We're assumably within a circular reference.
// <4> 如果**非单例模式**下的 Bean 正在创建,这里又开始创建,表明存在循环依赖,则直接抛出异常
if (isPrototypeCurrentlyInCreation(beanName)) {
throw new BeanCurrentlyInCreationException(beanName);
}
// Check if bean definition exists in this factory.
BeanFactory parentBeanFactory = getParentBeanFactory();
// <5> 如果从当前容器中没有找到对应的 BeanDefinition,则从父容器中加载(如果存在父容器)
if (parentBeanFactory != null && !containsBeanDefinition(beanName)) {
// Not found -> check parent.
// <5.1> 获取 `beanName`,因为可能是别名,则进行处理
// 和第 `1` 步不同,不需要对 `&` 进行处理,因为进入父容器重新依赖查找
String nameToLookup = originalBeanName(name);
// <5.2> 若为 AbstractBeanFactory 类型,委托父容器的 doGetBean 方法进行处理
// 否则,就是非 Spring IoC 容器,根据参数调用相应的 `getBean(...)`方法
if (parentBeanFactory instanceof AbstractBeanFactory) {
return ((AbstractBeanFactory) parentBeanFactory).doGetBean(nameToLookup, requiredType, args, typeCheckOnly);
}
else if (args != null) {
return (T) parentBeanFactory.getBean(nameToLookup, args);
}
else if (requiredType != null) {
return parentBeanFactory.getBean(nameToLookup, requiredType);
}
else {
return (T) parentBeanFactory.getBean(nameToLookup);
}
}
// <6> 如果不是仅仅做类型检查,则表示需要创建 Bean,将 `beanName` 标记为已创建过
if (!typeCheckOnly) {
markBeanAsCreated(beanName);
}
try {
// <7> 从容器中获取 `beanName` 对应的的 RootBeanDefinition(合并后)
final RootBeanDefinition mbd = getMergedLocalBeanDefinition(beanName);
// 检查是否为抽象类
checkMergedBeanDefinition(mbd, beanName, args);
// Guarantee initialization of beans that the current bean depends on.
// <8> 获取当前正在创建的 Bean 所依赖对象集合(`depends-on` 配置的依赖)
String[] dependsOn = mbd.getDependsOn();
if (dependsOn != null) {
for (String dep : dependsOn) {
// <8.1> 检测是否存在循环依赖,存在则抛出异常
if (isDependent(beanName, dep)) {
throw new BeanCreationException(mbd.getResourceDescription(), beanName,
"Circular depends-on relationship between '" + beanName + "' and '" + dep + "'");
}
// <8.2> 将 `beanName` 与 `dep` 之间依赖的关系进行缓存
registerDependentBean(dep, beanName);
try {
// <8.3> 先创建好依赖的 Bean(重新调用 `getBean(...)` 方法)
getBean(dep);
}
catch (NoSuchBeanDefinitionException ex) {
throw new BeanCreationException(mbd.getResourceDescription(), beanName,
"'" + beanName + "' depends on missing bean '" + dep + "'", ex);
}
}
}
// Create bean instance.
// <9> 开始创建 Bean,不同模式创建方式不同
if (mbd.isSingleton()) { // <9.1> 单例模式
/*
* <9.1.1> 创建 Bean,成功创建则进行缓存,并移除缓存的早期对象
* 创建过程实际调用的下面这个 `createBean(...)` 方法
*/
sharedInstance = getSingleton(beanName,
// ObjectFactory 实现类
() -> {
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.
// 如果创建过程出现异常,则显式地从缓存中删除当前 Bean 相关信息
// 在单例模式下为了解决循环依赖,创建过程会缓存早期对象,这里需要进行删除
destroySingleton(beanName);
throw ex;
}
});
// <9.1.2> 获取 Bean 的目标对象,`scopedInstance` 非 FactoryBean 类型直接返回
// 否则,调用 FactoryBean#getObject() 获取目标对象
bean = getObjectForBeanInstance(sharedInstance, name, beanName, mbd);
}
// <9.2> 原型模式
else if (mbd.isPrototype()) {
// It's a prototype -> create a new instance.
Object prototypeInstance = null;
try {
// <9.2.1> 将 `beanName` 标记为原型模式正在创建
beforePrototypeCreation(beanName);
// <9.2.2> **【核心】** 创建 Bean
prototypeInstance = createBean(beanName, mbd, args);
}
finally {
// <9.2.3> 将 `beanName` 标记为不在创建中,照应第 `9.2.1` 步
afterPrototypeCreation(beanName);
}
// <9.2.4> 获取 Bean 的目标对象,`scopedInstance` 非 FactoryBean 类型直接返回
// 否则,调用 FactoryBean#getObject() 获取目标对象
bean = getObjectForBeanInstance(prototypeInstance, name, beanName, mbd);
}
// <9.3> 其他模式
else {
// <9.3.1> 获取该模式的 Scope 对象 `scope`,不存在则抛出异常
String scopeName = mbd.getScope();
final Scope scope = this.scopes.get(scopeName);
if (scope == null) {
throw new IllegalStateException("No Scope registered for scope name '" + scopeName + "'");
}
try {
// <9.3.1> 从 `scope` 中获取 `beanName` 对应的对象(看你的具体实现),不存在则执行**原型模式**的四个步骤进行创建
Object scopedInstance = scope.get(beanName, () -> {
// 将 `beanName` 标记为原型模式正在创建
beforePrototypeCreation(beanName);
try {
// **【核心】** 创建 Bean
return createBean(beanName, mbd, args);
}
finally {
// 将 `beanName` 标记为不在创建中,照应上一步
afterPrototypeCreation(beanName);
}
});
// 获取 Bean 的目标对象,`scopedInstance` 非 FactoryBean 类型直接返回
// 否则,调用 FactoryBean#getObject() 获取目标对象
bean = getObjectForBeanInstance(scopedInstance, name, beanName, mbd);
}
catch (IllegalStateException ex) {
throw new BeanCreationException(beanName,
"Scope '" + scopeName + "' is not active for the current thread; consider " +
"defining a scoped proxy for this bean if you intend to refer to it from a singleton",
ex);
}
}
}
catch (BeansException ex) {
cleanupAfterBeanCreationFailure(beanName);
throw ex;
}
}
// Check if required type matches the type of the actual bean instance.
// <10> 如果入参 `requiredType` 不为空,并且 Bean 不是该类型,则需要进行类型转换
if (requiredType != null && !requiredType.isInstance(bean)) {
try {
// <10.1> 通过类型转换机制,将 Bean 转换成 `requiredType` 类型
T convertedBean = getTypeConverter().convertIfNecessary(bean, requiredType);
// <10.2> 转换后的 Bean 为空则抛出异常
if (convertedBean == null) {
// 转换失败,抛出 BeanNotOfRequiredTypeException 异常
throw new BeanNotOfRequiredTypeException(name, requiredType, bean.getClass());
}
// <10.3> 返回类型转换后的 Bean 对象
return convertedBean;
}
catch (TypeMismatchException ex) {
if (logger.isTraceEnabled()) {
logger.trace("Failed to convert bean '" + name + "' to required type '" +
ClassUtils.getQualifiedName(requiredType) + "'", ex);
}
throw new BeanNotOfRequiredTypeException(name, requiredType, bean.getClass());
}
}
// <11> 返回获取到的 Bean
return (T) bean;
}
这个方法的处理过程有点长,如下:
获取
beanName
,因为入参name
可能是别名,也可能是 FactoryBean 类型 Bean 的名称(&
开头,需要去除),所以需要获取真实的beanName
先从缓存(仅缓存单例 Bean )中获取 Bean 对象,这里缓存指的是
3
个 Map;缓存中也可能是正在初始化的 Bean,可以避免循环依赖注入引起的问题若从缓存中获取到对应的 Bean,且
args
参数为空【同】调用
getObjectForBeanInstance(Object beanInstance, String name, String beanName, @Nullable RootBeanDefinition mbd)
方法获取 Bean 的目标对象,
scopedInstance
非 FactoryBean 类型直接返回,否则,调用 FactoryBean#getObject() 获取目标对象
缓存中没有对应的 Bean,则开启 Bean 的加载
如果非单例模式下的 Bean 正在创建,这里又开始创建,表明存在循环依赖,则直接抛出异常
如果从当前容器中没有找到对应的 BeanDefinition,则从父容器中加载(如果存在父容器)
- 获取
beanName
,因为可能是别名,则进行处理,和第1
步不同,不需要对&
进行处理,因为进入父容器重新依赖查找 - 若为 AbstractBeanFactory 类型,委托父容器的 doGetBean 方法进行处理;否则,就是非 Spring IoC 容器,根据参数调用相应的
getBean(...)
方法
- 获取
如果不是仅仅做类型检查,则表示需要创建 Bean,将
beanName
标记为已创建过,在后面的循环依赖检查中会使用到从容器中获取
beanName
对应的的 RootBeanDefinition(合并后),调用getMergedLocalBeanDefinition(String beanName)
方法获取当前正在创建的 Bean 所依赖对象集合(
depends-on
配置的依赖)- 检测是否存在循环依赖,存在则抛出异常
- 将
beanName
与dep
之间依赖的关系进行缓存 - 先创建好依赖的 Bean(重新调用
getBean(...)
方法)
开始创建 Bean,不同模式创建方式不同
单例模式
创建 Bean,成功创建则进行缓存,并移除缓存的早期对象,调用
getSingleton(String beanName, ObjectFactory<?> singletonFactory)
方法【核心】入参的 ObjectFactory 实现类就是调用的
AbstractAutowireCapableBeanFactory#createBean(String, RootBeanDefinition, Object[])
方法【同】 和上面的
3.1
相同操作
原型模式
- 将
beanName
标记为非单例模式正在创建 - 【核心】 创建 Bean,调用
AbstractAutowireCapableBeanFactory#createBean(String, RootBeanDefinition, Object[])
方法 - 将
beanName
标记为不在创建中,照应第9.2.1
步 - 【同】 和上面的
3.1
相同操作
- 将
其他模式
- 获取该模式的 Scope 对象
scope
,不存在则抛出异常 - 从
scope
中获取beanName
对应的对象(看你的具体实现),不存在则执行原型模式的四个步骤进行创建
- 获取该模式的 Scope 对象
如果入参
requiredType
不为空,并且 Bean 不是该类型,则需要进行类型转换- 通过类型转换机制,将 Bean 转换成
requiredType
类型 - 转换后的 Bean 为空则抛出异常
- 返回类型转换后的 Bean 对象
- 通过类型转换机制,将 Bean 转换成
返回获取到的 Bean
概括:
可以看到这个方法加载 Bean 的过程中,会先从缓存中获取单例模式的 Bean;
不管是从缓存中获取的还是新创建的,都会进行处理,如果是 FactoryBean 类型则调用其 getObject() 获取目标对象;
BeanFactory 可能有父容器,如果当前容器找不到 BeanDefinition 则会尝试让父容器创建;
创建 Bean 的任务交由 AbstractAutowireCapableBeanFactory 去完成;
如果获取到的 Bean 不是我们想要类型,会通过类型转换机制转换成目标类型
接下来依次分析上述过程的相关步骤(doGetBean(...)
)
1. 获取 beanName
对应代码段:
// AbstractBeanFactory.java
final String beanName = transformedBeanName(name);
因为入参 name
可能是别名,也可能是 FactoryBean 类型 Bean 的名称(&
开头,需要去除),所以需要进行一番转换,如下:
// AbstractBeanFactory.java
protected String transformedBeanName(String name) {
return canonicalName(BeanFactoryUtils.transformedBeanName(name));
}
// BeanFactoryUtils.java
public static String transformedBeanName(String name) {
Assert.notNull(name, "'name' must not be null");
if (!name.startsWith(BeanFactory.FACTORY_BEAN_PREFIX)) {
return name;
}
// 获取 name 对应的 beanName,
// 不为 null 则返回 `transformedBeanNameCache` 缓存中对应的 beanName,
// 为 null 则对 name 进行处理,将前缀 '&' 去除,直至没有 '&',然后放入 `transformedBeanNameCache` 缓存中,并返回处理后的 beanName
return transformedBeanNameCache.computeIfAbsent(name, beanName -> {
do {
beanName = beanName.substring(BeanFactory.FACTORY_BEAN_PREFIX.length());
}
while (beanName.startsWith(BeanFactory.FACTORY_BEAN_PREFIX));
return beanName;
});
}
// SimpleAliasRegistry.java
public String canonicalName(String name) {
String canonicalName = name;
// Handle aliasing...
String resolvedName;
// 循环,从 aliasMap 中,获取到最终的 beanName
do {
resolvedName = this.aliasMap.get(canonicalName);
if (resolvedName != null) {
canonicalName = resolvedName;
}
}
while (resolvedName != null);
return canonicalName;
}
过程并不复杂,先将前缀 &
去除(如果存在),如果是别名则获取对应的 beanName
定义了一个 FactoryBean 类型的 Bean,名称为
user
,通过user
获取 Bean,获取到的是 FactoryBean#getObject() 返回的对象(只会被调用一次)通过
&user
获取 Bean,获取到的是 FactoryBean 本身这个对象
2. 从缓存中获取单例 Bean
对应代码段:
// AbstractBeanFactory#doGetBean(...) 方法
Object sharedInstance = getSingleton(beanName);
单例模式的 Bean 被创建后会缓存,为了避免循环依赖注入,在创建过程会临时缓存正在创建的 Bean(早期 Bean),在后续文章会讲到,从缓存中获取对象过程如下:
// DefaultSingletonBeanRegistry.java
public Object getSingleton(String beanName) {
return getSingleton(beanName, true);
}
protected Object getSingleton(String beanName, boolean allowEarlyReference) {
// <1> **【一级 Map】**从单例缓存 `singletonObjects` 中获取 beanName 对应的 Bean
Object singletonObject = this.singletonObjects.get(beanName);
// <2> 如果**一级 Map**中不存在,且当前 beanName 正在创建
if (singletonObject == null && isSingletonCurrentlyInCreation(beanName)) {
// <2.1> 对 `singletonObjects` 加锁
synchronized (this.singletonObjects) {
// <2.2> **【二级 Map】**从 `earlySingletonObjects` 集合中获取,里面会保存从 **三级 Map** 获取到的正在初始化的 Bean
singletonObject = this.earlySingletonObjects.get(beanName);
// <2.3> 如果**二级 Map** 中不存在,且允许提前创建
if (singletonObject == null && allowEarlyReference) {
// <2.3.1> **【三级 Map】**从 `singletonFactories` 中获取对应的 ObjectFactory 实现类
ObjectFactory<?> singletonFactory = this.singletonFactories.get(beanName);
// 如果从**三级 Map** 中存在对应的对象,则进行下面的处理
if (singletonFactory != null) {
// <2.3.2> 调用 ObjectFactory#getOject() 方法,获取目标 Bean 对象(早期半成品)
singletonObject = singletonFactory.getObject();
// <2.3.3> 将目标对象放入**二级 Map**
this.earlySingletonObjects.put(beanName, singletonObject);
// <2.3.4> 从**三级 Map**移除 `beanName`
this.singletonFactories.remove(beanName);
}
}
}
}
// <3> 返回从缓存中获取的对象
return singletonObject;
}
过程如下:
- 【一级 Map】从单例缓存
singletonObjects
中获取 beanName 对应的 Bean - 如果一级 Map中不存在,且当前 beanName 正在创建
- 对
singletonObjects
加锁 - 【二级 Map】从
earlySingletonObjects
集合中获取,里面会保存从 三级 Map 获取到的正在初始化的 Bean - 如果二级 Map 中不存在,且允许提前创建
- 【三级 Map】从
singletonFactories
中获取对应的 ObjectFactory 实现类,如果从三级 Map 中存在对应的对象,则进行下面的处理 - 调用 ObjectFactory#getOject() 方法,获取目标 Bean 对象(早期半成品)
- 将目标对象放入二级 Map
- 从三级 Map移除 beanName
- 【三级 Map】从
- 对
- 返回从缓存中获取的对象
这个过程对应《深入了解 Spring IoC(面试题)》中的BeanFactory 是如何处理循环依赖问题
3. FactoryBean 的处理
一般情况下,Spring 通过反射机制利用 Bean 的 beanClass 属性指定实现类来实例化 Bean。某些情况下,Bean 的实例化过程比较复杂,如果按照传统的方式,则需要提供大量的配置信息,配置方式的灵活性有限,这时采用编码的方式可能会得到一个简单的方案。Spring 为此提供了一个 FactoryBean 的工厂 Bean 接口,用户可以通过实现该接口定制实例化 Bean 的逻辑。
FactoryBean 接口对于 Spring 框架本身也非常重要,其内部就提供了大量 FactoryBean 的实现。它们隐藏了实例化过程中一些复杂细节,给上层应用带来了便利。
对应代码段:
// AbstractBeanFactory#doGetBean(...) 方法
bean = getObjectForBeanInstance(sharedInstance, name, beanName, mbd);
不管是从缓存中获取的还是新创建的,都会调用这个方法进行处理,如果是 FactoryBean 类型则调用其 getObject() 获取目标对象
getObjectForBeanInstance 方法
// AbstractBeanFactory.java
protected Object getObjectForBeanInstance( Object beanInstance, String name, String beanName,
@Nullable RootBeanDefinition mbd) {
// Don't let calling code try to dereference the factory if the bean isn't a factory.
// <1> 若 `name` 以 `&` 开头,说明想要获取 FactoryBean,则校验其**正确性**
if (BeanFactoryUtils.isFactoryDereference(name)) {
// <1.1> 如果是 NullBean 空对象,则直接返回
if (beanInstance instanceof NullBean) {
return beanInstance;
}
// <1.2> 如果不是 FactoryBean 类型,则抛出异常
if (!(beanInstance instanceof FactoryBean)) {
throw new BeanIsNotAFactoryException(beanName, beanInstance.getClass());
}
}
// Now we have the bean instance, which may be a normal bean or a FactoryBean.
// If it's a FactoryBean, we use it to create a bean instance, unless the caller actually wants a reference to the factory.
// 到这里我们就有了一个 Bean,可能是一个正常的 Bean,也可能是一个 FactoryBean
// 如果是 FactoryBean,则需要通过其 getObject() 方法获取目标对象
// <2> 如果 `beanInstance` 不是 FactoryBean 类型,不需要再处理则直接返回
// 或者(表示是 FactoryBean 类型) `name` 以 `&` 开头,表示你想要获取实际 FactoryBean 对象,则直接返回
// 还不符合条件的话,表示是 FactoryBean,需要获取 getObject() 返回目标对象
if (!(beanInstance instanceof FactoryBean) || BeanFactoryUtils.isFactoryDereference(name)) {
return beanInstance;
}
Object object = null;
// <3> 如果入参没有传 BeanDefinition,则从 `factoryBeanObjectCache` 缓存中获取对应的 Bean 对象
// 入参传了 BeanDefinition 表示这个 Bean 是刚创建的,不走缓存,需要调用其 getObject() 方法获取目标对象
// `factoryBeanObjectCache`:FactoryBean#getObject() 调用一次后返回的目标对象缓存在这里
if (mbd == null) {
object = getCachedObjectForFactoryBean(beanName);
}
// <4> 若第 `3` 步获取的对象为空,则需要调用 FactoryBean#getObject() 获得对象
if (object == null) {
// Return bean instance from factory.
// <4.1> 将 `beanInstance` 转换成 FactoryBean 类型
FactoryBean<?> factory = (FactoryBean<?>) beanInstance;
// Caches object obtained from FactoryBean if it is a singleton.
// <4.2> 如果入参没有传 BeanDefinition 并且当前容器存在对应的 BeanDefinition
if (mbd == null && containsBeanDefinition(beanName)) {
// 获取对应的 RootBeanDefinition(合并后)
mbd = getMergedLocalBeanDefinition(beanName);
}
// 是否是用户定义的(不是 Spring 创建解析出来的)
boolean synthetic = (mbd != null && mbd.isSynthetic());
// <4.3> **【核心】**通过 FactoryBean 获得目标对象,单例模式会缓存在 `factoryBeanObjectCache` 中
object = getObjectFromFactoryBean(factory, beanName, !synthetic);
}
return object;
}
过程如下:
若
name
以&
开头,说明想要获取 FactoryBean,则校验其正确性- 如果是 NullBean 空对象,则直接返回
- 如果不是 FactoryBean 类型,则抛出异常
如果
beanInstance
不是 FactoryBean 类型,不需要再处理则直接返回;或者(表示是 FactoryBean 类型)name
以&
开头,表示你想要获取实际 FactoryBean 对象,则直接返回;还不符合条件的话,表示是 FactoryBean,需要获取 getObject() 返回目标对象,往下处理如果入参没有传 BeanDefinition,则从
factoryBeanObjectCache
缓存中获取对应的 Bean 对象,如下:// FactoryBeanRegistrySupport.java
protected Object getCachedObjectForFactoryBean(String beanName) {
return this.factoryBeanObjectCache.get(beanName);
}
factoryBeanObjectCache
:FactoryBean#getObject() 调用一次后返回的目标对象缓存在这里入参传了 BeanDefinition 表示这个 Bean 是刚创建的,不走缓存,需要调用其 getObject() 方法获取目标对象
若第
3
步获取的对象为空,则需要调用 FactoryBean#getObject() 获得对象- 将
beanInstance
转换成 FactoryBean 类型 - 如果入参没有传 BeanDefinition 并且当前容器存在对应的 BeanDefinition,则获取对应的 RootBeanDefinition(合并后)
- 【核心】通过 FactoryBean 获得目标对象,单例模式会缓存在
factoryBeanObjectCache
中,调用getObjectFromFactoryBean(FactoryBean<?>, String, boolean)
方法
- 将
getObjectFromFactoryBean 方法
getObjectFromFactoryBean(FactoryBean<?> factory, String beanName, boolean shouldPostProcess)
方法,获取 FactoryBean 的目标对象,方法如下:
// FactoryBeanRegistrySupport.java
protected Object getObjectFromFactoryBean(FactoryBean<?> factory, String beanName, boolean shouldPostProcess) {
// <1> `factory` 为单例模式,且单例 Bean 缓存中存在 `beanName` 对应的 FactoryBean 对象
if (factory.isSingleton() && containsSingleton(beanName)) {
synchronized (getSingletonMutex()) { // <1.1> 获取单例锁,保证安全
// <1.2> 从 `factoryBeanObjectCache` 缓存中获取 FactoryBean#getObject() 创建的目标对象
Object object = this.factoryBeanObjectCache.get(beanName);
if (object == null) {
// <1.3> 则根据 `factory` 获取目标对象,调用 FactoryBean#getObject() 方法
object = doGetObjectFromFactoryBean(factory, beanName);
// Only post-process and store if not put there already during getObject() call above
// (e.g. because of circular reference processing triggered by custom getBean calls)
// <1.4> 这里再进行一次校验,看是否在缓存中存在 FactoryBean 创建的目标对象,如果有则优先从缓存中获取
// 保证 FactoryBean#getObject() 只能被调用一次
// 没有的话,则对刚获取到的目标对象进行接下来的处理
Object alreadyThere = this.factoryBeanObjectCache.get(beanName);
if (alreadyThere != null) {
object = alreadyThere;
} else {
// <1.5> 是否需要后续处理,这个 FactoryBean 的前身 BeanDefinition 是否由 Spring 解析出来的,通常情况下都是
if (shouldPostProcess) {
// <1.5.1> 若该 FactoryBean 处于创建中,则直接返回这个目标对象,不进行接下来的处理过程
if (isSingletonCurrentlyInCreation(beanName)) {
// Temporarily return non-post-processed object, not storing it yet..
return object;
}
// <1.5.2> 前置处理,将 `beanName` 标志为正在创建
beforeSingletonCreation(beanName);
try {
// <1.5.3> 对通过 FactoryBean 获取的目标对象进行后置处理
// 遍历所有的 BeanPostProcessor 的 postProcessAfterInitialization 方法(初始化的处理)
object = postProcessObjectFromFactoryBean(object, beanName);
}
catch (Throwable ex) {
throw new BeanCreationException(beanName,
"Post-processing of FactoryBean's singleton object failed", ex);
}
finally {
// <1.5.4> 后置处理,将 `beanName` 标志为不在创建中
afterSingletonCreation(beanName);
}
}
// <1.6> 如果缓存中存在 `beanName` 对应的 FactoryBean 对象
// 上面不是判断了吗?也可能在上面的处理过程会有所变化,所以这里在做一层判断
// 目的:缓存 FactoryBean 创建的目标对象,则需要保证 FactoryBean 本身这个对象存在缓存中
if (containsSingleton(beanName)) {
// <1.6.1> 将这个 FactoryBean 创建的目标对象保存至 `factoryBeanObjectCache`
this.factoryBeanObjectCache.put(beanName, object);
}
}
}
// <1.7> 返回 FactoryBean 创建的目标对象
return object;
}
}
// <2> `factory` 非单例模式,或单例 Bean 缓存中不存在 `beanName` 对应的 FactoryBean 对象
else {
// <2.1> 则根据 `factory` 获取目标对象,调用 FactoryBean#getObject() 方法
Object object = doGetObjectFromFactoryBean(factory, beanName);
// <2.2> 是否需要后续处理,这个 FactoryBean 的前身 BeanDefinition 是否由 Spring 解析出来的,通常情况下都是
if (shouldPostProcess) {
try {
// <2.2.1> 对通过 FactoryBean 获取的目标对象进行后置处理
// 遍历所有的 BeanPostProcessor 的 postProcessAfterInitialization 方法(初始化的处理)
object = postProcessObjectFromFactoryBean(object, beanName);
}
catch (Throwable ex) {
throw new BeanCreationException(beanName, "Post-processing of FactoryBean's object failed", ex);
}
}
// <2.3> 返回 FactoryBean 创建的目标对象,非单例模式不会进行缓存
return object;
}
}
过程如下:
factory
为单例模式,且单例 Bean 缓存中存在beanName
对应的 FactoryBean 对象获取单例锁,保证安全
从
factoryBeanObjectCache
缓存中获取 FactoryBean#getObject() 创建的目标对象则根据
factory
获取目标对象,调用 FactoryBean#getObject() 方法(反射机制)这里再进行一次校验(第
1.2
已经判断过),看是否在缓存中存在 FactoryBean 创建的目标对象,如果有则优先从缓存中获取,保证 FactoryBean#getObject() 只能被调用一次;没有的话,则对刚获取到的目标对象进行接下来的处理是否需要后续处理,这个 FactoryBean 的 BeanDefinition 是否由 Spring 解析出来的,通常情况下都是
若该 FactoryBean 处于创建中,则直接返回这个目标对象,不进行接下来的处理过程
前置处理,将
beanName
标志为正在创建对通过 FactoryBean 获取的目标对象进行后置处理,遍历所有的 BeanPostProcessor 的 postProcessAfterInitialization 方法(初始化的处理)
后置处理,将
beanName
标志为不在创建中如果缓存中存在
beanName
对应的 FactoryBean 对象,上面不是判断了吗(第1
步判断过)?也可能在上面的处理过程会有所变化,所以这里在做一层判断,目的:缓存 FactoryBean 创建的目标对象,则需要保证 FactoryBean 本身这个对象存在缓存中
- 将这个 FactoryBean 创建的目标对象保存至
factoryBeanObjectCache
- 将这个 FactoryBean 创建的目标对象保存至
返回 FactoryBean 创建的目标对象
factory
非单例模式,或单例 Bean 缓存中不存在beanName
对应的 FactoryBean 对象- 则根据
factory
获取目标对象,调用 FactoryBean#getObject() 方法(反射机制) - 是否需要后续处理,这个 FactoryBean 的 BeanDefinition 是否由 Spring 解析出来的,通常情况下都是
- 对通过 FactoryBean 获取的目标对象进行后置处理,遍历所有的 BeanPostProcessor 的 postProcessAfterInitialization 方法(初始化的处理)
- 返回 FactoryBean 创建的目标对象,非单例模式不会进行缓存
- 则根据
概括:调用 FactoryBean#getObject() 获取目标对象,单例模式会缓存起来;过程中 Sping 考虑到各种情况,例如保证单例模式下 FactoryBean#getObject() 只调用一次,是否需要进行后置处理。
4. 非单例模式依赖检查
对应代码段:
// AbstractBeanFactory#doGetBean(...) 方法
if (isPrototypeCurrentlyInCreation(beanName)) {
throw new BeanCurrentlyInCreationException(beanName);
}
protected boolean isPrototypeCurrentlyInCreation(String beanName) {
Object curVal = this.prototypesCurrentlyInCreation.get();
return (curVal != null && (curVal.equals(beanName) // 相等
|| (curVal instanceof Set && ((Set<?>) curVal).contains(beanName)))); // 包含
}
prototypesCurrentlyInCreation
中保存非单例模式下正在创建的 Bean 的名称,这里又重新创建,表示出现循环依赖,则直接抛出异常
Spring 对于非单例模式的 Bean 无法进行相关缓存,也就无法处理循环依赖的情况,选择了直接抛出异常
5. BeanFactory 层次性加载 Bean 策略
对应代码段:
// AbstractBeanFactory#doGetBean(...) 方法
BeanFactory parentBeanFactory = getParentBeanFactory();
// <5> 如果从当前容器中没有找到对应的 BeanDefinition,则从父容器中加载(如果存在父容器)
if (parentBeanFactory != null && !containsBeanDefinition(beanName)) {
// Not found -> check parent.
// <5.1> 获取 `beanName`,因为可能是别名,则进行处理
// 和第 `1` 步不同,不需要对 `&` 进行处理,因为进入父容器重新依赖查找
String nameToLookup = originalBeanName(name);
// <5.2> 若为 AbstractBeanFactory 类型,委托父容器的 doGetBean 方法进行处理
// 否则,就是非 Spring IoC 容器,根据参数调用相应的 `getBean(...)`方法
if (parentBeanFactory instanceof AbstractBeanFactory) {
return ((AbstractBeanFactory) parentBeanFactory).doGetBean(nameToLookup, requiredType, args, typeCheckOnly);
}
else if (args != null) {
return (T) parentBeanFactory.getBean(nameToLookup, args);
}
else if (requiredType != null) {
return parentBeanFactory.getBean(nameToLookup, requiredType);
}
else {
return (T) parentBeanFactory.getBean(nameToLookup);
}
}
如果当前 BeanFactory 没有对应的 BeanDefinition,也就无法创建 Bean,但是如果存在父 BeanFactory,则将接下来的操作交由父 BeanFactory,找不到会层层找上去,如果所有 BeanFactory 都找不到对应的 BeanDefinition 最终会抛出异常。
6. 将 beanName 标记为已创建
对应代码段:
// AbstractBeanFactory#doGetBean(...) 方法
// <6> 如果不是仅仅做类型检查,则表示需要创建 Bean,将 `beanName` 标记为已创建过
if (!typeCheckOnly) {
markBeanAsCreated(beanName);
}
如果不是仅仅做类型检查,则调用 markBeanAsCreated(String beanName)
方法,如下:
// AbstractBeanFactory.java
protected void markBeanAsCreated(String beanName) {
// 没有创建
if (!this.alreadyCreated.contains(beanName)) {
// 加上全局锁
synchronized (this.mergedBeanDefinitions) {
// 再次检查一次:DCL 双检查模式
if (!this.alreadyCreated.contains(beanName)) {
// Let the bean definition get re-merged now that we're actually creating
// the bean... just in case some of its metadata changed in the meantime.
// 从 mergedBeanDefinitions 中删除 beanName,并在下次访问时重新创建它
clearMergedBeanDefinition(beanName);
// 添加到已创建 bean 集合中
this.alreadyCreated.add(beanName);
}
}
}
}
将这个 beanName
保存在 alreadyCreated
集合中(SetFromMap),在后面的循环依赖检查中会使用到
7. 获取 RootBeanDefinition
对应代码段:
// AbstractBeanFactory#doGetBean(...) 方法
// <7> 从容器中获取 `beanName` 对应的的 RootBeanDefinition(合并后)
final RootBeanDefinition mbd = getMergedLocalBeanDefinition(beanName);
// 检查是否为抽象类
checkMergedBeanDefinition(mbd, beanName, args);
因为我们定义的 Bean 大多数都被 Spring 解析成 GenericBeanDefinition 类型,具有父子关系,则需要获取最终的 BeanDefinition;如果存在父子关系,则会进行一系列的合并,转换成 RootBeanDefinition 对象,调用 getMergedLocalBeanDefinition(String beanName)
方法,如下:
// AbstractBeanFactory.java
protected RootBeanDefinition getMergedLocalBeanDefinition(String beanName) throws BeansException {
// Quick check on the concurrent map first, with minimal locking.
// 从 `mergedBeanDefinitions` 缓存中获取合并后的 RootBeanDefinition,存在则直接返回
RootBeanDefinition mbd = this.mergedBeanDefinitions.get(beanName);
if (mbd != null) {
return mbd;
}
// 获取 BeanDefinition 并转换成,如果存在父子关系则进行合并
return getMergedBeanDefinition(beanName, getBeanDefinition(beanName));
}
protected RootBeanDefinition getMergedBeanDefinition(String beanName, BeanDefinition bd)
throws BeanDefinitionStoreException {
return getMergedBeanDefinition(beanName, bd, null);
}
protected RootBeanDefinition getMergedBeanDefinition(
String beanName, BeanDefinition bd, @Nullable BeanDefinition containingBd)
throws BeanDefinitionStoreException {
// 加锁
synchronized (this.mergedBeanDefinitions) {
RootBeanDefinition mbd = null;
// Check with full lock now in order to enforce the same merged instance.
if (containingBd == null) {
mbd = this.mergedBeanDefinitions.get(beanName);
}
if (mbd == null) {
// 如果没有父类则直接转换成 RootBeanDefinition 对象
if (bd.getParentName() == null) {
// Use copy of given root bean definition.
if (bd instanceof RootBeanDefinition) {
mbd = ((RootBeanDefinition) bd).cloneBeanDefinition();
}
else {
mbd = new RootBeanDefinition(bd);
}
}
// 有父类则进行合并
else {
// Child bean definition: needs to be merged with parent.
BeanDefinition pbd;
try {
// 获取父类的对应的 BeanDefinition 对象
String parentBeanName = transformedBeanName(bd.getParentName());
if (!beanName.equals(parentBeanName)) {
pbd = getMergedBeanDefinition(parentBeanName);
}
else {
BeanFactory parent = getParentBeanFactory();
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");
}
}
}
catch (NoSuchBeanDefinitionException ex) {
throw new BeanDefinitionStoreException(bd.getResourceDescription(), beanName,
"Could not resolve parent bean definition '" + bd.getParentName() + "'", ex);
}
// Deep copy with overridden values.
mbd = new RootBeanDefinition(pbd);
// 父子合并
mbd.overrideFrom(bd);
}
// Set default singleton scope, if not configured before.
if (!StringUtils.hasLength(mbd.getScope())) {
mbd.setScope(RootBeanDefinition.SCOPE_SINGLETON);
}
// A bean contained in a non-singleton bean cannot be a singleton itself.
// Let's correct this on the fly here, since this might be the result of
// parent-child merging for the outer bean, in which case the original inner bean
// definition will not have inherited the merged outer bean's singleton status.
if (containingBd != null && !containingBd.isSingleton() && mbd.isSingleton()) {
mbd.setScope(containingBd.getScope());
}
// Cache the merged bean definition for the time being
// (it might still get re-merged later on in order to pick up metadata changes)
if (containingBd == null && isCacheBeanMetadata()) {
// 放入缓存中
this.mergedBeanDefinitions.put(beanName, mbd);
}
}
return mbd;
}
}
过程大致如下:
- 从
mergedBeanDefinitions
缓存中获取合并后的 RootBeanDefinition,存在则直接返回,不存在则进行后面的操作 - 获取合并后的 RootBeanDefinition 对象,逻辑并不复杂,将一些属性进行合并;这里对于父 BeanDefinition 的获取也存在层次性查找策略;注意,如果一个单例 BeanDefinition 包含在非单例 BeanDefinition,那么会变成非单例 Bean
后续还会对合并后的 RootBeanDefinition 对象进行检查,如果是抽象的,则抛出异常
8. 依赖 Bean 的处理
对应代码段:
// AbstractBeanFactory#doGetBean(...) 方法
// Guarantee initialization of beans that the current bean depends on.
// <8> 获取当前正在创建的 Bean 所依赖对象集合(`depends-on` 配置的依赖)
String[] dependsOn = mbd.getDependsOn();
if (dependsOn != null) {
for (String dep : dependsOn) {
// <8.1> 检测是否存在循环依赖,存在则抛出异常
if (isDependent(beanName, dep)) {
throw new BeanCreationException(mbd.getResourceDescription(), beanName,
"Circular depends-on relationship between '" + beanName + "' and '" + dep + "'");
}
// <8.2> 将 `beanName` 与 `dep` 之间依赖的关系进行缓存
registerDependentBean(dep, beanName);
try {
// <8.3> 先创建好依赖的 Bean(重新调用 `getBean(...)` 方法)
getBean(dep);
}
catch (NoSuchBeanDefinitionException ex) {
throw new BeanCreationException(mbd.getResourceDescription(), beanName,
"'" + beanName + "' depends on missing bean '" + dep + "'", ex);
}
}
}
每个 Bean 不一定是单独工作的,可以通过
depends-on
配置依赖的 Bean,其他 Bean 也可以依赖它对于依赖的 Bean,会优先加载,所以在 Spring 的加载顺序中,在初始化某个 Bean 的时候,首先会初始化这个 Bean 的依赖
isDependent 方法
在初始化依赖的 Bean 之前,会调用 isDependent(String beanName, String dependentBeanName)
方法,判断是否出现循环依赖,方法如下:
DefaultSingletonBeanRegistry.java
protected boolean isDependent(String beanName, String dependentBeanName) {
synchronized (this.dependentBeanMap) {
return isDependent(beanName, dependentBeanName, null);
}
}
private boolean isDependent(String beanName, String dependentBeanName, @Nullable Set<String> alreadySeen) {
// <1> `alreadySeen` 中已经检测过该 `beanName` 则直接返回 `false`
if (alreadySeen != null && alreadySeen.contains(beanName)) {
return false;
}
// <2> 获取最终的 `beanName`,因为可能是别名,需要进行相关处理
String canonicalName = canonicalName(beanName);
// <3> 从 `dependentBeanMap` 中获取依赖 `beanName` 的 Bean 集合
Set<String> dependentBeans = this.dependentBeanMap.get(canonicalName);
// <4> 没有 Bean 依赖该 `beanName`,也就不存在循环依赖,返回 `false`
if (dependentBeans == null) {
return false;
}
// <5> 依赖 `beanName` 的 Bean 们包含 `dependentBeanName`,表示出现循环依赖,返回 `true`
if (dependentBeans.contains(dependentBeanName)) {
// `beanName` 与 `dependentBeanName` 相互依赖
return true;
}
// <6> 对依赖该 `beanName` 的 Bean 们进行检查,看它们是否与 `dependentBeanName` 存在依赖,递归处理
for (String transitiveDependency : dependentBeans) {
if (alreadySeen == null) {
alreadySeen = new HashSet<>();
}
alreadySeen.add(beanName);
if (isDependent(transitiveDependency, dependentBeanName, alreadySeen)) {
return true;
}
}
return false;
}
过程大致如下:
alreadySeen
中已经检测过该beanName
则直接返回false
- 获取最终的
beanName
,因为可能是别名,需要进行相关处理 - 从
dependentBeanMap
中获取依赖beanName
的 Bean 集合 - 没有 Bean 依赖该
beanName
,也就不存在循环依赖,返回false
- 依赖
beanName
的 Bean 们包含dependentBeanName
,表示出现循环依赖,返回true
- 对依赖该
beanName
的 Bean 们进行检查,看它们是否与dependentBeanName
存在依赖,递归处理
判断是否出现循环依赖的过程有点绕,需要花点时间理解一下。例如:现在检查 A ->(依赖)B,看是否出现循环依赖,我获取到依赖 A 的所有 Bean,看 B 是否依赖这里面的 Bean,如果出现 A -> B -> C -> A,那就出现循环依赖了。如果出现循环依赖,则会抛出异常,所以我们说 Spring 处理了单例 Bean 的循环依赖注入比较好一点。
registerDependentBean 方法
将 beanName
与 dep
(beanName
的依赖)之间依赖的关系进行缓存,调用 registerDependentBean(String beanName, String dependentBeanName)
方法,如下:
DefaultSingletonBeanRegistry.java
public void registerDependentBean(String beanName, String dependentBeanName) {
String canonicalName = canonicalName(beanName);
// 对应关系:beanName -> 依赖 beanName 的集合
synchronized (this.dependentBeanMap) {
Set<String> dependentBeans = this.dependentBeanMap.computeIfAbsent(canonicalName,
k -> new LinkedHashSet<>(8));
if (!dependentBeans.add(dependentBeanName)) {
return;
}
}
// 对应关系:beanName - > beanName 的依赖的集合
synchronized (this.dependenciesForBeanMap) {
Set<String> dependenciesForBean = this.dependenciesForBeanMap.computeIfAbsent(dependentBeanName,
k -> new LinkedHashSet<>(8));
dependenciesForBean.add(canonicalName);
}
}
将两者的依赖关系保存起来,目的是在 isDependent
方法中判断是否出现循环依赖
getBean 方法
加载 beanName
依赖的 Bean,同样是调用 AbstractBeanFactory#getBean(String dep)
方法,也就是本文开头讲的这个方法
9. 不同作用域的 Bean 的创建
Spring 的作用域划分为三种:单例模式、原型模式、其他模式,会依次进行判断,然后进行创建,创建过程都是一样的,主要是存储范围不一样
- 单例模式:一个 BeanFactory 有且仅有一个实例
- 原型模式:每次依赖查找和依赖注入生成新 Bean 对象
- 其他模式,例如
request
作用域会将 Bean 存储在 ServletRequest 上下文中;session
作用域会将 Bean 存储在 HttpSession 中;application
作用域会将 Bean 存储在 ServletContext 中
单例模式
对应代码段:
// AbstractBeanFactory#doGetBean(...) 方法
if (mbd.isSingleton()) { // <9.1> 单例模式
/*
* <9.1.1> 创建 Bean,成功创建则进行缓存,并移除缓存的早期对象
* 创建过程实际调用的下面这个 `createBean(...)` 方法
*/
sharedInstance = getSingleton(beanName,
// ObjectFactory 实现类
() -> {
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.
// 如果创建过程出现异常,则显式地从缓存中删除当前 Bean 相关信息
// 在单例模式下为了解决循环依赖,创建过程会缓存早期对象,这里需要进行删除
destroySingleton(beanName);
throw ex;
}
});
// <9.1.2> 获取 Bean 的目标对象,`scopedInstance` 非 FactoryBean 类型直接返回
// 否则,调用 FactoryBean#getObject() 获取目标对象
bean = getObjectForBeanInstance(sharedInstance, name, beanName, mbd);
}
如果是单例模式,创建过程大致如下:
调用
DefaultSingletonBeanRegistry#getSingleton(String beanName, ObjectFactory<?> singletonFactory)
方法创建 Bean,成功创建则进行缓存,并移除缓存的早期对象,创建过程实际调用的下面这个
AbstractAutowireCapableBeanFactory#createBean(...)
方法FactoryBean 的处理,在前面 3. FactoryBean 的处理 中已经分析过
getSingleton 方法
DefaultSingletonBeanRegistry#getSingleton(String beanName, ObjectFactory<?> singletonFactory)
方法,单例模式下获取单例 Bean,如下:
// DefaultSingletonBeanRegistry.java
public Object getSingleton(String beanName, ObjectFactory<?> singletonFactory) {
Assert.notNull(beanName, "Bean name must not be null");
// 全局加锁
synchronized (this.singletonObjects) {
// <1> 从 `singletonObjects` 单例 Bean 的缓存中获取 Bean(再检查一遍),存在则直接返回,否则开始创建
Object singletonObject = this.singletonObjects.get(beanName);
if (singletonObject == null) {
if (this.singletonsCurrentlyInDestruction) {
throw new BeanCreationNotAllowedException(beanName,
"Singleton bean creation not allowed while singletons of this factory are in destruction " +
"(Do not request a bean from a BeanFactory in a destroy method implementation!)");
}
if (logger.isDebugEnabled()) {
logger.debug("Creating shared instance of singleton bean '" + beanName + "'");
}
// <2> 将 `beanName` 标记为单例模式正在创建
beforeSingletonCreation(beanName);
boolean newSingleton = false;
boolean recordSuppressedExceptions = (this.suppressedExceptions == null);
if (recordSuppressedExceptions) {
this.suppressedExceptions = new LinkedHashSet<>();
}
try {
/**
* <3> 创建 Bean,实际调用
* {@link AbstractAutowireCapableBeanFactory#createBean(String, RootBeanDefinition, Object[])} 方法
*/
singletonObject = singletonFactory.getObject();
newSingleton = true;
}
catch (IllegalStateException ex) {
// Has the singleton object implicitly appeared in the meantime ->
// if yes, proceed with it since the exception indicates that state.
singletonObject = this.singletonObjects.get(beanName);
if (singletonObject == null) {
throw ex;
}
}
catch (BeanCreationException ex) {
if (recordSuppressedExceptions) {
for (Exception suppressedException : this.suppressedExceptions) {
ex.addRelatedCause(suppressedException);
}
}
throw ex;
}
finally {
if (recordSuppressedExceptions) {
this.suppressedExceptions = null;
}
// <4> 将 `beanName` 标记为不在创建中,照应第 `2` 步
afterSingletonCreation(beanName);
}
// <5> 如果这里是新创建的单例模式 Bean,则在 `singletonObjects` 中进行缓存(无序),移除缓存的早期对象
// 并在 `registeredSingletons` 中保存 `beanName`,保证注册顺序
if (newSingleton) {
addSingleton(beanName, singletonObject);
}
}
return singletonObject;
}
}
过程大致如下:
- 从
singletonObjects
单例 Bean 的缓存中获取 Bean(再检查一遍),存在则直接返回,否则开始创建 - 将
beanName
标记为单例模式正在创建 - 【核心】创建 Bean,实际调用
AbstractAutowireCapableBeanFactory#createBean(...)
方法 - 将
beanName
标记为不在创建中,照应第2
步 - 如果这里是新创建的单例模式 Bean,则在
singletonObjects
中进行缓存(无序),移除缓存的早期对象,并在registeredSingletons
中保存beanName
,保证注册顺序
createBean 方法
AbstractAutowireCapableBeanFactory#createBean(String beanName, RootBeanDefinition mbd, @Nullable Object[] args)
方法,创建 Bean,整个过程大致如下:
- Bean 的实例化
- 属性赋值(包括依赖注入)
- Aware 接口回调
- 调用初始化方法
上面涉及到 Bean 生命周期的大部分阶段,将会在后续的文章中依次分析
原型模式
对应代码段:
// AbstractBeanFactory.java
// <9.2> 原型模式
else if (mbd.isPrototype()) {
// It's a prototype -> create a new instance.
Object prototypeInstance = null;
try {
// <9.2.1> 将 `beanName` 标记为**非单例模式**正在创建
beforePrototypeCreation(beanName);
// <9.2.2> **【核心】** 创建 Bean
prototypeInstance = createBean(beanName, mbd, args);
}
finally {
// <9.2.3> 将 `beanName` 标记为不在创建中,照应第 `9.2.1` 步
afterPrototypeCreation(beanName);
}
// <9.2.4> 获取 Bean 的目标对象,`scopedInstance` 非 FactoryBean 类型直接返回
// 否则,调用 FactoryBean#getObject() 获取目标对象
bean = getObjectForBeanInstance(prototypeInstance, name, beanName, mbd);
}
过程大致如下:
- 将
beanName
标记为非单例模式正在创建 - 【核心】创建 Bean 也是调用
AbstractAutowireCapableBeanFactory#createBean(...)
方法,这里没有缓存,每次加载 Bean 都会创建一个对象 - 将
beanName
标记为不在创建中,照应第1
步 - FactoryBean 的处理,在前面 3. FactoryBean 的处理 中已经分析过
其他模式
对应代码段:
// AbstractBeanFactory.java
// <9.3> 其他模式
else {
// <9.3.1> 获取该模式的 Scope 对象 `scope`,不存在则抛出异常
String scopeName = mbd.getScope();
final Scope scope = this.scopes.get(scopeName);
if (scope == null) {
throw new IllegalStateException("No Scope registered for scope name '" + scopeName + "'");
}
try {
// <9.3.2> 从 `scope` 中获取 `beanName` 对应的对象(看你的具体实现),不存在则执行**原型模式**的四个步骤进行创建
Object scopedInstance = scope.get(beanName, () -> {
// 将 `beanName` 标记为**非单例模式**式正在创建
beforePrototypeCreation(beanName);
try {
// **【核心】** 创建 Bean
return createBean(beanName, mbd, args);
}
finally {
// 将 `beanName` 标记为不在创建中,照应上一步
afterPrototypeCreation(beanName);
}
});
// 获取 Bean 的目标对象,`scopedInstance` 非 FactoryBean 类型直接返回
// 否则,调用 FactoryBean#getObject() 获取目标对象
bean = getObjectForBeanInstance(scopedInstance, name, beanName, mbd);
}
catch (IllegalStateException ex) {
throw new BeanCreationException(beanName,
"Scope '" + scopeName + "' is not active for the current thread; consider " +
"defining a scoped proxy for this bean if you intend to refer to it from a singleton",
ex);
}
}
过程如下:
- 获取该模式的 Scope 对象
scope
,不存在则抛出异常 - 从
scope
中获取beanName
对应的对象(看你的具体实现),不存在则执行原型模式的四个步骤进行创建
想要自定义一个作用域,可以实现 org.springframework.beans.factory.config.Scope
接口,并往 Spring 应用上下文注册即可
10. 类型转换
对应代码段:
// AbstractBeanFactory#doGetBean(...) 方法
// <10> 如果入参 `requiredType` 不为空,并且 Bean 不是该类型,则需要进行类型转换
if (requiredType != null && !requiredType.isInstance(bean)) {
try {
// <10.1> 通过类型转换机制,将 Bean 转换成 `requiredType` 类型
T convertedBean = getTypeConverter().convertIfNecessary(bean, requiredType);
// <10.2> 转换后的 Bean 为空则抛出异常
if (convertedBean == null) {
throw new BeanNotOfRequiredTypeException(name, requiredType, bean.getClass());
}
// <10.3> 返回类型转换后的 Bean 对象
return convertedBean;
}
catch (TypeMismatchException ex) {
if (logger.isTraceEnabled()) {
logger.trace("Failed to convert bean '" + name + "' to required type '" +
ClassUtils.getQualifiedName(requiredType) + "'", ex);
}
throw new BeanNotOfRequiredTypeException(name, requiredType, bean.getClass());
}
}
如果入参 requiredType
不为空,并且 Bean 不是该类型,则需要进行类型转换,过程如下:
- 通过类型转换机制,将 Bean 转换成
requiredType
类型,对 Spring 的类型转换机制感兴趣的小伙伴可以自己研究,参考org.springframework.core.convert.support.DefaultConversionService
- 转换后的 Bean 为空则抛出异常
- 返回类型转换后的 Bean 对象
总结
本文对 BeanFactory 接口的体系结构进行了分析,得知 DefaultListableBeanFactory 是 BeanFactory 的最底层实现,也就是 Spring 的底层 IoC 容器。接着分析了 AbstractBeanFactory
的 getBean(...)
方法,当我们显示或者隐式地调用这个方法时,会触发 Bean 的加载。上面所有小节对 Bean 的加载过程进行了分析,我已经有序地在每个小节面前添加了序号,这些序号对应着加载过程中的顺序。
不同作用域的 Bean 的创建,底层都会调用 AbstractAutowireCapableBeanFactory
的 createBean(...)
方法进行创建,创建 Bean 的过程涉及到 Bean 生命周期的大部分阶段,例如实例化阶段、属性赋值阶段、Aware 接口回调阶段、初始化阶段都是在这个方法中完成的,整个创建过程将在后续的文章进行分析。
死磕Spring之IoC篇 - 开启 Bean 的加载的更多相关文章
- 死磕Spring之IoC篇 - 文章导读
该系列文章是本人在学习 Spring 的过程中总结下来的,里面涉及到相关源码,可能对读者不太友好,请结合我的源码注释 Spring 源码分析 GitHub 地址 进行阅读 Spring 版本:5.1. ...
- 死磕Spring之IoC篇 - Bean 的创建过程
该系列文章是本人在学习 Spring 的过程中总结下来的,里面涉及到相关源码,可能对读者不太友好,请结合我的源码注释 Spring 源码分析 GitHub 地址 进行阅读 Spring 版本:5.1. ...
- 【死磕 Spring】----- IOC 之解析 bean 标签:开启解析进程
原文出自:http://cmsblogs.com import 标签解析完毕了,再看 Spring 中最复杂也是最重要的标签 bean 标签的解析过程. 在方法 parseDefaultElement ...
- 死磕Spring之IoC篇 - @Bean 等注解的实现原理
该系列文章是本人在学习 Spring 的过程中总结下来的,里面涉及到相关源码,可能对读者不太友好,请结合我的源码注释 Spring 源码分析 GitHub 地址 进行阅读 Spring 版本:5.1. ...
- 死磕Spring之IoC篇 - BeanDefinition 的加载阶段(XML 文件)
该系列文章是本人在学习 Spring 的过程中总结下来的,里面涉及到相关源码,可能对读者不太友好,请结合我的源码注释 Spring 源码分析 GitHub 地址 进行阅读 Spring 版本:5.1. ...
- 死磕Spring之IoC篇 - BeanDefinition 的解析阶段(XML 文件)
该系列文章是本人在学习 Spring 的过程中总结下来的,里面涉及到相关源码,可能对读者不太友好,请结合我的源码注释 Spring 源码分析 GitHub 地址 进行阅读 Spring 版本:5.1. ...
- 死磕Spring之IoC篇 - Spring 应用上下文 ApplicationContext
该系列文章是本人在学习 Spring 的过程中总结下来的,里面涉及到相关源码,可能对读者不太友好,请结合我的源码注释 Spring 源码分析 GitHub 地址 进行阅读 Spring 版本:5.1. ...
- 死磕Spring之IoC篇 - 解析自定义标签(XML 文件)
该系列文章是本人在学习 Spring 的过程中总结下来的,里面涉及到相关源码,可能对读者不太友好,请结合我的源码注释 Spring 源码分析 GitHub 地址 进行阅读 Spring 版本:5.1. ...
- 死磕Spring之IoC篇 - BeanDefinition 的解析过程(面向注解)
该系列文章是本人在学习 Spring 的过程中总结下来的,里面涉及到相关源码,可能对读者不太友好,请结合我的源码注释 Spring 源码分析 GitHub 地址 进行阅读 Spring 版本:5.1. ...
随机推荐
- 【noi 2.6_9277】Logs Stacking堆木头(DP)
题意:给出在最底层的木头的个数,问有多少种堆放木头的方式.要求木头必须互相挨着在一起. 解法:f[i]表示最底层i个木头的堆放木头的方式.注意递推的思想!只需知道上一层堆放0~i-1个(即最底层堆放i ...
- 【noi 2.6_4982】踩方格(DP)
题意:一个无限大的方格矩阵,能向北.东.西三个方向走.问走N步共有多少种不同的方案. 解法: f[i]表示走 i 格的方案数. 状态转移方程推导如下--设l[i],r[i],u[i]分别为第 i 步向 ...
- Python 实现多线程的几种方式
threading.Thread 模块 继承实现: import threading import time class TestThread(threading.Thread): def __ini ...
- java笔试中创建String对象的思考
题目是这样的下面那些生成新的String对象() A . String s = new String(); B . String s = new String("A"); C. ...
- Leetcode(869)-重新排序得到 2 的幂
从正整数 N 开始,我们按任何顺序(包括原始顺序)将数字重新排序,注意其前导数字不能为零. 如果我们可以通过上述方式得到 2 的幂,返回 true:否则,返回 false. 示例 1: 输入:1 输出 ...
- 图像处理中Stride的理解
一行有 11 个像素(Width = 11), 对一个 32 位(每个像素 4 字节)的图像, Stride = 11 * 4 = 44. 但还有个字节对齐的问题, 譬如: 一行有 11 个像素(Wi ...
- springboot项目打war包
spring官方教程地址(包含打war包和打jar包的):https://docs.spring.io/spring-boot/docs/current/reference/htmlsingle/#b ...
- 九种姿势运行Mimikatz
https://www.freebuf.com/articles/web/176796.html
- ARM汇编---程序获取符号的物理地址
在移植u-boot的过程看到过u-boot在重定向时的实现,当时不知道怎么就觉得很好理解就把这个知识点没怎么深入的理解,最近在看华为的鸿蒙OS在Cortex-A平台上的实现过程时再次遇到一时间看不太懂 ...
- LeetCode Binary Search All In One
LeetCode Binary Search All In One Binary Search 二分查找算法 https://leetcode-cn.com/problems/binary-searc ...