Spring底层原理(三)
Spring底层原理(三)
Bean的生命周期
@SpringBootApplication
public class Application {public static void main(String[] args) {ConfigurableApplicationContext context = SpringApplication.run(Application.class, args);context.close();}
}@Slf4j
@Component
public class LifeCycleBean {public LifeCycleBean(){log.info("构造");}@Autowiredpublic void autowire(@Value("${JAVA_HOME}") String home){log.info("依赖注入:{}",home);}@PostConstructpublic void init(){log.info("初始化");}@PreDestroypublic void destroy(){log.info("销毁");}
}
启动容器后会得到以下结果

Bean的生命周期为:构造方法 -> 依赖注入->初始化 ->销毁
与Bean生命周期相关的后置处理器
PostProcessor中文意思为后置处理器
InstantiationAwareBeanPostProcessor与DestructionAwareBeanPostProcessor都是BeanPostProcessor的子接口
@Slf4j
@Component
public class MyBeanPostProcessor implements InstantiationAwareBeanPostProcessor, DestructionAwareBeanPostProcessor {@Overridepublic void postProcessBeforeDestruction(Object bean, String beanName) throws BeansException {if (beanName.equals("lifeCycleBean")){log.info("<<<< 销毁前执行,如@PreDestory");}}@Overridepublic Object postProcessBeforeInstantiation(Class<?> beanClass, String beanName) throws BeansException {if (beanName.equals("lifeCycleBean")){log.debug("<<<< 实例化之前执行,这里返回的对象会替换掉原本的bean");}return null;}@Overridepublic boolean postProcessAfterInstantiation(Object bean, String beanName) throws BeansException {if (beanName.equals("lifeCycleBean")){log.debug("<<<< 实例化后执行,这里返回false会跳过依赖注入阶段");}return true;}@Overridepublic PropertyValues postProcessProperties(PropertyValues pvs, Object bean, String beanName) throws BeansException {if (beanName.equals("lifeCycleBean")){log.debug("<<<< 依赖注入阶段执行,如@Autowired、@Value、@Resource");}return pvs;}@Overridepublic Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {if (beanName.equals("lifeCycleBean")){log.debug("<<<< 初始化之前执行,这里返回的对象会替换掉原本的bean,如@PostConstruct、@ConfigurationProperties");}return bean;}@Overridepublic Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {if (beanName.equals("lifeCycleBean")){log.debug("<<<< 初始化之后执行,这里返回的对象会替换掉原本的bean,如代理增强");}return bean;}
}

Bean后置处理器与模板方法模式
public class MethodTemplateTest {public static void main(String[] args) {MyBeanFactory factory = new MyBeanFactory();factory.addProcessor(bean -> System.out.println("解析@Autowired"));factory.addProcessor(bean -> System.out.println("解析@Resources"));factory.getBean();}static class MyBeanFactory {private List<BeanPostProcessor> processors = new ArrayList<>();public void addProcessor(BeanPostProcessor postProcessor) {processors.add(postProcessor);}public Object getBean() {Object bean = new Object();System.out.println("构造:" + bean);System.out.println("依赖注入:" + bean);for (BeanPostProcessor processor : processors) {processor.inject(bean);}System.out.println("初始化:" + bean);return bean;}}interface BeanPostProcessor {void inject(Object bean);//对依赖注入阶段进行拓展}
}
- 将代码中不确定的部分抽象成接口,供后续拓展
常见的bean后置处理器
public class A4Application {public static void main(String[] args) {//GenericApplicationContext是一个干净的容器,没有添加BeanFactory后置处理器和Bean后置处理器GenericApplicationContext context = new GenericApplicationContext();//注册beancontext.registerBean("bean1",Bean1.class);context.registerBean("bean2",Bean2.class);context.registerBean("bean3",Bean3.class);//初始化容器context.refresh();//执行beanFactory后置处理器,添加bean后置处理器,初始化所有单例bean//销毁容器context.close();}
}
添加AutowiredAnnotationBeanPostProcessor
context.getDefaultListableBeanFactory().setAutowireCandidateResolver(new ContextAnnotationAutowireCandidateResolver());
context.registerBean(AutowiredAnnotationBeanPostProcessor.class);
ContextAnnotationAutowireCandidateResolver:用于支持解析@ValueAutowiredAnnotationBeanPostProcessor:该处理器用于解析@Autowired@Value

添加CommonAnnotationBeanPostProcessor
context.registerBean(CommonAnnotationBeanPostProcessor.class);
CommonAnnotationBeanPostProcessor:用于解析@Resurce@PostConstruct@PreDestroy
ConfigurationPropertiesBindingPostProcessor.register(context);
ConfigurationPropertiesBindingPostProcessor:用于解析@ConfigurationProperties
Autowired后处理器执行分析
AutowiredAnnotationBeanPostProcessor processor = new AutowiredAnnotationBeanPostProcessor();
processor.setBeanFactory(beanFactory);//需要从容器中查找依赖
Bean1 bean1 = new Bean1();
System.out.println(bean1);//Bean1{bean2=null, bean3=null, home='null'}
//参数1:需要注入的值,null则从容器中获取 参数2:被注入的目标
processor.postProcessProperties(null,bean1,"bean1");

通过反射访问InjectionMetadata中的信息
Method findAutowiringMetadata = AutowiredAnnotationBeanPostProcessor.class.getDeclaredMethod("findAutowiringMetadata", String.class, Class.class, PropertyValues.class);
findAutowiringMetadata.setAccessible(true);
InjectionMetadata metadata = (InjectionMetadata) findAutowiringMetadata.invoke(processor, "bean1", Bean1.class, null);//获取bean1上加了@Value @Autowired的成员变量 方法参数信息

如何查找依赖?
//根据field获取field对应的type,然后容factory中查找
Field bean3 = Bean1.class.getDeclaredField("bean3");
DependencyDescriptor dd1 = new DependencyDescriptor(bean3, false);
Object o = beanFactory.doResolveDependency(dd1, null, null, null);
//根据方法参数查找依赖
Method setBean2 = Bean1.class.getDeclaredMethod("setBean2", Bean2.class);
//创建依赖描述器,按照方法参数查找依赖,需要一个MethodParameter对象,参数2为参数的索引
DependencyDescriptor dd2 = new DependencyDescriptor(new MethodParameter(setBean2, 0), true);
Object o2 = beanFactory.doResolveDependency(dd2, null, null, null);//匹配@Value
Method setHome = Bean1.class.getDeclaredMethod("setHome", String.class);
DependencyDescriptor dd3 = new DependencyDescriptor(new MethodParameter(setHome, 0), true);
Object o3 = beanFactory.doResolveDependency(dd3, null, null, null);
相关文章:
Spring底层原理(三)
Spring底层原理(三) Bean的生命周期 SpringBootApplication public class Application {public static void main(String[] args) {ConfigurableApplicationContext context SpringApplication.run(Application.class, args);context.close();} }Slf4j Component public cla…...
ElementPlus表格中的背景透明
ElementPlus表格中的背景透明 最近写大屏,用到elementplus中的el-table,为了让显示效果好看一点,需要把表格的白色背景调整为透明,与整个背景融为一体。可以参考的资料非常少,大部分都是ElmentUI的方法,在…...
【会议征稿通知】2024第四届神经网络、信息与通信工程国际学术会议(NNICE 2024)
2024第四届神经网络、信息与通信工程国际学术会议(NNICE 2024) 2024 4th International Conference on Neural Networks, Information and Communication Engineering 2024第四神经网络、信息与通信工程国际学术会议(NNICE 2024࿰…...
PyCharm改变代码背景图片的使用教程
一个好的集成环境是学习和使用一门编程语言的重中之重,这次我给大家分享如何改变PyCharm软件的代码背景图片。 说明:本教程使用的是汉化版PyCharm软件。 打开PyCharm软件。 点击软件最上方导航栏的文件,然后找到设置。 打开设置然后点击外观…...
BadNets: Identifying Vulnerabilities in the Machine Learning Model Supply Chain
BadNets: Identifying Vulnerabilities in the Machine Learning Model Supply Chain----《BadNets:识别机器学习模型供应链中的漏洞》 背景: 许多用户将训练过程外包给云计算,或者依赖于经过训练的模型,然后根据特定的任务对模型进行微调。这…...
Kubernetes速成课程:掌握容器编排的精髓
微服务演进方向 • 面向分布式设计(Distribution):容器、微服务、API 驱动的开发; • 面向配置设计(Configuration):⼀个镜像,多个环境配置; • 面向韧性设计(Resistancy):故障容忍和自愈; • 面向弹性设计(Elasticity):弹性扩展和对环境变化(负载)做出响应; •…...
【数据库】分组数据 GROUP BY、HAVING
分组数据 创建分组过滤分组SQL 子句顺序 创建分组 s q l sql sql 中,使用 GROUP BY 子句对数据进行分组。分组通常与聚合函数一起使用,以对每个组内的数据执行聚合操作; e . g . e.g. e.g. 按照客户分组,计算每个客户的订单总金额…...
“唯品会VIP商品API:一键获取奢侈品详情,尊享品质生活!“
要获取唯品会VIP商品的详细信息,您可以通过唯品会的API接口进行调用。 唯品会提供了多种商品选择,包括服装、美容护肤、鞋子、箱包、家居、母婴等等。在这些商品中,VIP奢侈品专区是唯品会的重要特色之一。 要获取VIP商品的详细信息…...
uniapp解决iOS切换语言——原生导航栏buttons文字不生效
uniapp 切换语言原生导航栏buttons文字不生效? 文章目录 uniapp 切换语言原生导航栏buttons文字不生效?效果图page.json配置解决方式 效果图 场景:在 tabbar 页面中,配置 原生导航栏 buttons ,切换语言时,不…...
idea 基础设置
1、设置 IDEA 主题 2、自动导包和优化多余的包 3、同一个包下的类,超过指定个数的时候,导包合并为* 4、显示行号 , 方法和方法间的分隔符: 5、忽略大小写,进行提示 6、多个类不隐藏,多行显示 7、设置默认的…...
Rockchip Uboot CmdLine 作用 来源 常用参数
Rockchip Uboot CmdLine cmdline 是 U-Boot 向 kernel 传递参数的一个重要手段,诸如传递启动存储,设备状态等。cmdline 参数有多个来源,由 U-Boot 进行拼接、过滤重复数据之后再传给 kernel。U-Boot 阶段的 cmdline 被保存在 bootargs 环境变…...
MySQL表导出
# 导出表和数据 mysqldump --skip-extended-insert -hHost -uUser -pPassword -PPost database table > table.sql# 如: mysqldump --skip-extended-insert -h172.1.0.1 -uroot -pabc123 -P3306 data_support city_code > city_code.sql# 导入表和数据 mysql …...
HTML页面获取URL传递的参数值
如: // 查询url上链接的参数与参数值 function getQueryString(name) {var url window.location.search; // 获取URLvar pattern new RegExp("[\?\&]" name "([^\&])", "i"); // 正则匹配URLvar matcher pattern.exec(…...
mac安装jenkins
1、安装jenkins之前确认是否安装了homebrew 2、开始安装jenkins 安装完如下图则安装完成 3、改一下ip和端口 4、启动jenkins brew services restart jenkins 使用自己修改后的ip:port http://0.0.0.0:8088 根据提示信息,拿到管理员密码,并解锁 5、安装…...
asp.net网球馆计费管理系统VS开发sqlserver数据库web结构c#编程Microsoft Visual Studio
一、源码特点 asp.net网球馆计费管理系统是一套完善的web设计管理系统,系统具有完整的源代码和数据库,系统主要采用B/S模式开发。开发环境为vs2010,数据库为sqlserver2008,使用c#语 言开发 aspnet网球馆计费管理系统1 二、…...
动手学深度学习——第五次学
权重衰减是最广泛使用的正则化的技术之一 今天学的很头疼,好多都是公式 12权重衰退(解决过拟合) 13丢弃法(解决过拟合) 14数值稳定(梯度爆炸和梯度消失问题) 15竞赛题讲解 层和块 多层感知机…...
python实验16_网络爬虫
实验16:网络爬虫 1.实验目标及要求 (1)掌握简单爬虫方法。 2. 实验主要内容 爬取中国票房网 ① 爬取中国票房网(www.cbooo.cn)2019年票房排行榜前20名的电影相关数据 代码部分: import time from selenium.webdriver impor…...
家长扫码查成绩
亲爱的老师,你是否曾为了如何让家长更方便地查询学生的成绩而烦恼?现在,我们为你介绍一款简单易用的成绩查询系统,让家长只需轻轻一扫,即可查看孩子的成绩。 一、什么是成绩查询系统? 成绩查询系统是一款专…...
【转】多台服务器共享session问题
多台服务器共享 session 问题 现在的大型网站中,如何实现多台服务器中的 session 数据共享呢? 当使用多台服务器架设成集群之后,我们通过负载均衡的方式,同一个用户(或者 ip)访问时被分配到不同的服务器上…...
页面置换算法的模拟实现及命中率对比
页面置换算法是用于管理计算机内存中页面(或页面框)的一种策略。常见的页面置换算法包括FIFO(先进先出)、LRU(最近最少使用)、LFU(最少使用)等。以下是一个简单的页面置换算法模拟实…...
用RP2350微控制器实现《黑客帝国》数字雨:嵌入式图形系统实战
1. 项目概述与核心价值如果你和我一样,对《黑客帝国》里那些从屏幕顶端倾泻而下的绿色字符雨有着难以言喻的情结,同时又是个喜欢动手鼓捣硬件的开发者,那么这个项目绝对能让你兴奋起来。它不是一个简单的屏幕保护程序,而是一个完整…...
别再乱点U盘里的.exe了!手把手教你清除‘Usb Disk.exe’病毒并恢复隐藏文件
彻底清除U盘病毒:从识别到恢复的完整实战指南 当你发现U盘里的文件突然"消失",只剩下一些可疑的.exe文件时,很可能已经遭遇了典型的U盘病毒攻击。这种病毒不仅会隐藏你的重要文档,还可能通过自动运行机制感染整个计算机…...
零代码构建你的AI知识库:让Obsidian笔记开口说话
零代码构建你的AI知识库:让Obsidian笔记开口说话 【免费下载链接】anything-llm The all-in-one AI productivity accelerator. On device and privacy first with no annoying setup or configuration. 项目地址: https://gitcode.com/GitHub_Trending/an/anythi…...
别再手动改参数了!用Fluent 2023R1的Parametric模块,5分钟搞定N个工况的批量仿真
Fluent 2023R1参数化模块实战:从单点仿真到智能设计空间探索 在计算流体动力学(CFD)领域,工程师们常常需要面对一个现实困境:如何高效完成数十种工况的参数扫描?传统手动修改边界条件的方式不仅耗时费力&am…...
企业无线网络进阶:FreeRadius服务器配置与TLS证书实战
1. 为什么企业无线网络需要FreeRadius与TLS证书 想象一下你公司的Wi-Fi像是一个没有门禁的公共广场,任何人都能随意进出。这种情况对于企业网络来说简直是灾难——数据泄露、带宽被占、内网渗透风险接踵而至。而FreeRadiusTLS证书的方案,就相当于给这个广…...
从零构建AI智能体:核心架构、ReAct模式与实战指南
1. 项目概述:从零构建AI智能体的核心价值最近在GitHub上看到一个挺有意思的项目,叫pguso/ai-agents-from-scratch。光看名字,很多朋友可能就心动了——“从零开始构建AI智能体”,听起来就像是把那些神秘的大模型应用开发黑盒给彻底…...
关于光缆,这些事儿通信人一定要知道
随着5G网络的全面铺开和持续深耕,通信工程师的工作边界正在不断拓展。过去,后台网优工程师可能更多地专注于参数调整、信令分析和性能优化;而如今,越来越多的项目要求前后台协同作业,网优人员也需要熟悉现场施工规范&a…...
长期使用Taotoken Token Plan套餐的成本控制体会
🚀 告别海外账号与网络限制!稳定直连全球优质大模型,限时半价接入中。 👉 点击领取海量免费额度 长期使用Taotoken Token Plan套餐的成本控制体会 1. 从按需计费到套餐订阅的转变 在开始使用Taotoken平台时,我和团队…...
重建二叉树-C++
分享一个大牛的人工智能教程。零基础!通俗易懂!风趣幽默!希望你也加入到人工智能的队伍中来!请轻击人工智能教程https://www.captainai.net/troubleshooter // 面试题7:重建二叉树 // 题目:输入某二叉树的前…...
Oto 多平台适配原理揭秘:从 Windows 到 Android 的底层实现
Oto 多平台适配原理揭秘:从 Windows 到 Android 的底层实现 【免费下载链接】oto ♪ A low-level library to play sound on multiple platforms ♪ 项目地址: https://gitcode.com/gh_mirrors/ot/oto Oto 是一个强大的跨平台音频播放库,支持从 W…...
