【Spring源码核心篇-01】精通Spring的bean的生命周期

news/2024/11/1 22:43:23/

Spring源码核心篇整体栏目


内容链接地址
【一】Spring的bean的生命周期https://zhenghuisheng.blog.csdn.net/article/details/143441012

springbean的生命周期

  • 一,springbean的生命周期
    • 1,生成BeanDefinition
      • 1.1,初始化context和BeanFactory
      • 1.2,核心doScan方法
      • 1.3,获取BeanDefinition
      • 1.4,BeanDefinition属性赋值
      • 1.5,Bedefinition存入BeanDefinitionMap
    • 2,Bean工厂加载bean
      • 2.1,实例化全部的单例bean
      • 2.2,doGetBean
      • 2.3,createBean
        • 2.3.1,bean的前置处理器(实例化前)
        • 2.3.2,实例化bean
        • 2.3.3,bean的后置处理器(实例化后)
        • 2.3.4,属性填充
        • 2.3.5,初始化
      • 2.4,销毁

如需转载,请附上链接:https://blog.csdn.net/zhenghuishengq/article/details/143441012

springbean_10">一,springbean的生命周期

在本人前面的文章中,也写过一些关于spring源码的一些核心方法,主要是对spring中refresh中的九个方法进行的一些源码剖析,接下来的spring系列主要为核心篇,就是疏通spring的主干和脉络,通过spring的主干来了解spring的IOC和aop。源码依旧可以选择5.2的版本: https://github.com/spring-projects/spring-framework/tree/5.2.x

本文主要的内容就是了解spring的IOC中,bean的什么周期以及流程是怎么样的,结合bean的生命周期,了解一些spring中的一些扩展点机制,如bean的前置处理器,后置处理器,bean实例化前能做的事情,bean实例化后做的事情,bean初始化前做的事情,bean初始化后做的事情等

本人通过读取一下源码锁总结的流程图如下:

在这里插入图片描述

1,生成BeanDefinition

首先第一步是生成一个Bean定义,如何理解这个Bean定义,就是类似于我要做一个家具,在做之前需要找一个加工厂帮忙做好,但是加工厂并不知道要做成什么样子,因此就需要我们定义好一份图纸交给工厂,那么这个图纸就是所谓的BeanDefinition,然后这个工厂就是对应的spring容器

1.1,初始化context和BeanFactory

spring中,主要有注解的方式和xml启动上下文,这里直接选用注解的方式启动上下文

java">AnnotationConfigApplicationContext ac = new AnnotationConfigApplicationContext();

这个对象的继承关系如下,继承了 GenericApplicationContext 类,实现了 AnnotationConfigRegistry 接口

java">public class AnnotationConfigApplicationContext extends GenericApplicationContext implements AnnotationConfigRegistry {}

在初始化这个 AnnotationConfigApplicationContext 对象之后,可以发现这个对象是 BeanFactory 的一个实现类,也就是说在初始化这个context上下文之前,还会先初始化一个 BeanFactory 的工厂,并且BeanFactory工厂有的功能context上下文都有,context就是一个BeanFactory的一个具体实现

在这里插入图片描述

接下来以下面这个包路径的源码进行分析,如分析一段service包下面的所有注解是如何注册到spring中生产bean对象,AnnotationConfigApplicationContext 其他的几个构造方法可以先不看

java">public AnnotationConfigApplicationContext(String... basePackages) {this();		//注册一个读取器和扫描器,也可以先不看scan(basePackages);	//扫描包路径refresh();			//spring中最核心的方法,refresh方法
}

1.2,核心doScan方法

然后直接分析这个scan方法,一直往下点,可以看到一个 doScan 方法,就是扫描的核心方法,然后会循环的寻找包路径集合,最后回去找每一个路径下面的有 @Component 注解的bean,然后将bean生成一个 BeanDefinition

java">protected Set<BeanDefinitionHolder> doScan(String... basePackages) {Assert.notEmpty(basePackages, "At least one base package must be specified");//创建bean定义的holder对象用于保存扫描后生成的bean定义对象Set<BeanDefinitionHolder> beanDefinitions = new LinkedHashSet<>();//循环我们的包路径集合for (String basePackage : basePackages) {//找到候选的ComponentsSet<BeanDefinition> candidates = findCandidateComponents(basePackage);for (BeanDefinition candidate : candidates) {//拿到元数据解析器,可以获取类中所有信息ScopeMetadata scopeMetadata = this.scopeMetadataResolver.resolveScopeMetadata(candidate);candidate.setScope(scopeMetadata.getScopeName());//设置我们的beanNameString beanName = this.beanNameGenerator.generateBeanName(candidate, this.registry);//这是默认配置 autowire-candidateif (candidate instanceof AbstractBeanDefinition) {postProcessBeanDefinition((AbstractBeanDefinition) candidate, beanName);}//获取@Lazy @DependsOn等注解的数据设置到BeanDefinition中if (candidate instanceof AnnotatedBeanDefinition) {AnnotationConfigUtils.processCommonDefinitionAnnotations((AnnotatedBeanDefinition) candidate);}//把我们解析出来的组件bean定义注册到我们的IOC容器中(容器中没有才注册)if (checkCandidate(beanName, candidate)) {BeanDefinitionHolder definitionHolder = new BeanDefinitionHolder(candidate, beanName);definitionHolder =AnnotationConfigUtils.applyScopedProxyMode(scopeMetadata, definitionHolder, this.registry);beanDefinitions.add(definitionHolder);registerBeanDefinition(definitionHolder, this.registry);}}}return beanDefinitions;
}

1.3,获取BeanDefinition

可以直接查看这个 findCandidateComponents 方法时如何获取到Bean定义的,内部主要会通过一个 scanCandidateComponents 方法来具体的扫描这些带有@Component注解的主键,如下图所示

如一个com.zhs.service的包下面有一个OrderService的类:

  • 这个方法首先会获取到这个包路径为 com.zhs.service
  • 然后获取到该包下面的全部带有 .class 类文件,将这个OrderService类封装成一个Resource资源
  • 遍历每个资源,判断是否在includeFilters中或者excludeFilters中,Component在容器启动已经加入到includeFilters中,所以有这个注解的会生成一个BeanDefinition被选中加入到集合中

在这里插入图片描述

这里还有一个细节,就是在下面这行代码中,设置到这个Bean的ClassName还是这个类的名字,而不是一个对象,在后面实例化之后那么设置的就是一个Object的对象了,并且这个 beanClass 原本就是一个Object的对象,因为此时在容器启动时,目前还没有真正的bean对象被实例化

java">@Nullable
private volatile Object beanClass;	//原因是目前只扫描到了,但是并没有加载ScannedGenericBeanDefinition sbd = new ScannedGenericBeanDefinition(metadataReader);public ScannedGenericBeanDefinition(MetadataReader metadataReader) {this.metadata = metadataReader.getAnnotationMetadata();setBeanClassName(this.metadata.getClassName());
}

1.4,BeanDefinition属性赋值

在上面虽然获取到了BeanDefinition,但是这个bean定义里面只有名字,还需要给BeanDefinition设置一些基础属性,如是否懒加载,是否单例bean

在拿到 BeanDefinition 的set集合之后,会遍历这个set集合,为里面每一个bean定义进行属性赋值,首先是获取到每个bean定义的元数据解析器,可以获取到每个bean定义的所有属性,然后设置bean定义作用域

java">ScopeMetadata scopeMetadata = this.scopeMetadataResolver.resolveScopeMetadata(candidate);
candidate.setScope(scopeMetadata.getScopeName());

然后就是判断类是否懒加载,是否加了 @Dependson注解等,Dependson注解主要用于依赖关系,比如A上面加了一个依赖B的注解,那么在加载A实例前需要先加载B实例,这种方式造成的循环依赖解决不了,只能手动的避免

java">if (candidate instanceof AnnotatedBeanDefinition) {					AnnotationConfigUtils.processCommonDefinitionAnnotations((AnnotatedBeanDefinition) candidate);
}

在这里插入图片描述

1.5,Bedefinition存入BeanDefinitionMap

最后会先判断当前bean定义是否已经存在于容器中,如果不存在的话,把我们解析出来的组件bean定义注册到spring的IOC容器中

java">if (checkCandidate(beanName, candidate)) {BeanDefinitionHolder definitionHolder = new BeanDefinitionHolder(candidate, beanName);definitionHolder =AnnotationConfigUtils.applyScopedProxyMode(scopeMetadata, definitionHolder, this.registry);beanDefinitions.add(definitionHolder);registerBeanDefinition(definitionHolder, this.registry);
}

最后直接进入到这个 registerBeanDefinition 方法中,可以发现是直接通过一个工具类进行了注册

java">BeanDefinitionReaderUtils.registerBeanDefinition(definitionHolder, registry);

最后将这个BeanDefinition注册到BeanDefinitionMap

在这里插入图片描述

2,Bean工厂加载bean

上面说了beanDefinition是一张图纸,spring是一个加工厂,那么接下来就需要通过工厂将图纸生成对应的家具,就是需要通过spring将beanDefinitionMap中的全部beanDefinition生成对应的bean

2.1,实例化全部的单例bean

在通过scan扫描方法将全部的beanDefinition拿到之后,接下来的事情就是遍历全部的BeanDefinition,然后将BeanDefinition交给spring的bean工厂,直接来直接分析 refresh 中的初始化单例bean的方法

java">finishBeanFactoryInitialization(beanFactory);

在这个方法中,会有一个专门实例化单例bean的方法 preInstantiateSingletons

java">protected void finishBeanFactoryInitialization(ConfigurableListableBeanFactory beanFactory) {//实例化剩余的单实例beanbeanFactory.preInstantiateSingletons();
}

在这个实例化单例bean的方法中,会遍历全部扫描拿到的单例beanDefinition,做以下流程:

  • 先判断这个beanDefinition是否为抽象的、单例的或者是否为懒加载的
  • 再次判断这个beanDefinition是否为工厂bean,是的话则需要特殊处理转化成对应的bean
  • 最后调用这个getBean方法去创建对应的实例,有这个实例则直接获取,无则创建

在这里插入图片描述

2.2,doGetBean

接下来就是进入bean工厂创建bean的方法,在进入上面的getBean方法之后,里面可以看到这个真正去创建bean的方法 doGetBean 方法

java">@Override
public Object getBean(String name) throws BeansException {//真正的获取bean的逻辑return doGetBean(name, null, null, false);
}

如下图所示,其部分流程如下:

  • 首先第一步就是获取到这个bean的别名,如果有别名则获取到别名,没有则用当前bean的名字
  • 随后去单例池的缓存中获取对象,默认绝大多数的对象都是单例对象

在这里插入图片描述

首先刚进来这个单例池里面肯定是没有对象的,因为还未初始化放到单例池里面,因此看后面的else逻辑。下面这段代码的逻辑也比较简单,就是判断这个BeanDefinition是否存在于单前的BeanFactory中,如果不存在,那么就去父工厂的BeanFactory中去获取

java">BeanFactory parentBeanFactory = getParentBeanFactory();
//若存在父工厂,切当前的bean工厂不存在当前的bean定义,那么bean定义是存在于父beanFacotry中
if (parentBeanFactory != null && !containsBeanDefinition(beanName)) {//获取bean的原始名称String nameToLookup = originalBeanName(name);//若为 AbstractBeanFactory 类型,委托父类处理if (parentBeanFactory instanceof AbstractBeanFactory) {return ((AbstractBeanFactory) parentBeanFactory).doGetBean(nameToLookup, requiredType, args, typeCheckOnly);}else if (args != null) {//  委托给构造函数 getBean() 处理return (T) parentBeanFactory.getBean(nameToLookup, args);}else {// 没有 args,委托给标准的 getBean() 处理return parentBeanFactory.getBean(nameToLookup, requiredType);}
}

如果没有父BeanFactory的话,那么就会继续往下走,其流程如下

  • 首先会拿到合并的RootBeanDefinition,这个才是最终交给bean工厂加载的BeanDefinition
  • 随后就是会对这个合并的RootBeanDefinition进行检查,判断是否抽象的等
  • 随后会校验这个 dependsOn 注解,就是前面所讲到的依赖于谁的注解,如A依赖于B,那么在创建A之前则需要将B先创建出来,这个注解方式避免不了循环依赖,只能手动解决
java">final RootBeanDefinition mbd = getMergedLocalBeanDefinition(beanName);
//检查当前创建的bean定义是不是抽象的bean定义
checkMergedBeanDefinition(mbd, beanName, args);
//依赖bean的名称
String[] dependsOn = mbd.getDependsOn();if (dependsOn != null) {// <1> 若给定的依赖 bean 已经注册为依赖给定的 bean// 即循环依赖的情况,抛出 BeanCreationException 异常for (String dep : dependsOn) {//beanName是当前正在创建的bean,dep是正在创建的bean的依赖的bean的名称if (isDependent(beanName, dep)) {throw new BeanCreationException(mbd.getResourceDescription(), beanName,"Circular depends-on relationship between '" + beanName + "' and '" + dep + "'");}//保存的是依赖 beanName 之间的映射关系:依赖 beanName - > beanName 的集合registerDependentBean(dep, beanName);try {//获取depentceOn的beangetBean(dep);}catch (NoSuchBeanDefinitionException ex) {throw new BeanCreationException(mbd.getResourceDescription(), beanName,"'" + beanName + "' depends on missing bean '" + dep + "'", ex);}}
}

2.3,createBean

在对上面的那些东西进行校验完成之后,接下来就是真正的进入创建单例bean的方法,在单例方法中,首先会判断是否为单例bean,然后最终调用这个 createBean 方法进行bean的创建

java">//创建单例bean
if (mbd.isSingleton()) {//把beanName 和一个singletonFactory 并且传入一个回调对象用于回调sharedInstance = getSingleton(beanName, () -> {try {//进入创建bean的逻辑return createBean(beanName, mbd, args);}catch (BeansException ex) {//创建bean的过程中发生异常,需要销毁关于当前bean的所有信息destroySingleton(beanName);throw ex;}});bean = getObjectForBeanInstance(sharedInstance, name, beanName, mbd);
}
2.3.1,bean的前置处理器(实例化前)

接下来直接进入这个创建bean的主角 createBean 方法,也就是bean生命周期最重要的一部分,就是在这个方法里面,在这个方法里面,首先会在真正的doCreateBean创建bean之前,创建一个bean的前置处理器,aop的实现就是在这里去进行扫描所有的@AespectJ注解,然后扫描类内部的@Before,@after等注解,最后进行一个动态代理,这一步就是实例化前的操作

java">@Override
protected Object createBean(String beanName, RootBeanDefinition mbd, @Nullable Object[] args)throws BeanCreationException {try {//bean定义的前置处理器Object bean = resolveBeforeInstantiation(beanName, mbdToUse);if (bean != null) {return bean;}}   
}

在这个 resolveBeforeInstantiation中,可以在里面看到一下这段代码,将这个对应的切面解析并保存到缓存中

java">//bean的前置处理器
bean = applyBeanPostProcessorsBeforeInstantiation(targetType, beanName);
//bean的后置处理器
bean = applyBeanPostProcessorsAfterInitialization(bean, beanName);

在这里插入图片描述

2.3.2,实例化bean

在上面的getBean方法中继续往下走,可以发现一个真正的去创建实例bean的doCreateBean方法

java">try {/*** 该步骤是我们真正的创建我们的bean的实例对象的过程*/Object beanInstance = doCreateBean(beanName, mbdToUse, args);
}

方法如下图,首先会将这个Bean进行一个 BeanWrapper的包装,然后调用 createBeanInstance 进行bean的实例化,在进行实例化时,会对实例化的方式进行推断,如是否用构造方法、工厂方法等

java">instanceWrapper = createBeanInstance(beanName, mbd, args);

在这里插入图片描述

2.3.3,bean的后置处理器(实例化后)

在实例化之后,这里又会进行一个后置处理器的调用,这里会将一些 @AutoWired @Value 的注解进行预解析

java">synchronized (mbd.postProcessingLock) {if (!mbd.postProcessed) {try {//进行后置处理 @AutoWired @Value的注解的预解析applyMergedBeanDefinitionPostProcessors(mbd, beanType, beanName);}catch (Throwable ex) {throw new BeanCreationException(mbd.getResourceDescription(), beanName,"Post-processing of merged bean definition failed", ex);}mbd.postProcessed = true;}
}
2.3.4,属性填充

接下来就是进入属性填充的阶段,里面通过调用这个 populateBean 方法进行属性填充

java">//属性赋值 给我们的属性进行赋值(调用set方法进行赋值)
populateBean(beanName, mbd, instanceWrapper);

在属性填充的方法中,会通过这个InstantiationAwareBeanPostProcessor类判断是否有一个 postProcessAfterInstantiation 的后置处理器,和实例化前的前置处理器功能类似,这种接口都是spring留给我们开发人员去自定义扩展的一些接口,改功能为实例化后,属性注入前的一个扩展点

java">if (!mbd.isSynthetic() && hasInstantiationAwareBeanPostProcessors()) {//获取容器中的所有的BeanPostProcessorfor (BeanPostProcessor bp : getBeanPostProcessors()) {//判断我们的后置处理器是不是InstantiationAwareBeanPostProcessorif (bp instanceof InstantiationAwareBeanPostProcessor) {//进行强制转化InstantiationAwareBeanPostProcessor ibp = (InstantiationAwareBeanPostProcessor) bp;//若存在后置处理器给我们属性赋值了,那么返回false 可以来修改我们的开关变量,就不会走下面的逻辑了if (!ibp.postProcessAfterInstantiation(bw.getWrappedInstance(), beanName)) {// 返回值为是否继续填充 bean// postProcessAfterInstantiation:如果应该在 bean上面设置属性则返回 true,否则返回 false// 一般情况下,应该是返回true 。// 返回 false 的话,将会阻止在此 Bean 实例上调用任何后续的 InstantiationAwareBeanPostProcessor 实continueWithPropertyPopulation = false;break;}}}
}

下面这段代码就是依赖注入的功能,判断注入的类型是通过type类型还是通过name的类型输入属性

java">if (mbd.getResolvedAutowireMode() == AUTOWIRE_BY_NAME || mbd.getResolvedAutowireMode() == AUTOWIRE_BY_TYPE) {//把PropertyValues封装成为MutablePropertyValuesMutablePropertyValues newPvs = new MutablePropertyValues(pvs);//根据bean的属性名称注入if (mbd.getResolvedAutowireMode() == AUTOWIRE_BY_NAME) {autowireByName(beanName, mbd, bw, newPvs);}//根据bean的类型进行注入if (mbd.getResolvedAutowireMode() == AUTOWIRE_BY_TYPE) {autowireByType(beanName, mbd, bw, newPvs);}//把处理过的 属性覆盖原来的pvs = newPvs;
}

代码往下执行又可以看到一个InstantiationAwareBeanPostProcessor对象的 ,给开发人员一些扩展接口,用于给开发者在@Autoware等属性中提前进行初始赋值

在这里插入图片描述

2.3.5,初始化

最后一个步骤就是进行初始化,上面已经进行了对象的实例化,属性填充,那么最后一步就剩下初始化了。

java">//进行对象初始化操作(在这里可能生成代理对象)
exposedObject = initializeBean(beanName, exposedObject, mbd);

直接查看这个 initializeBean 方法,可以发现初始化方法中主要有四个步骤:

  • 一个是判断是否实现Aware接口的回调,比如是否实现 BeanNameAware、BeanFactoryAware 接口,还有一些环境的aware,以及Resource资源的aware,事件发布器的aware等
  • 初始化前会调用bean的后置处理器,用于加载一些 @PostConstruct 等注解
  • 然后就是进行调用初始化的方法,
  • 最后执行一个调用bean的后置处理器的一个方法,比如处理所有aop是否需要执行动态代理等

在这里插入图片描述

2.4,销毁

依旧是在这个doCreateBean方法的最后面,有一个销毁的方法 registerDisposableBeanIfNecessary

java">registerDisposableBeanIfNecessary(beanName, bean, mbd);

由于这一块用的相对较少,因此不做过多的分析

在这里插入图片描述


http://www.ppmy.cn/news/1543705.html

相关文章

YOLOv11改进策略【小目标改进】| 添加专用于小目标的检测层 附YOLOv1~YOLOv11的检测头变化详解

前言 在目标检测领域,小目标检测一直是一个具有挑战性的问题。YOLO系列算法以其高效快速的特点受到广泛关注,然而在面对小目标时,仍存在一些局限性。本文将介绍如何在YOLOv11中添加小目标检测层,以提高对小目标的检测能力。 专栏目录:YOLOv11改进目录一览 | 涉及卷积层、…

CSS3简介(一)

1、CSS3简介 CSS3&#xff08;层叠样式表3级&#xff09;是用于控制网页外观设计的一种样式表语言&#xff0c;它是CSS2的继承者&#xff0c;并且是目前最为先进的版本之一。CSS3为Web设计师提供了更多功能强大的工具来创建更加动态和美观的网站。 以下是一些CSS3的主要特点和新…

安达发|零部件APS车间排程系统销售预测的优点

2024制造业面临着前所未有的挑战与机遇。为了保持竞争力&#xff0c;企业必须确保其生产系统能够高效、灵活地运作。在这方面&#xff0c;采用高级计划与排程系统&#xff0c;特别是零部件APS车间排程系统的预测方法&#xff0c;已成为提升生产效率和响应能力的关键策略。这种系…

Apple iap2协议栈在蓝牙中的移植及MFi认证的实现

资料准备&#xff1a;iap2协议栈源码以及MFi Accessory spec规格书 一、iap2协议栈在蓝牙中的移植&#xff1a; 1&#xff0c;rfcomm注册iap2协议栈数据收发回调函数 iap2协议栈和hfp&#xff0c;spp一样都是基于rfcomm实现的&#xff0c;因此需要在rfcomm中单独注册一个数据…

Linux版更新流程

一.下载更新包 下载地址&#xff1a;https://www.nvisual.com/%e4%b8%8b%e8%bd%bd/ 二.更新包组成 更新包由三部分组成&#xff1a; 前端更新包&#xff1a;压缩的ZIP文件&#xff0c;例如&#xff1a;dist-2.2.26-20231227.zip (2.2.26是版本号 20231227是发布日期)后端更…

第J4周:DenseNet与ResNet结合探索

&#x1f368; 本文为&#x1f517;365天深度学习训练营 中的学习记录博客&#x1f356; 原作者&#xff1a;K同学啊 本次尝试根据DenseNet与ResNet的特征来构建一个新的模型结构&#xff0c;目前的思路&#xff1a;将ResNet的残差结构加入到DenseNet中&#xff0c;也就是说把D…

MATLAB实现变领域搜索算法(VNS)

MATLAB实现变领域搜索算法(VNS) 1.算法介绍 变邻域搜索算法&#xff08;Variable Neighborhood Search&#xff0c;VNS&#xff09;是一种改进型的局部搜索算法&#xff0c;旨在通过不断变化问题的邻域结构来寻找更好的解决方案。 邻域&#xff1a;指对当前解进行一个操作&a…

算法工程师重生之第四十一天(每日温度 下一个更大元素 I 下一个更大元素II)

参考文献 代码随想录 一、每日温度 给定一个整数数组 temperatures &#xff0c;表示每天的温度&#xff0c;返回一个数组 answer &#xff0c;其中 answer[i] 是指对于第 i 天&#xff0c;下一个更高温度出现在几天后。如果气温在这之后都不会升高&#xff0c;请在该…