死磕 Spring----- IOC 之加载 bean:总结
Posted chenssy
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了死磕 Spring----- IOC 之加载 bean:总结相关的知识,希望对你有一定的参考价值。
原文:https://www.topjava.cn/category/1391374860344758272 『chenssy』
在 【死磕 Spring】 Spring bean 解析篇深入分析了一个配置文件经历了哪些过程转变成了 BeanDefinition,但是这个 BeanDefinition 并不是我们真正想要的想要的 bean,因为它还仅仅只是承载了我们需要的目标 bean 的信息,从 BeanDefinition 到我们需要的目标还需要一个漫长的 bean 的初始化阶段,在 【死磕 Spring】 Spring bean 加载阶段已经详细分析了初始化 bean 的过程,所以这里做一个概括性的总结。
bean 的初始化节点由第一次调用 getBean()
(显式或者隐式)开启,所以我们从这个方法开始。
public Object getBean(String name) throws BeansException {
return doGetBean(name, null, null, false);
}
protected <T> T doGetBean(final String name, @Nullable final Class<T> requiredType,
@Nullable final Object[] args, boolean typeCheckOnly) throws BeansException {
// 获取 beanName,这里是一个转换动作,将 name 转换Wie beanName
final String beanName = transformedBeanName(name);
Object bean;
// 从缓存中或者实例工厂中获取 bean
// *** 这里会涉及到解决循环依赖 bean 的问题
Object sharedInstance = getSingleton(beanName);
if (sharedInstance != null && args == null) {
if (logger.isDebugEnabled()) {
if (isSingletonCurrentlyInCreation(beanName)) {
logger.debug("Returning eagerly cached instance of singleton bean '" + beanName +
"' that is not fully initialized yet - a consequence of a circular reference");
}
else {
logger.debug("Returning cached instance of singleton bean '" + beanName + "'");
}
}
bean = getObjectForBeanInstance(sharedInstance, name, beanName, null);
}
else {
// 因为 Spring 只解决单例模式下得循环依赖,在原型模式下如果存在循环依赖则会抛出异常
// **关于循环依赖后续会单独出文详细说明**
if (isPrototypeCurrentlyInCreation(beanName)) {
throw new BeanCurrentlyInCreationException(beanName);
}
// 如果容器中没有找到,则从父类容器中加载
BeanFactory parentBeanFactory = getParentBeanFactory();
if (parentBeanFactory != null && !containsBeanDefinition(beanName)) {
String nameToLookup = originalBeanName(name);
if (parentBeanFactory instanceof AbstractBeanFactory) {
return ((AbstractBeanFactory) parentBeanFactory).doGetBean(
nameToLookup, requiredType, args, typeCheckOnly);
}
else if (args != null) {
return (T) parentBeanFactory.getBean(nameToLookup, args);
}
else {
return parentBeanFactory.getBean(nameToLookup, requiredType);
}
}
// 如果不是仅仅做类型检查则是创建bean,这里需要记录
if (!typeCheckOnly) {
markBeanAsCreated(beanName);
}
try {
// 从容器中获取 beanName 相应的 GenericBeanDefinition,并将其转换为 RootBeanDefinition
final RootBeanDefinition mbd = getMergedLocalBeanDefinition(beanName);
// 检查给定的合并的 BeanDefinition
checkMergedBeanDefinition(mbd, beanName, args);
// 处理所依赖的 bean
String[] dependsOn = mbd.getDependsOn();
if (dependsOn != null) {
for (String dep : dependsOn) {
// 若给定的依赖 bean 已经注册为依赖给定的b ean
// 循环依赖的情况
if (isDependent(beanName, dep)) {
throw new BeanCreationException(mbd.getResourceDescription(), beanName,
"Circular depends-on relationship between '" + beanName + "' and '" + dep + "'");
}
// 缓存依赖调用
registerDependentBean(dep, beanName);
try {
getBean(dep);
}
catch (NoSuchBeanDefinitionException ex) {
throw new BeanCreationException(mbd.getResourceDescription(), beanName,
"'" + beanName + "' depends on missing bean '" + dep + "'", ex);
}
}
}
// bean 实例化
// 单例模式
if (mbd.isSingleton()) {
sharedInstance = getSingleton(beanName, () -> {
try {
return createBean(beanName, mbd, args);
}
catch (BeansException ex) {
// 显示从单利缓存中删除 bean 实例
// 因为单例模式下为了解决循环依赖,可能他已经存在了,所以销毁它
destroySingleton(beanName);
throw ex;
}
});
bean = getObjectForBeanInstance(sharedInstance, name, beanName, mbd);
}
// 原型模式
else if (mbd.isPrototype()) {
// It's a prototype -> create a new instance.
Object prototypeInstance = null;
try {
beforePrototypeCreation(beanName);
prototypeInstance = createBean(beanName, mbd, args);
}
finally {
afterPrototypeCreation(beanName);
}
bean = getObjectForBeanInstance(prototypeInstance, name, beanName, mbd);
}
else {
// 从指定的 scope 下创建 bean
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 {
Object scopedInstance = scope.get(beanName, () -> {
beforePrototypeCreation(beanName);
try {
return createBean(beanName, mbd, args);
}
finally {
afterPrototypeCreation(beanName);
}
});
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;
}
}
// 检查需要的类型是否符合 bean 的实际类型
if (requiredType != null && !requiredType.isInstance(bean)) {
try {
T convertedBean = getTypeConverter().convertIfNecessary(bean, requiredType);
if (convertedBean == null) {
throw new BeanNotOfRequiredTypeException(name, requiredType, bean.getClass());
}
return convertedBean;
}
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;
}
内部调用 doGetBean()
方法,doGetBean()
的代码量比较多,从这里就可以看出 bean 的加载过程是一个非常复杂的过程,会涉及到各种各样的情况处理。doGetBean()
可以分为以下几个过程。
- 转换 beanName。因为我们调用
getBean()
方法传入的 name 并不一定就是 beanName,可以传入 aliasName,FactoryBean,所以这里需要进行简单的转换过程。 - 尝试从缓存中加载单例 bean。
- bean 的实例化。
- 原型模式的依赖检查。因为 Spring 只会解决单例模式的循环依赖,对于原型模式的循环依赖都是直接抛出 BeanCurrentlyInCreationException 异常。
- 尝试从 parentBeanFactory 获取 bean 实例。如果
parentBeanFactory != null && !containsBeanDefinition(beanName)
则尝试从 parentBeanFactory 中获取 bean 实例对象,因为!containsBeanDefinition(beanName)
就意味着定义的 xml 文件中没有 beanName 相应的配置,这个时候就只能从 parentBeanFactory 中获取。 - 获取 RootBeanDefinition,并对其进行合并检查。从缓存中获取已经解析的 RootBeanDefinition,同时如果父类不为 null 的话,则会合并父类的属性。
- 依赖检查。某个 bean 依赖其他 bean ,则需要先加载依赖的 bean。
- 对不同的 scope 进行处理。
- 类型转换处理。如果传递的 requiredType 不为 null,则需要检测所得到 bean 的类型是否与该 requiredType 一致,如果不一致则尝试转换,当然也要能够转换成功,否则抛出 BeanNotOfRequiredTypeException 异常。
下面就以下几个方面进行阐述,说明 Spring bean 的加载过程。
- 从缓存中获取 bean
- 创建 bean 实例对象
- 从 bean 实例中获取对象
从缓存中获取 bean
Spring 中根据 scope 可以将 bean 分为以下几类:singleton、prototype 和 其他,这样分的原因在于 Spring 在对不同 scope 处理的时候是这么处理的。
- singleton:在 Spring 的 IoC 容器中只存在一个对象实例,所有该对象的引用都共享这个实例。Spring 容器只会创建该 bean 定义的唯一实例,这个实例会被保存到缓存中,并且对该bean的所有后续请求和引用都将返回该缓存中的对象实例。
- prototype:每次对该bean的请求都会创建一个新的实例
- 其他:其他包括 request、session、global session:
- request:每次 http 请求将会有各自的 bean 实例。
- session:在一个 http session 中,一个 bean 定义对应一个 bean 实例。
- global session:在一个全局的 http session 中,一个 bean 定义对应一个 bean 实例。
所以从缓存中获取的 bean 一定是 singleton bean,这也是 Spring 为何只解决 singleton bean 的循环依赖。调用 getSingleton()
从缓存中获取 singleton bean。
public Object getSingleton(String beanName) {
return getSingleton(beanName, true);
}
protected Object getSingleton(String beanName, boolean allowEarlyReference) {
Object singletonObject = this.singletonObjects.get(beanName);
if (singletonObject == null && isSingletonCurrentlyInCreation(beanName)) {
synchronized (this.singletonObjects) {
singletonObject = this.earlySingletonObjects.get(beanName);
if (singletonObject == null && allowEarlyReference) {
ObjectFactory<?> singletonFactory = this.singletonFactories.get(beanName);
if (singletonFactory != null) {
singletonObject = singletonFactory.getObject();
this.earlySingletonObjects.put(beanName, singletonObject);
this.singletonFactories.remove(beanName);
}
}
}
}
return singletonObject;
}
getSingleton()
就是从 singletonObjects、earlySingletonObjects、 singletonFactories 三个缓存中获取,这里也是 Spring 解决 bean 循环依赖的关键之处。详细内容请查看如下内容:
创建 bean 实例对象
如果缓存中没有,也没有 parentBeanFactory ,则会调用 createBean()
创建 bean 实例,该方法主要是在处理不同 scope 的 bean 的时候进行调用。
protected abstract Object createBean(String beanName, RootBeanDefinition mbd, @Nullable Object[] args)
throws BeanCreationException
该方法是定义在 AbstractBeanFactory 中的虚拟方法,其含义是根据给定的 BeanDefinition 和 args实例化一个 bean 对象,如果该 BeanDefinition 存在父类,则该 BeanDefinition 已经合并了父类的属性。所有 Bean 实例的创建都会委托给该方法实现。
方法接受三个参数:
- beanName:bean 的名字
- mbd:已经合并了父类属性的(如果有的话)BeanDefinition
- args:用于构造函数或者工厂方法创建 bean 实例对象的参数
该抽象方法的默认实现是在类 AbstractAutowireCapableBeanFactory 中实现,该方法其实只是做一些检查和验证工作,真正的初始化工作是由 doCreateBean()
实现,如下:
protected Object doCreateBean(final String beanName, final RootBeanDefinition mbd, final @Nullable Object[] args)
throws BeanCreationException {
// BeanWrapper是对Bean的包装,其接口中所定义的功能很简单包括设置获取被包装的对象,获取被包装bean的属性描述器
BeanWrapper instanceWrapper = null;
// 单例模型,则从未完成的 FactoryBean 缓存中删除
if (mbd.isSingleton()) {anceWrapper = this.factoryBeanInstanceCache.remove(beanName);
}
// 使用合适的实例化策略来创建新的实例:工厂方法、构造函数自动注入、简单初始化
if (instanceWrapper == null) {
instanceWrapper = createBeanInstance(beanName, mbd, args);
}
// 包装的实例对象
final Object bean = instanceWrapper.getWrappedInstance();
// 包装的实例对象的类型
Class<?> beanType = instanceWrapper.getWrappedClass();
if (beanType != NullBean.class) {
mbd.resolvedTargetType = beanType;
}
// 检测是否有后置处理
// 如果有后置处理,则允许后置处理修改 BeanDefinition
synchronized (mbd.postProcessingLock) {
if (!mbd.postProcessed) {
try {
// applyMergedBeanDefinitionPostProcessors
// 后置处理修改 BeanDefinition
applyMergedBeanDefinitionPostProcessors(mbd, beanType, beanName);
}
catch (Throwable ex) {
throw new BeanCreationException(mbd.getResourceDescription(), beanName,
"Post-processing of merged bean definition failed", ex);
}
mbd.postProcessed = true;
}
}
// 解决单例模式的循环依赖
// 单例模式 & 运行循环依赖&当前单例 bean 是否正在被创建
boolean earlySingletonExposure = (mbd.isSingleton() && this.allowCircularReferences &&
isSingletonCurrentlyInCreation(beanName));
if (earlySingletonExposure) {
if (logger.isDebugEnabled()) {
logger.debug("Eagerly caching bean '" + beanName +
"' to allow for resolving potential circular references");
}
// 提前将创建的 bean 实例加入到ectFactory 中
// 这里是为了后期避免循环依赖
addSingletonFactory(beanName, () -> getEarlyBeanReference(beanName, mbd, bean));
}
/*
* 开始初始化 bean 实例对象
*/
Object exposedObject = bean;
try {
// 对 bean 进行填充,将各个属性值注入,其中,可能存在依赖于其他 bean 的属性
// 则会递归初始依赖 bean
populateBean(beanName, mbd, instanceWrapper);
// 调用初始化方法
exposedObject = initializeBean(beanName, exposedObject, mbd);
}
catch (Throwable ex) {
if (ex instanceof BeanCreationException && beanName.equals(((BeanCreationException) ex).getBeanName())) {
throw (BeanCreationException) ex;
}
else {
throw new BeanCreationException(
mbd.getResourceDescription(), beanName, "Initialization of bean failed", ex);
}
}
/**
* 循环依赖处理
*/
if (earlySingletonExposure) {
// 获取 earlySingletonReference
Object earlySingletonReference = getSingleton(beanName, false);
// 只有在存在循环依赖的情况下,earlySingletonReference 才不会为空
if (earlySingletonReference != null) {
// 如果 exposedObject 没有在初始化方法中被改变,也就是没有被增强
if (exposedObject == bean) {
exposedObject = earlySingletonReference;
}
// 处理依赖
else if (!this.allowRawInjectionDespiteWrapping && hasDependentBean(beanName)) {
String[] dependentBeans = getDependentBeans(beanName);
Set<String> actualDependentBeans = new LinkedHashSet<>(dependentBeans.length);
for (String dependentBean : dependentBeans) {
if (!removeSingletonIfCreatedForTypeCheckOnly(dependentBean)) {
actualDependentBeans.add(dependentBean);
}
}
if (!actualDependentBeans.isEmpty()) {
throw new BeanCurrentlyInCreationException(beanName,
"Bean with name '" + beanName + "' has been injected into other beans [" +
StringUtils.collectionToCommaDelimitedString(actualDependentBeans) +
"] in its raw version as part of a circular reference, but has eventually been " +
"wrapped. This means that said other beans do not use the final version of the " +
"bean. This is often the result of over-eager type matching - consider using " +
"'getBeanNamesOfType' with the 'allowEagerInit' flag turned off, for example.");
}
}
}
}
try {
// 注册 bean
registerDisposableBeanIfNecessary(beanName, bean, mbd);
}
catch (BeanDefinitionValidationException ex) {
throw new BeanCreationException(
mbd.getResourceDescription(), beanName, "Invalid destruction signature", ex);
}
return exposedObject;
}
doCreateBean()
是创建 bean 实例的核心方法,它的整体思路是:
- 如果是单例模式,则清除 factoryBeanInstanceCache 缓存,同时
以上是关于死磕 Spring----- IOC 之加载 bean:总结的主要内容,如果未能解决你的问题,请参考以下文章
死磕 Spring----- IOC 之 深入分析 PropertyPlaceholderConfigurer
[死磕 Spring 7/43] --- IOC 之解析Bean:解析 import 标签
[死磕 Spring 3/43] --- IOC 之 加载 Bean
[死磕 Spring26/43] --- IOC 之加载 bean:总结