传送:
前置知识点
假定你已或多或少知晓如下知识点(如果以前不知道,看完你就算知道了...)
- spring中有BeanFactory(容器)。
- Bean容器可以有多个,彼此之间从逻辑上组成链表(父子关系),且单向可见(子可见父)。
- spring中通过BeanFactoryPostProcessor解析配置类,扫描组件,注册BeanDefinition,类似于JVM中扫描加载类
- spring 根据BeanDefinition来创建Bean,类似于JVM中根据Class创建Object.
- BeanFactory中有几个缓存,存储BeanDefinition,单例bean等。
- 循环依赖处理方法论
对象创建 VS Bean创建
BeanDefinition vs Class:
spring有自己的一套管理对象的机制,比如是否单例,什么时候实例化,实例化后的自定义初始化等等;这些特性都是在JVM的Class之外的东西,要把这些个性化的东西存封装起来于是变有了BeanDefinition,Class信息只是其一个属性。
Bean vs Object
- Bean本身就是Object,new出来一个Object只是创建Bean的第一步;
- 实例化Object 到Bean创建完成之间,spring还规范了好几个步骤,这些步骤构成了Bean的生命周期(一部分)。
getBean的知识点
我们从不同的角度来拆解Bean创建的知识点,后边再从源码中将这些知识点串联起来,更便于理解源码。
- spring认为Bean的创建是自己的事情,因此spring对外提供的方法是getBean;createBean在getBean的方法内部。
- 对于单例Bean的情况下getBean内部有两个逻辑:
1.从缓存中拿,如果BeanFactory中有缓存,就直接返回。
2.缓存没有就创建,创建后放入BeanFactory缓存中,于是有了逻辑1;其创建过程中还会用到几个缓存,后边会提及。
另外对于prototype来说,每次都创建。 - 容器之间构成父子链路,getBean的时候优先调用父Factory中getBean,即先从祖宗Factory的getBean中去获取(创建)
- bean的创建需要其BeanDefinition,调用getBeanDefinition方法,根据bean名称从beanDefinitionMap的拿到BeanDefinition.
- FactoryBean很绕口的描述是:创建Bean的Bean;获取其自身需要在bean的名称前加上&符号。
- spring把Bean的创建分了几个步骤,
- 记录Bean开始创建状态(循环依赖的时候,避免重复创建)。
- 实例化对象
- 装配属性;依赖注入,依赖bean处理
- BeanPostProcessor,初始化的扩展点,这里是spring给使用者的扩展点,用户可以参与bean的创建过程,甚至替换对象
- 返回对象(单例的缓存到单例池)
- 循环依赖的处理只支持单例模式
理解记忆这些知识点,下边源码中的流程就基本都能理解了。
源码中的流程
- 获取实际的beanName,处理FactoryBean(带&号前缀的beanName)和别名换成原名。
- 从缓存中获取此beanName的bean
- 如果beanName的实例存在于缓存中
- prototype类型bean的循环依赖检测。
- 检查bean是否存在于父类工厂中,若存在,则走父类工厂的getBean流程。向上委托,保证容器中只会存在一个同名的bean。
- 标记Bean为已创建或即将创建。
- 获取BeanDefinition ;如果有父类,这里会递归合并父类的方法以及属性。并会用自己重写的方法覆盖其父类的方法。合并完成并检查这个bean的是否是抽象类。
- 依赖Bean处理 ;如果该bean上有注解@DependsOn,或者配置文件<bean depends-on="..."/>上配置有该属性,则需保证该bean的所有依赖需要先在容器内注册。
- 不同作用域的Bean实例化;分单例和原型以及其他scope类型来创建bean。
- 类型转换 ;检查beanName类型是否符合需要的类型,若不符合,尝试进行转换。
- 返回创建好的bean。
源码解读
AbstractBeanFactory#doGetBean
1. 获取实际的beanName
inal String beanName = transformedBeanName(name);
-
如果有&,去掉&;&是从Spring中取FactoryBean的时候,在bean名称前+&;更多FactoryBean的信息看FactoryBean是bean还是Factory?
-
别名换成原名;从Map<String, String> aliasMap 中获取原名
2. 从缓存中获取此beanName的bean
// Eagerly check singleton cache for manually registered singletons.
Object sharedInstance = getSingleton(beanName);
强力建议先看 吃透Spring的循环依赖 把这个函数的作用分析的很透彻。
3.如果beanName的实例存在于缓存中
if (sharedInstance != null && args == null) {
// 3.如果beanName的实例存在于缓存中
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 + "'");
}
}
// 3.1 返回beanName对应的实例对象(主要用于FactoryBean的特殊处理,普通Bean会直接返回sharedInstance本身)
bean = getObjectForBeanInstance(sharedInstance, name, beanName, null);
}
4. prototype类型bean的循环依赖检测。
强力建议先看 吃透Spring的循环依赖 把这个函数的作用就理解了。
spring规范了bean创建的流程可以从模板方法模式的角度来看率, BeanFactory接口中没有
AbstractBeanFactory#getBean(java.lang.String)
@Override
public Object getBean(String name) throws BeansException {
return doGetBean(name, null, null, false);
}
5. 从parentBeanFactory中获取Bean
// Check if bean definition exists in this factory.
BeanFactory parentBeanFactory = getParentBeanFactory(); // 获取父factory
// containsBeanDefinition(beanName) -> 判断该beanName的BeanDefinition是否在该factory中
if (parentBeanFactory != null && !containsBeanDefinition(beanName)) {
// 有父factory存在并且当前factory不包含该beanName,则尝试从父factory中加载bean
// Not found -> check parent.
String nameToLookup = originalBeanName(name); // 若有多个'&'值保留一个或者别名转换为原名
if (parentBeanFactory instanceof AbstractBeanFactory) {
// 递归调用父类 doGetBean 方法
return ((AbstractBeanFactory) parentBeanFactory).doGetBean(
nameToLookup, requiredType, args, typeCheckOnly);
}
else if (args != null) {
// // 用明确的 args 从 parentBeanFactory 中,获取 Bean 对象
// Delegation to parent with explicit args.
return (T) parentBeanFactory.getBean(nameToLookup, args);
}
else if (requiredType != null) {
// 用明确的 requiredType 从 parentBeanFactory 中,获取 Bean 对象
// No args -> delegate to standard getBean method.
return parentBeanFactory.getBean(nameToLookup, requiredType);
}
else {
// 直接使用 nameToLookup 从 parentBeanFactory 获取 Bean 对象
return (T) parentBeanFactory.getBean(nameToLookup);
}
}
父容器的场景其实在Springmvc的父容器是Spring容器,Servlet规范和Servlet容器 笔记的末尾中有说清楚。
从这个getBean的委托父容器的流程可以解释为什么子容器可以引用父容器中的Bean,而父容器不可以引用子容器中的Bean。
6. 标记Bean为已创建或即将创建
Set<String> alreadyCreated
存储bean名称;在set中表示bean已开始创建
// 如果不是仅做类型检查,而是创建bean,则需要标记该beanName为已经开启创建
if (!typeCheckOnly) {
markBeanAsCreated(beanName);
}
//具体实现
protected void markBeanAsCreated(String beanName) {
if (!this.alreadyCreated.contains(beanName)) {
synchronized (this.mergedBeanDefinitions) {
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.
clearMergedBeanDefinition(beanName);
//添加到一个set集合中
this.alreadyCreated.add(beanName);
}
}
}
}
7 获取BeanDefinition
//根据beanName重新获取MergedBeanDefinition(步骤6将MergedBeanDefinition删除了,这边获取一个新的)
//如果有父类,这里会递归合并父类的方法以及属性。并会用自己重写的方法覆盖其父类的方法。合并完成并
final RootBeanDefinition mbd = getMergedLocalBeanDefinition(beanName);
// 检查给定的合并的 BeanDefinition 是否是抽象类
checkMergedBeanDefinition(mbd, beanName, args);
下边描述MergedBeanDefinition的内容来自:https://blog.csdn.net/v123411739/article/details/87907784
MergedBeanDefinition:这个词其实不是一个官方词,但是很接近,该词主要是用来表示 “合并的 bean 定义”,因为每次都写 “合并的 bean 定义” 有点太绕口,因此我在之后的注释或解析中或统一使用 MergedBeanDefinition 来表示 “合并的 bean 定义”。
之所以称之为 “合并的”,是因为存在 “子定义” 和 “父定义” 的情况。对于一个 bean 定义来说,可能存在以下几种情况:
- 该 BeanDefinition 存在 “父定义”:首先使用 “父定义” 的参数构建一个 RootBeanDefinition,然后再使用该 BeanDefinition 的参数来进行覆盖。
- 该 BeanDefinition 不存在 “父定义”,并且该 BeanDefinition 的类型是 RootBeanDefinition:直接返回该 RootBeanDefinition 的一个克隆。
- 该 BeanDefinition 不存在 “父定义”,但是该 BeanDefinition 的类型不是 RootBeanDefinition:使用该 BeanDefinition 的参数构建一个 RootBeanDefinition。
之所以区分出2和3,是因为通常 BeanDefinition 在之前加载到 BeanFactory 中的时候,通常是被封装成 GenericBeanDefinition 或 ScannedGenericBeanDefinition,但是从这边之后 bean 的后续流程处理都是针对 RootBeanDefinition,因此在这边会统一将 BeanDefinition 转换成 RootBeanDefinition。
在我们日常使用的过程中,通常会是上面的第3种情况。如果我们使用 XML 配置来注册 bean,则该 bean 定义会被封装成:GenericBeanDefinition;如果我们使用注解的方式来注册 bean,也就是<context:component-scan /> + @Compoment,则该 bean 定义会被封装成 ScannedGenericBeanDefinition。
理论了解后,可以从源码看MergedBeanDefinition
8 依赖Bean处理
如果该bean上有注解@DependsOn,或者配置文件<bean depends-on="..."/>上配置有该属性,则需保证该bean的所有依赖需要先在容器内注册
// 8.拿到当前bean依赖的bean名称集合,在实例化自己之前,需要先实例化自己依赖的bean
String[] dependsOn = mbd.getDependsOn();
if (dependsOn != null) {
// 8.1 遍历当前bean依赖的bean名称集合
for (String dep : dependsOn) {
// 8.2 检查dep是否依赖于beanName,即检查是否存在循环依赖
if (isDependent(beanName, dep)) {
// 8.3 如果是循环依赖则抛异常
throw new BeanCreationException(mbd.getResourceDescription(), beanName,
"Circular depends-on relationship between '" + beanName + "' and '" + dep + "'");
}
// 8.4 将dep和beanName的依赖关系注册到缓存中
registerDependentBean(dep, beanName);
// 8.5 获取dep对应的bean实例,如果dep还没有创建bean实例,则创建dep的bean实例
getBean(dep);
}
}
9 不同作用域的Bean实例化
// 9.针对不同的scope进行bean的创建
if (mbd.isSingleton()) {
// 9.1 scope为singleton的bean创建(新建了一个ObjectFactory,并且重写了getObject方法)
sharedInstance = getSingleton(beanName, new ObjectFactory<Object>() {
@Override
public Object getObject() throws BeansException { //
try {
// 9.1.1 创建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.
destroySingleton(beanName);
throw ex;
}
}
});
// 9.1.2 返回beanName对应的实例对象
bean = getObjectForBeanInstance(sharedInstance, name, beanName, mbd);
} else if (mbd.isPrototype()) {
// 9.2 scope为prototype的bean创建
// It's a prototype -> create a new instance.
Object prototypeInstance = null;
try {
// 9.2.1 创建实例前的操作(将beanName保存到prototypesCurrentlyInCreation缓存中)
beforePrototypeCreation(beanName);
// 9.2.2 创建Bean实例
prototypeInstance = createBean(beanName, mbd, args);
} finally {
// 9.2.3 创建实例后的操作(将创建完的beanName从prototypesCurrentlyInCreation缓存中移除)
afterPrototypeCreation(beanName);
}
// 9.2.4 返回beanName对应的实例对象
bean = getObjectForBeanInstance(prototypeInstance, name, beanName, mbd);
} else {
// 9.3 其他scope的bean创建,可能是request之类的
// 9.3.1 根据scopeName,从缓存拿到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的bean创建(新建了一个ObjectFactory,并且重写了getObject方法)
Object scopedInstance = scope.get(beanName, new ObjectFactory<Object>() {
@Override
public Object getObject() throws BeansException {
// 9.3.3 创建实例前的操作(将beanName保存到prototypesCurrentlyInCreation缓存中)
beforePrototypeCreation(beanName);
try {
// 9.3.4 创建bean实例
return createBean(beanName, mbd, args);
} finally {
// 9.3.5 创建实例后的操作(将创建完的beanName从prototypesCurrentlyInCreation缓存中移除)
afterPrototypeCreation(beanName);
}
}
});
// 9.3.6 返回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);
}
10 类型转换
// 10.检查所需类型是否与实际的bean对象的类型匹配
if (requiredType != null && bean != null && !requiredType.isInstance(bean)) {
try {
// 10.1 类型不对,则尝试转换bean类型
return 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());
}
}
11 返回bean
// 11.返回创建出来的bean实例对象
return (T) bean;
感谢你们:
GetBean源码全面解读
Spring IoC:getBean 详解
Spring的bean定义 4 : 合并了的bean定义--MergedBeanDefinition
网友评论