Spring 框架源码(六) Bean的生命周期全流程源码解析
Spring框架作为Java王国的地基,我觉得它包含了很多精妙的设计,例如Bean工厂设计、Bean的生命周期、tx、aop、web、mvc等,最核心基本的Bean设计是Spring 的框架的灵魂,本文就Bean的生命周期全流程做源码程度上的解析,欢迎各位大佬指点江山。
先上一张DefaultListableBeanFactory的UML图来来感受Spring 框架设计的强大,跟着DefaultListableBeanFactory去揭开Spring框架的核心面纱。
一、DefaultListableBeanFactory
DefaultListableBeanFactory掌管了Bean生命周期的大权,Bean的创建、初始化、销毁,添加BeanPostProcessor等功能,可以说是Spring框架最全的Bean工厂, 掌握DefaultListableBeanFactory 是非常有必要的。
1. 创建并注册BeanDefinition
我们可以使用DefaultListableBeanFactory 对象注册一个BeanDefition, 使用registerBeanDefinition()方法, 如果想要加入一个BeanPostProcessor, 可以使用addBeanPostProcessor()方法。
private DefaultListableBeanFactory createBeanByDefaultListableBeanFactory(final Class<?> beanClass) {DefaultListableBeanFactory beanFactory = new DefaultListableBeanFactory();RootBeanDefinition beanDefinition = new RootBeanDefinition(beanClass);beanDefinition.setInitMethodName("testMethod");beanDefinition.setDestroyMethodName("testDestroy");beanFactory.registerBeanDefinition("testBean", beanDefinition);//添加BeanPostProcessorbeanFactory.addBeanPostProcessor(new BeanPostProcessor() {@Overridepublic Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {//System.out.println("执行前..");return bean;}@Overridepublic Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {System.out.println("执行后..");return bean;}});return beanFactory;}public static class User {public void testMethod(){System.out.println("初始化..");}public void testDestroy(){System.out.println("销毁..");}}@Testpublic void testDefaultListableBeanFactory() {final Class<?> beanClass = User.class;DefaultListableBeanFactory beanFactory = createBeanByDefaultListableBeanFactory(beanClass);User user = beanFactory.getBean("testBean", User.class);System.out.println("user= " + user);}
打印结果:

从打印结果可以知道User这个Bean的三个方法的执行顺序:
postProcessBeforeIntialization()> init-method()>postProcessAfterInitialization()
为了进一步理解Bean的生命周期,下面我们继续看Aware、BeanPostProcessor、InitialzingBean接口的执行顺序。
二、Bean的生命周期
BeanNameAware、BeanFactoryAware、BeanClassLoaderAware
BeanNameAware、BeanFactoryAware、BeanClassLoaderAware接口分别是在初始化Bean之前调用的,我们可以利用BeanName、BeanFactory、ClassLoader去开发一些业务。
/*** 执行BeanNameAware、BeanClassLoaderAware、BeanFactoryAware的接口。* @param beanName* @param bean*/private void invokeAwareMethods(final String beanName, final Object bean) {if (bean instanceof Aware) {if (bean instanceof BeanNameAware) {((BeanNameAware) bean).setBeanName(beanName);}if (bean instanceof BeanClassLoaderAware) {ClassLoader bcl = getBeanClassLoader();if (bcl != null) {((BeanClassLoaderAware) bean).setBeanClassLoader(bcl);}}if (bean instanceof BeanFactoryAware) {((BeanFactoryAware) bean).setBeanFactory(AbstractAutowireCapableBeanFactory.this);}}}
BeanPostProcessor
BeanPostProcessor接口里有2个默认方法,分别为PostProcessBeforeInitialization和PostProcessAfterInitialization。
public interface BeanPostProcessor {/*** Apply this BeanPostProcessor to the given new bean instance <i>before</i> any bean* initialization callbacks (like InitializingBean's {@code afterPropertiesSet}* or a custom init-method). The bean will already be populated with property values.* The returned bean instance may be a wrapper around the original.* <p>The default implementation returns the given {@code bean} as-is.* @param bean the new bean instance* @param beanName the name of the bean* @return the bean instance to use, either the original or a wrapped one;* if {@code null}, no subsequent BeanPostProcessors will be invoked* @throws org.springframework.beans.BeansException in case of errors* @see org.springframework.beans.factory.InitializingBean#afterPropertiesSet*/@Nullabledefault Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {return bean;}/*** Apply this BeanPostProcessor to the given new bean instance <i>after</i> any bean* initialization callbacks (like InitializingBean's {@code afterPropertiesSet}* or a custom init-method). The bean will already be populated with property values.* The returned bean instance may be a wrapper around the original.* <p>In case of a FactoryBean, this callback will be invoked for both the FactoryBean* instance and the objects created by the FactoryBean (as of Spring 2.0). The* post-processor can decide whether to apply to either the FactoryBean or created* objects or both through corresponding {@code bean instanceof FactoryBean} checks.* <p>This callback will also be invoked after a short-circuiting triggered by a* {@link InstantiationAwareBeanPostProcessor#postProcessBeforeInstantiation} method,* in contrast to all other BeanPostProcessor callbacks.* <p>The default implementation returns the given {@code bean} as-is.* @param bean the new bean instance* @param beanName the name of the bean* @return the bean instance to use, either the original or a wrapped one;* if {@code null}, no subsequent BeanPostProcessors will be invoked* @throws org.springframework.beans.BeansException in case of errors* @see org.springframework.beans.factory.InitializingBean#afterPropertiesSet* @see org.springframework.beans.factory.FactoryBean*/@Nullabledefault Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {return bean;}}
InitializingBean
InitializingBean接口官方解释: 当所有的Bean属性被BeanFactory设置完后允许你用afterPropertieSet()方法做一次调。
/*** Interface to be implemented by beans that need to react once all their* properties have been set by a BeanFactory: for example, to perform custom* initialization, or merely to check that all mandatory properties have been set.** <p>An alternative to implementing InitializingBean is specifying a custom* init-method, for example in an XML bean definition.* For a list of all bean lifecycle methods, see the* {@link BeanFactory BeanFactory javadocs}.** @author Rod Johnson* @see BeanNameAware* @see BeanFactoryAware* @see BeanFactory* @see org.springframework.beans.factory.support.RootBeanDefinition#getInitMethodName* @see org.springframework.context.ApplicationContextAware*/
public interface InitializingBean {/*** Invoked by a BeanFactory after it has set all bean properties supplied* (and satisfied BeanFactoryAware and ApplicationContextAware).* <p>This method allows the bean instance to perform initialization only* possible when all bean properties have been set and to throw an* exception in the event of misconfiguration.* @throws Exception in the event of misconfiguration (such* as failure to set an essential property) or if initialization fails.*/void afterPropertiesSet() throws Exception;}
该接口一般可以用来做属性实例的校验,比如当前Bean依赖了哪些Bean, 如果依赖的Bean没有初始化,就应该抛出异常,例如DataSourceTransactionManager里用该方法去校验DataSource有没有被初始化。
public class DataSourceTransactionManager extends AbstractPlatformTransactionManagerimplements ResourceTransactionManager, InitializingBean {@Nullableprivate DataSource dataSource;private boolean enforceReadOnly = false;/*** Create a new DataSourceTransactionManager instance.* A DataSource has to be set to be able to use it.* @see #setDataSource*/public DataSourceTransactionManager() {setNestedTransactionAllowed(true);}/*** Create a new DataSourceTransactionManager instance.* @param dataSource JDBC DataSource to manage transactions for*/public DataSourceTransactionManager(DataSource dataSource) {this();setDataSource(dataSource);afterPropertiesSet();}@Overridepublic void afterPropertiesSet() {if (getDataSource() == null) {throw new IllegalArgumentException("Property 'dataSource' is required");}}}
InitializingBean接口的afterPropertiesSet()在AbstractAutowireCapableBeanFactoryinvokeInitMethods方法里被调用。
protected void invokeInitMethods(String beanName, final Object bean, @Nullable RootBeanDefinition mbd)throws Throwable {boolean isInitializingBean = (bean instanceof InitializingBean);// 执行InitializingBean的afterPropertiesSet()if (isInitializingBean && (mbd == null || !mbd.isExternallyManagedInitMethod("afterPropertiesSet"))) {if (logger.isDebugEnabled()) {logger.debug("Invoking afterPropertiesSet() on bean with name '" + beanName + "'");}if (System.getSecurityManager() != null) {try {AccessController.doPrivileged((PrivilegedExceptionAction<Object>) () -> {((InitializingBean) bean).afterPropertiesSet();return null;}, getAccessControlContext());}catch (PrivilegedActionException pae) {throw pae.getException();}}else {// 执行InitialingBean的afterProperties()接口。((InitializingBean) bean).afterPropertiesSet();}}if (mbd != null && bean.getClass() != NullBean.class) {String initMethodName = mbd.getInitMethodName();if (StringUtils.hasLength(initMethodName) &&!(isInitializingBean && "afterPropertiesSet".equals(initMethodName)) &&!mbd.isExternallyManagedInitMethod(initMethodName)) {invokeCustomInitMethod(beanName, bean, mbd);}}}
三、DefaultListableBeanFactory的父类AbstractAutowireCapableBeanFactory
AbstarctAutowireCapableBeanFactory 是一个抽象类,实现了AutowireCapableBeanFactory和AbstarctBeanFactory接口,initializeBean方法实现了实例化Bean的整个流程。
protected Object initializeBean(final String beanName, final Object bean, @Nullable RootBeanDefinition mbd) {if (System.getSecurityManager() != null) {AccessController.doPrivileged((PrivilegedAction<Object>) () -> {invokeAwareMethods(beanName, bean);return null;}, getAccessControlContext());}else {// 1. 执行所有的BeanNameAware、BeanClassLoaderAware、BeanFactoryAware接口,把对象塞入到参数里交给开发者使用。invokeAwareMethods(beanName, bean);}// 2. 执行所有的BeanPostProcessor里的postProcessBeforeInitialization()Object wrappedBean = bean;if (mbd == null || !mbd.isSynthetic()) {wrappedBean = applyBeanPostProcessorsBeforeInitialization(wrappedBean, beanName);}try {// 3. 执行Init方法, 其中包含InitializingBean接口里的AfterPropertiesSet()方法和自定义的init()方法invokeInitMethods(beanName, wrappedBean, mbd);}catch (Throwable ex) {throw new BeanCreationException((mbd != null ? mbd.getResourceDescription() : null),beanName, "Invocation of init method failed", ex);}//4. 执行所有的BeanPostProcessor的postProcessAfterInitialization()方法if (mbd == null || !mbd.isSynthetic()) {wrappedBean = applyBeanPostProcessorsAfterInitialization(wrappedBean, beanName);}return wrappedBean;}
相关文章:
Spring 框架源码(六) Bean的生命周期全流程源码解析
Spring框架作为Java王国的地基,我觉得它包含了很多精妙的设计,例如Bean工厂设计、Bean的生命周期、tx、aop、web、mvc等,最核心基本的Bean设计是Spring 的框架的灵魂,本文就Bean的生命周期全流程做源码程度上的解析,欢…...
运维服务商低成本提升服务质量解决方案
在信息化高速发展的今天,网络建设的重要性不言而喻,更多客户选择将运维服务外包或托管给运维服务商,市场需求愈大竞争压力愈大,想要脱颖而出势必要优化自身提高服务质量,最好是低成本、大提升,nVisual助力渠…...
Raft 一致性算法
Raft Raft提供了一种在计算系统集群中分布状态机的通用方法,确保集群中的每个节点都同意一系列相同的状态转换。 一个Raft集群包含若干个服务器节点,通常为5个,这允许整个系统容忍2个节点的失效。每个节点处于以下三种状态之一: …...
驱动程序开发:基于EC20 4G模块自动拨号联网的两种方式(GobiNet工具拨号和PPP工具拨号)
目录一、EC20 4G模块简介二、根据移远官方文档修改EC20 4G模组驱动 1、因为EC20 4G模组min-pice接口其实就是usb接口,因此需要修改Linux内核源码drivers/usb/serial/option.c文件,如下图: 2、根据USB协议的要求,需要在drive…...
Web自动化测试——常见问题篇
文章目录一、什么是自动化测试二、为啥进行自动化测试(优点)三、Webdriver 的工作原理四、显示等待和隐式等待的区别五、什么样的项目适合做自动化六、自动化测试的流程七、如何分析生成的自动化测试报告一、什么是自动化测试 所谓的自动化测试就是使用…...
快速实现Modbus TCP转BACnet IP协议的方案
一、需求背景 BACnet是用于智能楼宇自控系统的主流通信协议,可用在暖通空调系统(HVAC,包括暖气、通风、空气调节),也可以用在照明控制、门禁系统、火警侦测系统及其相关的设备。楼宇中的受控设备都通过BACnet协议连接到…...
Unity CircleLayoutGroup 如何实现一个圆形自动布局组件
文章目录简介实现原理Editor 编辑器简介 Unity中提供了三种类型的自动布局组件,分别是Grid Layou Group、Horizontal Layout Group、Vertical Layout Group,本文自定义了一个圆形的自动布局组件Circle Layout Group,如图所示: Ra…...
springcloud+nacos+gateway案例
一、先搭建好springcloudnacos项目地址:https://javazhong.blog.csdn.net/article/details/128899999二、spring cloud gateway简述Spring Cloud Gateway 是Spring Cloud家族中的一款API网关。Gateway 建立在 Spring Webflux上,目标是提供一个简洁、高效的API网关&a…...
实习这么久,你知道Maven是如何从代码仓库中找到需要的依赖吗?
目录 碎碎念 Maven是如何找到代码仓库里需要的依赖的? 如何根据坐标在本地仓库中寻找所需要的依赖? 如何根据坐标在远程仓库中寻找所需要的依赖? Maven 如何使用 HTTP 或 HTTPS 协议从远程仓库中获取依赖项,请详细解释其原理…...
低代码/零代码的快速开发框架
目前国内主流的低代码开发平台有:宜搭、简道云、明道云、云程、氚云、伙伴云、道一云、JEPaaS、华炎魔方、搭搭云、JeecgBoot 、RuoYi等。这些平台各有优劣势,定位也不同,用户可以根据自己需求选择。 一、阿里云宜搭 宜搭是阿里巴巴集团在20…...
C# 中常见的设计模式
设计模式是一套被广泛应用于软件设计的最佳实践,它们可以帮助开发者解决特定的问题,提高代码的可重用性、可读性和可维护性。本文将介绍 C# 中常见的几种设计模式,并提供相应的示例代码。 工厂模式 工厂模式是一种创建型设计模式,…...
promethues/servicemonitor
目录 1.promethues 能保证源源不断地采集/metrics 信息吗?每次都是最新的吗 2.部署servicemonitor 的作用是什么? 3.pod 部署采集数据直接上报promthues ,不通过servicemonitor 可以吗? 4.你说的"此外,如果部署…...
postman使用简介
1、介绍 postman是一款功能强大的网页调试和模拟发送HTTP请求的Chrome插件,支持几乎所有类型的HTTP请求 2、下载及安装 官方文档:https://www.getpostman.com/docs/v6/ chrome插件:chrome浏览器应用商店直接搜索添加即可(需墙&…...
@DS注解在事务中实现数据源的切换@DS在事务中失效【已解决】
在Springboot的application.yml中的配置: spring:datasource:url: jdbc:mysql://localhost:3306/test2?serverTimezoneUTC&useUnicodetrue&characterEncodingutf8driver-class-name: com.mysql.cj.jdbc.Driverusername: rootpassword: rootdynamic:primar…...
Java I/O之文件系统
一、全文概览 在学习文件系统之前,需要了解下Java在I/O上的发展史:在Java7之前,打开和读取文件需要编写特别笨拙的代码,涉及到很多的InputStream、OutputStream等组合起来使用,每次在使用时或许都需要查一下文档才能记…...
Mysql元数据获取方法(information_schema绕过方法)
前提:如果waf或其它过滤了information_schema关键字,那我们该如何获取元数据呢?能够代替information_schema的有:sys.schema_auto_increment_columnssys.schema_table_statistics_with_bufferx$schema_table_statistics_with_buff…...
Eclipse快捷键
* 1.补全代码的声明:alt /* 2.快速修复: ctrl 1 * 3.批量导包:ctrl shift o* 4.使用单行注释:ctrl /* 5.使用多行注释: ctrl shift / * 6.取消多行注释:ctrl shift \* 7.复制指定行的代码:ctrl a…...
java ssm自习室选座预约系统开发springmvc
人工管理显然已无法应对时代的变化,而自习室选座预约系统开发能很好地解决这一问题,既能提高人力物力,又能提高预约选座的知名度,取代人工管理是必然趋势。 本自习室选座预约系统开发以SSM作为框架,JSP技术,…...
分享我从功能测试转型到测试开发的真实故事
由于这段时间我面试了很多家公司,也经历了之前公司的不愉快。所以我想写一篇文章来分享一下自己的面试体会。希望能对我在之后的工作或者面试中有一些帮助,也希望能帮助到正在找工作的你。 找工作 我们总是草率地进入一个自己不了解的公司工作…...
TypeScript快速入门———(二)TypeScript常用类型
文章目录概述1 类型注解2 常用基础类型概述3.原始类型4 数组类型5 类型别名6.函数类型7 对象类型8 接口9 元组10 类型推论11 类型断言12 字面量类型13 枚举14 any 类型15 typeof概述 TypeScript 是 JS 的超集,TS 提供了 JS 的所有功能,并且额外的增加了…...
深度学习在微纳光子学中的应用
深度学习在微纳光子学中的主要应用方向 深度学习与微纳光子学的结合主要集中在以下几个方向: 逆向设计 通过神经网络快速预测微纳结构的光学响应,替代传统耗时的数值模拟方法。例如设计超表面、光子晶体等结构。 特征提取与优化 从复杂的光学数据中自…...
Appium+python自动化(十六)- ADB命令
简介 Android 调试桥(adb)是多种用途的工具,该工具可以帮助你你管理设备或模拟器 的状态。 adb ( Android Debug Bridge)是一个通用命令行工具,其允许您与模拟器实例或连接的 Android 设备进行通信。它可为各种设备操作提供便利,如安装和调试…...
k8s从入门到放弃之Ingress七层负载
k8s从入门到放弃之Ingress七层负载 在Kubernetes(简称K8s)中,Ingress是一个API对象,它允许你定义如何从集群外部访问集群内部的服务。Ingress可以提供负载均衡、SSL终结和基于名称的虚拟主机等功能。通过Ingress,你可…...
阿里云ACP云计算备考笔记 (5)——弹性伸缩
目录 第一章 概述 第二章 弹性伸缩简介 1、弹性伸缩 2、垂直伸缩 3、优势 4、应用场景 ① 无规律的业务量波动 ② 有规律的业务量波动 ③ 无明显业务量波动 ④ 混合型业务 ⑤ 消息通知 ⑥ 生命周期挂钩 ⑦ 自定义方式 ⑧ 滚的升级 5、使用限制 第三章 主要定义 …...
TRS收益互换:跨境资本流动的金融创新工具与系统化解决方案
一、TRS收益互换的本质与业务逻辑 (一)概念解析 TRS(Total Return Swap)收益互换是一种金融衍生工具,指交易双方约定在未来一定期限内,基于特定资产或指数的表现进行现金流交换的协议。其核心特征包括&am…...
深入浅出深度学习基础:从感知机到全连接神经网络的核心原理与应用
文章目录 前言一、感知机 (Perceptron)1.1 基础介绍1.1.1 感知机是什么?1.1.2 感知机的工作原理 1.2 感知机的简单应用:基本逻辑门1.2.1 逻辑与 (Logic AND)1.2.2 逻辑或 (Logic OR)1.2.3 逻辑与非 (Logic NAND) 1.3 感知机的实现1.3.1 简单实现 (基于阈…...
OD 算法题 B卷【正整数到Excel编号之间的转换】
文章目录 正整数到Excel编号之间的转换 正整数到Excel编号之间的转换 excel的列编号是这样的:a b c … z aa ab ac… az ba bb bc…yz za zb zc …zz aaa aab aac…; 分别代表以下的编号1 2 3 … 26 27 28 29… 52 53 54 55… 676 677 678 679 … 702 703 704 705;…...
ui框架-文件列表展示
ui框架-文件列表展示 介绍 UI框架的文件列表展示组件,可以展示文件夹,支持列表展示和图标展示模式。组件提供了丰富的功能和可配置选项,适用于文件管理、文件上传等场景。 功能特性 支持列表模式和网格模式的切换展示支持文件和文件夹的层…...
密码学基础——SM4算法
博客主页:christine-rr-CSDN博客 专栏主页:密码学 📌 【今日更新】📌 对称密码算法——SM4 目录 一、国密SM系列算法概述 二、SM4算法 2.1算法背景 2.2算法特点 2.3 基本部件 2.3.1 S盒 2.3.2 非线性变换 编辑…...
字符串哈希+KMP
P10468 兔子与兔子 #include<bits/stdc.h> using namespace std; typedef unsigned long long ull; const int N 1000010; ull a[N], pw[N]; int n; ull gethash(int l, int r){return a[r] - a[l - 1] * pw[r - l 1]; } signed main(){ios::sync_with_stdio(false), …...

