spring源码分析bean的生命周期(下)
doGetBean()执行过程
createBean()执行过程

一、@DependsOn注解
spring创建对象之前会判断类上是否加了@DependsOn注解,加了会遍历然后会添加到一个map中,spring会先创建@DependsOn注解指定的类
二、spring类加载器
在合并BeanDefinition,确定beanName之后和scope之后就会调用createBean()方法获取类加载器,BeanDefinition合并之后,就可以去创建Bean对象了,而创建Bean就必须实例化对象,而实例化就必须先加载当前BeanDefinition所对应的class,在AbstractAutowireCapableBeanFactory类的createBean()方法中,一开始就会调用
Class<?> resolvedClass = resolveBeanClass(mbd, beanName);
这行代码就是去加载类,该方法是这么实现的:
if (mbd.hasBeanClass()) {return mbd.getBeanClass();
}
if (System.getSecurityManager() != null) {return AccessController.doPrivileged((PrivilegedExceptionAction<Class<?>>) () ->doResolveBeanClass(mbd, typesToMatch), getAccessControlContext());}
else {return doResolveBeanClass(mbd, typesToMatch);
}
public boolean hasBeanClass() {return (this.beanClass instanceof Class);
}
如果beanClass属性的类型是Class,那么就直接返回,如果不是,则会根据类名进行加载(doResolveBeanClass方法所做的事情)
会利用BeanFactory所设置的类加载器来加载类,如果没有设置,则默认使用**ClassUtils.getDefaultClassLoader()**所返回的类加载器来加载。
ClassUtils.getDefaultClassLoader()
- 优先返回当前线程中的ClassLoader
- 线程中类加载器为null的情况下,返回ClassUtils类的类加载器
- 如果ClassUtils类的类加载器为空,那么则表示是Bootstrap类加载器加载的ClassUtils类,那么则返回系统类加载器
三、实例化前
当前BeanDefinition对应的类成功加载后,就可以实例化对象了,但是...
在Spring中,实例化对象之前,Spring提供了一个扩展点,允许用户来控制是否在某个或某些Bean实例化之前做一些启动动作。这个扩展点叫InstantiationAwareBeanPostProcessor.postProcessBeforeInstantiation()。比如:
@Component
public class TestBeanPostProcessor implements InstantiationAwareBeanPostProcessor {@Overridepublic Object postProcessBeforeInstantiation(Class<?> beanClass, String beanName) throws BeansException {if ("userService".equals(beanName)) {System.out.println("实例化前");}return null;}
}
如上代码会导致,在userService这个Bean实例化前,会进行打印。
值得注意的是,postProcessBeforeInstantiation()是有返回值的,如果这么实现:
@Component
public class TestBeanPostProcessor implements InstantiationAwareBeanPostProcessor {@Overridepublic Object postProcessBeforeInstantiation(Class<?> beanClass, String beanName) throws BeansException {if ("userService".equals(beanName)) {System.out.println("实例化前");return new UserService();}return null;}
}
userService这个Bean,在实例化前会直接返回一个由我们所定义的UserService对象。如果是这样,表示不需要Spring来实例化了,并且后续的Spring依赖注入也不会进行了,会跳过一些步骤,直接执行初始化后这一步。
四、实例化
在这个步骤中就会根据BeanDefinition去创建一个对象了。
1、Supplier创建对象
首先判断BeanDefinition中是否设置了Supplier,如果设置了则调用Supplier的get()得到对象
得直接使用BeanDefinition对象来设置Supplier,比如:
AbstractBeanDefinition beanDefinition = BeanDefinitionBuilder.genericBeanDefinition().getBeanDefinition();
beanDefinition.setInstanceSupplier(new Supplier<Object>() {@Overridepublic Object get() {return new UserService();}
});
context.registerBeanDefinition("userService", beanDefinition);
2、工厂方法创建对象
如果没有设置Supplier,则检查BeanDefinition中是否设置了factoryMethod,也就是工厂方法,有两种方式可以设置factoryMethod,比如:
方式一:
<bean id="userService" class="com.spring.service.UserService" factory-method="createUserService" />
对应的UserService类为:
public class UserService {public static UserService createUserService() {System.out.println("执行createUserService()");UserService userService = new UserService();return userService;}public void test() {System.out.println("test");}}
方式二:
<bean id="commonService" class="com.spring.service.CommonService"/>
<bean id="userService1" factory-bean="commonService" factory-method="createUserService" />
对应的CommonService的类为:
public class CommonService {public UserService createUserService() {return new UserService();}
}
Spring发现当前BeanDefinition方法设置了工厂方法后,就会区分这两种方式,然后调用工厂方法得到对象。
值得注意的是,我们通过@Bean所定义的BeanDefinition,是存在factoryMethod和factoryBean的,也就是和上面的方式二非常类似,@Bean所注解的方法就是factoryMethod,AppConfig对象就是factoryBean。如果@Bean所所注解的方法是static的,那么对应的就是方式一。
五、BeanDefinition后置处理器
Bean对象实例化出来之后,接下来就应该给对象的属性赋值了。在真正给属性赋值之前,Spring又提供了一个扩展点MergedBeanDefinitionPostProcessor.postProcessMergedBeanDefinition(),可以对此时的BeanDefinition进行加工,比如:
@Component
public class TestMergedBeanDefinitionPostProcessor implements MergedBeanDefinitionPostProcessor {@Overridepublic void postProcessMergedBeanDefinition(RootBeanDefinition beanDefinition, Class<?> beanType, String beanName) {if ("userService".equals(beanName)) {beanDefinition.getPropertyValues().add("orderService", new OrderService());}}
}
在Spring源码中,AutowiredAnnotationBeanPostProcessor就是一个MergedBeanDefinitionPostProcessor,它的postProcessMergedBeanDefinition()中会去查找注入点,并缓存在AutowiredAnnotationBeanPostProcessor对象的一个Map中(injectionMetadataCache)。
六、实例化后
在处理完BeanDefinition后,Spring又设计了一个扩展点:InstantiationAwareBeanPostProcessor.postProcessAfterInstantiation(),比如:
@Component
public class TestInstantiationAwareBeanPostProcessor implements InstantiationAwareBeanPostProcessor {@Overridepublic boolean postProcessAfterInstantiation(Object bean, String beanName) throws BeansException {if ("userService".equals(beanName)) {UserService userService = (UserService) bean;userService.test();}return true;}
}
七、自动注入
spring会根据配置@Bean的autowire是byType或者byName进行注入,另外spring会调用InstantiationAwareBeanPostProcessor.postProcessProperties()解析@Autowired注解
八、处理属性
这个步骤中,就会处理@Autowired、@Resource、@Value等注解,也是通过**InstantiationAwareBeanPostProcessor.postProcessProperties()**扩展点来实现的,比如我们甚至可以实现一个自己的自动注入功能,比如:
@Component
public class TestInstantiationAwareBeanPostProcessor implements InstantiationAwareBeanPostProcessor {@Overridepublic PropertyValues postProcessProperties(PropertyValues pvs, Object bean, String beanName) throws BeansException {if ("userService".equals(beanName)) {for (Field field : bean.getClass().getFields()) {if (field.isAnnotationPresent(TestInject.class)) {field.setAccessible(true);try {field.set(bean, "123");} catch (IllegalAccessException e) {e.printStackTrace();}}}}return pvs;}
}
九、执行Aware
完成了属性赋值之后,Spring会执行一些回调,包括:
- BeanNameAware:回传beanName给bean对象。
- BeanClassLoaderAware:回传classLoader给bean对象。
- BeanFactoryAware:回传beanFactory给对象。
十、初始化前
初始化前,也是Spring提供的一个扩展点:BeanPostProcessor.postProcessBeforeInitialization(),比如
@Component
public class TestBeanPostProcessor implements BeanPostProcessor {@Overridepublic Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {if ("userService".equals(beanName)) {System.out.println("初始化前");}return bean;}
}
利用初始化前,可以对进行了依赖注入的Bean进行处理。
在Spring源码中:
- InitDestroyAnnotationBeanPostProcessor会在初始化前这个步骤中执行@PostConstruct的方法,
- ApplicationContextAwareProcessor会在初始化前这个步骤中进行其他Aware的回调:
- EnvironmentAware:回传环境变量
- EmbeddedValueResolverAware:回传占位符解析器
- ResourceLoaderAware:回传资源加载器
- ApplicationEventPublisherAware:回传事件发布器
- MessageSourceAware:回传国际化资源
- ApplicationStartupAware:回传应用其他监听对象,可忽略
- ApplicationContextAware:回传Spring容器ApplicationContext
十一、初始化
- 查看当前Bean对象是否实现了InitializingBean接口,如果实现了就调用其afterPropertiesSet()方法
- 执行BeanDefinition中指定的初始化方法
十二、、初始化后
这是Bean创建生命周期中的最后一个步骤,也是Spring提供的一个扩展点:BeanPostProcessor.postProcessAfterInitialization(),比如:
@Component
public class TestBeanPostProcessor implements BeanPostProcessor {@Overridepublic Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {if ("userService".equals(beanName)) {System.out.println("初始化后");}return bean;}
}
可以在这个步骤中,对Bean最终进行处理,Spring中的AOP就是基于初始化后实现的,初始化后返回的对象才是最终的Bean对象。
总结BeanPostProcessor
- InstantiationAwareBeanPostProcessor.postProcessBeforeInstantiation()
- 实例化
- MergedBeanDefinitionPostProcessor.postProcessMergedBeanDefinition()
- InstantiationAwareBeanPostProcessor.postProcessAfterInstantiation()
- 自动注入
- InstantiationAwareBeanPostProcessor.postProcessProperties()
- Aware对象
- BeanPostProcessor.postProcessBeforeInitialization()
- 初始化
- BeanPostProcessor.postProcessAfterInitialization()
相关文章:
spring源码分析bean的生命周期(下)
doGetBean()执行过程 createBean()执行过程 一、DependsOn注解 spring创建对象之前会判断类上是否加了DependsOn注解,加了会遍历然后会添加到一个map中,spring会先创建DependsOn注解指定的类 二、spring类加载器 在合并BeanDefinition,确定…...
完美解决Github提交PR后报错:File is not gofumpt-ed (gofumpt)
问题阐述 最近在Github上提交PR后,遇到了这么一个问题:golangci-lint运行失败,具体原因是File is not gofumpt-ed (gofumpt)。 名词解释 golangci-lint: golangci-lint 是Go语言社区中常用的代码质量检查工具,它可以…...
pytorch3d成功安装
一、pytorch3d是什么? PyTorch3D的目标是帮助加速深度学习和3D交叉点的研究。3D数据比2D图像更复杂,在从事Mesh R-CNN和C3DPO等项目时,我们遇到了一些挑战,包括3D数据表示、批处理和速度。我们开发了许多有用的算子和抽象…...
【vue3】同个页面引入多个图表组件实现自适应的方法
首先说明,此方案仅针对vue3项目在同一个页面引入了多个图表组件,因为我发现不能框架不同的引入,resize的写法还不同 window.addEventListener("resize", function() {...// 在此处重新调用即可 }以下是具体写法: 循环…...
一文了解汽车芯片的分类及用途介绍
汽车芯片按其功能可分为控制类(MCU和AI芯片)、功率类、传感器和其他(如存储器)四种类型。市场基本被国际巨头所垄断。人们常说的汽车芯片是指汽车里的计算芯片,按集成规模可分为MCU芯片和AI芯片(SoC芯片&am…...
Linux0.11内核源码解析-truncate.c
truncate文件只要实现释放指定i节点在设备上占用的所有逻辑块,包括直接块、一次间接块、二次间接块。从而将文件节点对应的文件长度截为0,并释放占用的设备空间。 索引节点的逻辑块连接方式 释放一次间接块 static void free_ind(int dev,int block) {…...
LED驱动型IC芯片的原理介绍
一、LED驱动器是什么 LED驱动器(LED Driver),是指驱动LED发光或LED模块组件正常工作的电源调整电子器件。由于LED PN结的导通特性决定,它能适应的电源电压和电流变动范围十分狭窄,稍许偏离就可能无法点亮LED或者发光效…...
VLAN实验
实验题目如下: 实验拓扑如下: 实验要求如下: 【1】PC1/3的接口均为access模式,且属于van2,在同一网段 【2】PC2/4/5/6的IP地址在同一网段,与PC1/3不在同一网段 【3】PC2可以访问4/5/6,PC4不能…...
Qt应用开发(基础篇)——高级纯文本窗口 QPlainTextEdit
一、前言 QPlainTextEdit类继承于QAbstractScrollArea,QAbstractScrollArea继承于QFrame,是Qt用来显示和编辑纯文本的窗口。 滚屏区域基类https://blog.csdn.net/u014491932/article/details/132245486?spm1001.2014.3001.5501框架类QFramehttps://blo…...
三维可视化平台有哪些?Sovit3D可视化平台怎么样?
随着社会经济的发展和数字技术的进步,互联网行业发展迅速。为了适应新时代社会发展的需要,大数据在这个社会经济发展过程中随着技术的进步而显得尤为重要。同时,大数据技术的快速发展进程也推动了可视化技术的飞速发展,国内外各类…...
Xxl-job安装部署以及SpringBoot集成Xxl-job使用
1、安装Xxl-job: 可以使用docker拉取镜像部署和源码编译两种方式,这里选择源码编译安装。 代码拉取地址: https://github.com/xuxueli/xxl-job/tree/2.1.2 官方开发文档: https://www.xuxueli.com/xxl-job/#%E3%80%8A%E5%88%…...
【【超声波避障小车代码】】
超声波避障小车代码 #include <reg51.h> //通用51头文件 #include <intrins.h> //使用了_nop()_函数#define uchar unsigned char //用 uchar 表示 unsigned char 类型 #define uint unsigned int //用 uint 表示 unsigned int 类型sbit EN…...
TDI(Time Delay Integration)
TDI(Time Delay Integration)是一种特殊的图像采集技术,常用于线阵CCD(Charge-Coupled Device)相机。TDI技术可以在保持高分辨率的同时增强图像的信噪比(Signal-to-Noise Ratio, SNR)࿰…...
RHCE——一、安装部署及例行性工作
RHCE 一、网络服务1、准备工作2、RHEL9操作系统的安装部署3、配置并优化RHEL9操作系统4、网络配置5、修改网络连接 二、例行性工作1、单一执行的例行性工作2、循环执行的例行性工作 三、书写定时任务的注意事项四、系统级别的计划任务五、实验1、实验一:编写脚本tes…...
服务器数据库中了360后缀勒索病毒怎么办?360后缀勒索病毒的加密形式
随着信息技术的发展,企业的计算机服务器数据库变得越来越重要。然而,在数字时代,网络上的威胁也日益增多。近期,我们收到很多企业的求助,企业的计算机服务器遭到了360后缀勒索病毒的攻击,导致服务器内的所有…...
期权就是股指期货吗,哪个好做一点?
近年来,场内ETF期权产品不断扩大,越来越多的投资者有投资期权的想法。当我们看到期权时,我们会不知不觉地想到期货,虽然期货与期权只有一个字的区别,但实际上有很大的不同,那么期权就是股指期货吗ÿ…...
week32
本周目标: Belady现象的解释 操作系统 计组IO/MM chapter 刷力扣 ubuntu磁盘/网络/命令行进阶*1 tarball之类的使用 Question 大数据系统实验要学吗? 据说课讲得不好这是一门类似数据库的课程——大数据之hadoop / hive / hbase 的区别是什么&a…...
【数据库】P1 数据库基本常识
数据库基本常识 数据库 ≠ 数据库管理系统表(Table)SQL是什么 数据库 ≠ 数据库管理系统 数据库是保存有组织的数据的容器,数据库称为 DB(DataBase);数据库管理系统是创建和操纵数据库的软件,数…...
c语言——计算两个数的乘积
//计算两个数的乘积 #include<stdio.h> #include<stdlib.h> int main() {double firstNumber,secondNumber,product;printf("两个浮点数:");scanf("%lf,%lf",&firstNumber,&secondNumber);productfirstNumber*secondNumber…...
单机模型并行最佳实践
单机模型并行最佳实践 模型并行在分布式训练技术中被广泛使用。 先前的帖子已经解释了如何使用 DataParallel 在多个 GPU 上训练神经网络; 此功能将相同的模型复制到所有 GPU,其中每个 GPU 消耗输入数据的不同分区。 尽管它可以极大地加快训练过程&…...
Vim 调用外部命令学习笔记
Vim 外部命令集成完全指南 文章目录 Vim 外部命令集成完全指南核心概念理解命令语法解析语法对比 常用外部命令详解文本排序与去重文本筛选与搜索高级 grep 搜索技巧文本替换与编辑字符处理高级文本处理编程语言处理其他实用命令 范围操作示例指定行范围处理复合命令示例 实用技…...
Linux链表操作全解析
Linux C语言链表深度解析与实战技巧 一、链表基础概念与内核链表优势1.1 为什么使用链表?1.2 Linux 内核链表与用户态链表的区别 二、内核链表结构与宏解析常用宏/函数 三、内核链表的优点四、用户态链表示例五、双向循环链表在内核中的实现优势5.1 插入效率5.2 安全…...
Xshell远程连接Kali(默认 | 私钥)Note版
前言:xshell远程连接,私钥连接和常规默认连接 任务一 开启ssh服务 service ssh status //查看ssh服务状态 service ssh start //开启ssh服务 update-rc.d ssh enable //开启自启动ssh服务 任务二 修改配置文件 vi /etc/ssh/ssh_config //第一…...
以下是对华为 HarmonyOS NETX 5属性动画(ArkTS)文档的结构化整理,通过层级标题、表格和代码块提升可读性:
一、属性动画概述NETX 作用:实现组件通用属性的渐变过渡效果,提升用户体验。支持属性:width、height、backgroundColor、opacity、scale、rotate、translate等。注意事项: 布局类属性(如宽高)变化时&#…...
QMC5883L的驱动
简介 本篇文章的代码已经上传到了github上面,开源代码 作为一个电子罗盘模块,我们可以通过I2C从中获取偏航角yaw,相对于六轴陀螺仪的yaw,qmc5883l几乎不会零飘并且成本较低。 参考资料 QMC5883L磁场传感器驱动 QMC5883L磁力计…...
PPT|230页| 制造集团企业供应链端到端的数字化解决方案:从需求到结算的全链路业务闭环构建
制造业采购供应链管理是企业运营的核心环节,供应链协同管理在供应链上下游企业之间建立紧密的合作关系,通过信息共享、资源整合、业务协同等方式,实现供应链的全面管理和优化,提高供应链的效率和透明度,降低供应链的成…...
《Playwright:微软的自动化测试工具详解》
Playwright 简介:声明内容来自网络,将内容拼接整理出来的文档 Playwright 是微软开发的自动化测试工具,支持 Chrome、Firefox、Safari 等主流浏览器,提供多语言 API(Python、JavaScript、Java、.NET)。它的特点包括&a…...
智能在线客服平台:数字化时代企业连接用户的 AI 中枢
随着互联网技术的飞速发展,消费者期望能够随时随地与企业进行交流。在线客服平台作为连接企业与客户的重要桥梁,不仅优化了客户体验,还提升了企业的服务效率和市场竞争力。本文将探讨在线客服平台的重要性、技术进展、实际应用,并…...
Java多线程实现之Callable接口深度解析
Java多线程实现之Callable接口深度解析 一、Callable接口概述1.1 接口定义1.2 与Runnable接口的对比1.3 Future接口与FutureTask类 二、Callable接口的基本使用方法2.1 传统方式实现Callable接口2.2 使用Lambda表达式简化Callable实现2.3 使用FutureTask类执行Callable任务 三、…...
2021-03-15 iview一些问题
1.iview 在使用tree组件时,发现没有set类的方法,只有get,那么要改变tree值,只能遍历treeData,递归修改treeData的checked,发现无法更改,原因在于check模式下,子元素的勾选状态跟父节…...

