当前位置: 首页 > news >正文

Spring源码-xxxAware实现类和BeanPostProcessor接口调用过程

xxxAware实现类作用

以ApplicationContextAware接口为例
ApplicationContextAware的作用是可以方便获取Spring容器ApplicationContext,从而可以获取容器内的Bean


package org.springframework.context;import org.springframework.beans.BeansException;
import org.springframework.beans.factory.Aware;/**
public interface ApplicationContextAware extends Aware {/**
设置该对象运行的ApplicationContext。通常,这个调用将用于初始化对象。
<p>在填充普通bean属性之后调用,但在初始回调之前调用,
例如{@link org.springframework.beans.factory.InitializingBeanafterPropertiesSet()}
或自定义初始化方法。
在{@link ResourceLoaderAwaresetResourceLoader}, 
{@link ApplicationEventPublisherAwaresetApplicationEventPublisher}
和{@link MessageSourceAware}之后调用,如果适用的话。
@param applicationContext这个对象要使用的applicationContext对象
@在context初始化错误的情况下抛出
ApplicationContextException 
@如果被应用程序context方法抛出则抛出BeansException @参见org.springframework.beans.factory.BeanInitializationException*/void setApplicationContext(ApplicationContext applicationContext) throws BeansException;}

下面这个例子就是ApplicationContextUtil 实现了ApplicationContextAware 这个接口,重写了setApplicationContext(ApplicationContext applicationContext)方法,在调用到这个方法的时候给类里的applicationContext 属性赋值,后续别的方法在拿到这个applicationContext进行操作,比如根据getBean方法获取Bean对象以及调用beanFactory.registerBeanDefinition(beanName, definition);方法进行添加BeanDefinition即bean的元数据信息。

public class ApplicationContextUtil implements ApplicationContextAware {private static ApplicationContext applicationContext = null;@Overridepublic void setApplicationContext(ApplicationContext applicationContext) throws BeansException {if (this.applicationContext == null) {this.applicationContext = applicationContext;}}//获取applicationContextpublic static ApplicationContext getApplicationContext() {return applicationContext;}//通过name获取 Bean.public static Object getBean(String name) {return getApplicationContext().getBean(name);}//通过class获取Bean.public static <T> T getBean(Class<T> clazz) {return getApplicationContext().getBean(clazz);}/*** 同步方法注册bean到ApplicationContext中** @param beanName* @param clazz* @param original bean的属性值*/public static synchronized void setBean(String beanName, Class<?> clazz, Map<String,Object> original) {checkApplicationContext();DefaultListableBeanFactory beanFactory = (DefaultListableBeanFactory) applicationContext.getAutowireCapableBeanFactory();if(beanFactory.containsBean(beanName)){return;}//BeanDefinition beanDefinition = new RootBeanDefinition(clazz);GenericBeanDefinition definition = new GenericBeanDefinition();//类classdefinition.setBeanClass(clazz);//属性赋值definition.setPropertyValues(new MutablePropertyValues(original));//注册到spring上下文beanFactory.registerBeanDefinition(beanName, definition);}}

上述是相关使用,为什么实现这个接口就会调用这个set方法,接下来根据spring源码,讲解xxxAware接口的前世今生。
不重要的步骤给出调用链路

AnnotationConfigApplicationContext## AnnotationConfigApplicationContext(String... basePackages) 构造函数
AbstractApplicationContext##refresh()容器刷新
AbstractApplicationContext##prepareBeanFactory(ConfigurableListableBeanFactory beanFactory)beanFactory的准备工作,对各种属性进行填充

prepareBeanFactory准备工作

protected void prepareBeanFactory(ConfigurableListableBeanFactory beanFactory) {// 添加beanPostProcessor,ApplicationContextAwareProcessor此类用来完成某些Aware对象的注入beanFactory.addBeanPostProcessor(new ApplicationContextAwareProcessor(this));// 设置要忽略自动装配的接口,很多同学理解不了为什么此处要对这些接口进行忽略,原因非常简单,这些接口的实现是由容器通过set方法进行注入的,// 所以在使用autowire进行注入的时候需要将这些接口进行忽略beanFactory.ignoreDependencyInterface(EnvironmentAware.class);beanFactory.ignoreDependencyInterface(EmbeddedValueResolverAware.class);beanFactory.ignoreDependencyInterface(ResourceLoaderAware.class);beanFactory.ignoreDependencyInterface(ApplicationEventPublisherAware.class);beanFactory.ignoreDependencyInterface(MessageSourceAware.class);beanFactory.ignoreDependencyInterface(ApplicationContextAware.class);}

看下ApplicationContextAwareProcessor这个类:

/*** 接口beanPostProcessor规定的方法,会在bean创建时,实例化后,初始化前,对bean对象应用* @param bean the new bean instance* @param beanName the name of the bean* @return* @throws BeansException*/@Override@Nullablepublic Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {if (!(bean instanceof EnvironmentAware || bean instanceof EmbeddedValueResolverAware ||bean instanceof ResourceLoaderAware || bean instanceof ApplicationEventPublisherAware ||bean instanceof MessageSourceAware || bean instanceof ApplicationContextAware)){return bean;}AccessControlContext acc = null;if (System.getSecurityManager() != null) {acc = this.applicationContext.getBeanFactory().getAccessControlContext();}if (acc != null) {AccessController.doPrivileged((PrivilegedAction<Object>) () -> {// 检测bean上是否实现了某个aware接口,有的话进行相关的调用invokeAwareInterfaces(bean);return null;}, acc);}else {invokeAwareInterfaces(bean);}return bean;}

在这个类postProcessBeforeInitialization(Object bean, String beanName)这个方法内部会调用invokeAwareInterfaces(Object bean) 这个方法,判断bean的类型是属于哪一个xxxAware接口然后执行对应的setXXX()方法,至此和前边实现ApplicationContextAware接口重写setApplicationContext()方法串起来了,在哪里调用setApplicationContext方法完成。

/*** 如果某个bean实现了某个aware接口,给指定的bean设置相应的属性值** @param bean*/private void invokeAwareInterfaces(Object bean) {if (bean instanceof EnvironmentAware) {((EnvironmentAware) bean).setEnvironment(this.applicationContext.getEnvironment());}if (bean instanceof EmbeddedValueResolverAware) {((EmbeddedValueResolverAware) bean).setEmbeddedValueResolver(this.embeddedValueResolver);}if (bean instanceof ResourceLoaderAware) {((ResourceLoaderAware) bean).setResourceLoader(this.applicationContext);}if (bean instanceof ApplicationEventPublisherAware) {((ApplicationEventPublisherAware) bean).setApplicationEventPublisher(this.applicationContext);}if (bean instanceof MessageSourceAware) {((MessageSourceAware) bean).setMessageSource(this.applicationContext);}if (bean instanceof ApplicationContextAware) {((ApplicationContextAware) bean).setApplicationContext(this.applicationContext);}}

还有一个问题,ApplicationContextAwareProcessor这个类的postProcessBeforeInitialization(Object bean, String beanName) 方法什么时候在哪里进行调用呢?这个类实现了BeanPostProcessor这个接口

/*** bean的后置处理器接口,在依赖注入的初始化方法前后进行调用*/
public interface BeanPostProcessor {/*** 初始化方法调用前要进行的处理逻辑*/@Nullabledefault Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {return bean;}/*** 在初始化方法指定后要进行的处理逻辑*/@Nullabledefault Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {return bean;}}

接下来看实现了BeanPostProcessor 这个接口的实现类在哪里会被触发调用里面的postProcessBeforeInitialization方法!!!!
通过看调用链路,下面是整个过程是在完成实例化,属性填充,执行初始化的时候在initializeBean方法调用 applyBeanPostProcessorsBeforeInitialization(wrappedBean, beanName);
在这里插入图片描述
applyBeanPostProcessorsBeforeInitialization细节,对实现BeanPostProcessor 的类进行调用postProcessBeforeInitialization这个方法,这里会调用到ApplicationContextAwareProcessor的postProcessBeforeInitialization方法来对invokeAwareInterfaces实现Aware接口的类进行set操作

	public Object applyBeanPostProcessorsBeforeInitialization(Object existingBean, String beanName)throws BeansException {//初始化返回结果为existingBeanObject result = existingBean;//遍历 该工厂创建的bean的BeanPostProcessors列表for (BeanPostProcessor processor : getBeanPostProcessors()) {// postProcessBeforeInitialization:在任何Bean初始化回调之前(如初始化Bean的afterPropertiesSet或自定义的init方法)// 将此BeanPostProcessor 应用到给定的新Bean实例。Bean已经填充了属性值。返回的Bean实例可能时原始Bean的包装器。// 默认实现按原样返回给定的 BeanObject current = processor.postProcessBeforeInitialization(result, beanName);// 如果 current为nullif (current == null) {//直接返回result,中断其后续的BeanPostProcessor处理return result;}//让result引用processor的返回结果,使其经过所有BeanPostProcess对象的后置处理的层层包装result = current;}//返回经过所有BeanPostProcess对象的后置处理的层层包装后的resultreturn result;}

同时,在完成实例化,属性填充,执行初始化的时候在initializeBean方法调用 applyBeanPostProcessorsAfterInitialization(wrappedBean, beanName);将BeanPostProcessors应用到给定的现有Bean实例,调用它们的postProcessAfterInitialization方法。

@Overridepublic Object applyBeanPostProcessorsAfterInitialization(Object existingBean, String beanName)throws BeansException {//初始化结果对象为result,默认引用existingBeanObject result = existingBean;//遍历该工厂创建的bean的BeanPostProcessors列表for (BeanPostProcessor processor : getBeanPostProcessors()) {//回调BeanPostProcessor#postProcessAfterInitialization来对现有的bean实例进行包装Object current = processor.postProcessAfterInitialization(result, beanName);//一般processor对不感兴趣的bean会回调直接返回result,使其能继续回调后续的BeanPostProcessor;// 但有些processor会返回null来中断其后续的BeanPostProcessor// 如果current为nullif (current == null) {//直接返回result,中断其后续的BeanPostProcessor处理return result;}//让result引用processor的返回结果,使其经过所有BeanPostProcess对象的后置处理的层层包装result = current;}//返回经过所有BeanPostProcess对象的后置处理的层层包装后的resultreturn result;}

至此,BeanPostProcessor接口的调用以及实现xxxAware的类的调用使用处理过程讲解结束

    初始化方法调用前要进行的处理逻辑default Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {return bean;}在初始化方法指定后要进行的处理逻辑default Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {return bean;}

相关文章:

Spring源码-xxxAware实现类和BeanPostProcessor接口调用过程

xxxAware实现类作用 以ApplicationContextAware接口为例 ApplicationContextAware的作用是可以方便获取Spring容器ApplicationContext&#xff0c;从而可以获取容器内的Bean package org.springframework.context;import org.springframework.beans.BeansException; import or…...

Uni-app x

uni-app x&#xff0c;是下一代 uni-app&#xff0c;是一个跨平台应用开发引擎。 uni-app x 是一个庞大的工程&#xff0c;它包括uts语言、uvue渲染引擎、uni的组件和API、以及扩展机制。 uts是一门类ts的、跨平台的、新语言。uts在iOS端编译为swift、在Android端编译为kotli…...

Python 基础:文件

目录 一、从文件中读取数据1.1 读取整个文件1.2 逐行读取 二、写入文件2.1 写入空文件2.2 写入多行2.3 附加到文件 遇到看不明白的地方&#xff0c;欢迎在评论中留言呐&#xff0c;一起讨论&#xff0c;一起进步&#xff01; 本文参考&#xff1a;《Python编程&#xff1a;从入…...

WebForms 母版页

WebForms 母版页 介绍 WebForms 母版页是 ASP.NET WebForms 应用程序中的一项功能&#xff0c;它允许开发人员创建一个包含页面布局和控件的模板&#xff0c;其他页面可以继承这个模板。使用母版页可以确保整个网站的一致性和减少重复代码。 如何创建母版页 在 Visual Stud…...

Java应用打包成Docker镜像

# 使用官方的OpenJDK17镜像作为基础镜像 FROM openjdk:17 # 设置工作目录 WORKDIR /app # 复制本地的Java应用程序文件到镜像中的指定目录 COPY target/bear-module-system-0.0.1-SNAPSHOT.jar /app/bear-module-system-0.0.1-SNAPSHOT.jar # 暴露API端口 EXPOSE 8888 …...

什么是自动驾驶中的CopyCat?

"CopyCat"这个词通常有两个含义: 字面意思:它可以指一个模仿别人的人,就像猫一样模仿其他猫的行为。在日常用语中,如果有人说某人是个"copycat",他们可能是在说这个人缺乏原创性,总是模仿别人的想法、风格或者行为。 心理学和犯罪学中的含义:在心…...

为什么没人详细说过智能猫砂盆?最受欢迎的好用智能猫砂盆解析!

不知道大家有没有发现&#xff0c;在快节奏的现代生活中&#xff0c;忙碌于上班的我们会发现自己越来越难以抽出足够的时间去细心照料自己的猫咪。每次下班回家&#xff0c;看到猫砂盆里堆积的粪便和尿液&#xff0c;自己都感到一阵头痛。这时&#xff0c;我开始考虑起智能猫砂…...

AI视频智能监管赋能城市管理:打造安全有序的城市环境

一、方案背景 随着城市化进程的加速和科技的飞速发展&#xff0c;街道治安问题日益凸显&#xff0c;治安监控成为维护社会稳定和保障人民安全的重要手段。当前&#xff0c;许多城市已经建立了较为完善的治安监控体系&#xff0c;但仍存在一些问题。例如&#xff0c;监控设备分…...

多态性(Java)

本篇学习面向对象语言的第三个特性——多态。 目录 1、多态的概念 2、继承多态实现条件 3、重写 4、重新与重载的区别&#xff1a; 5、向上转移和向下转型 5、1向上转型&#xff1a; 5、2 向下转型 1、多态的概念 多态的概念&#xff1a;通俗来说&#xff0c;就是多种形态…...

国际期货行情相关术语

1&#xff09;合约&#xff1a;期货行情表提供了期货交易的相关信息 &#xff0c;行情表中每一个期货合约都有合约代码&#xff08;由期货合约交易代码和合约到期月份组成&#xff09;来标识。 &#xff08;2&#xff09;开盘价&#xff1a;当日某一期货合约交易开始前五分钟集…...

LeetCode20.有效的括号

题目描述 分析 我们刚上来的思路可能是&#xff1a;找出这三种括号的个数 如果都是偶数 说明匹配 但是这里还有一个顺序问题 比如 " )( "这样是不匹配的&#xff01; 所以这种思路不可取&#xff01; 我们想 如果遇到左括号&#xff0c;把他读到一个顺序表中&#…...

尚玩助手广告变现app开发

尚玩助手广告变现app的开发涉及到多个关键环节。首先&#xff0c;市场调研与定位是不可或缺的步骤&#xff0c;通过了解当前市场上流行的小游戏类型、用户偏好以及竞争对手的情况&#xff0c;来确定app的定位和目标用户群体。 其次&#xff0c;游戏设计与规划也是关键的一环&a…...

Anti-human IL-10 mAb (12G8), biotin:Mabtech热销品

Anti-human IL-10 mAb (12G8), biotin该单克隆抗体能够在ELISpot、FluoroSpot和ELISA等免疫分析方法中特异性检测人白介素10&#xff08;IL-10&#xff09;。可以将该单克隆抗体12G8作为检测抗体与单克隆抗体9D7&#xff08;ca#3430-3&#xff09;作为捕获抗体配对用于ELISpot、…...

【植物大战僵尸杂交版】致敬传奇游戏玩家——一个普通人的六年坚持

目录 缘起 波澜 凌云 缘起 曾​​​​​​佳伟是《植物大战僵尸》的忠实粉丝&#xff0c;这款游戏给了他很多乐趣&#xff0c;也成为了他度过困难时期的精神支柱。他决定制作杂交版&#xff0c;部分原因是出于对原版游戏的热爱和致敬。 六年前&#xff0c;出于对一些pvz续作…...

【2024最新华为OD-C/D卷试题汇总】[支持在线评测] 部门组队编程(200分) - 三语言AC题解(Python/Java/Cpp)

&#x1f36d; 大家好这里是清隆学长 &#xff0c;一枚热爱算法的程序员 ✨ 本系列打算持续跟新华为OD-C/D卷的三语言AC题解 &#x1f4bb; ACM银牌&#x1f948;| 多次AK大厂笔试 &#xff5c; 编程一对一辅导 &#x1f44f; 感谢大家的订阅➕ 和 喜欢&#x1f497; &#x1f…...

民生银行信用卡中心金融科技24届春招面经

本文介绍2024届春招中&#xff0c;中国民生银行下属信用卡中心的金融科技&#xff08;系统研发方向&#xff09; 岗位2场面试的基本情况、提问问题等。 2024年04月投递了中国民生银行下属信用卡中心的金融科技&#xff08;系统研发方向&#xff09; 岗位&#xff0c;暂时不清楚…...

HTML李峋同款跳动的爱心代码(双爱心版)

目录 写在前面 跳动的爱心 完整代码 代码分析 系列推荐 最后想说 写在前面 在浩瀚的网络世界中&#xff0c;总有一些小惊喜能触动我们的心弦。今天&#xff0c;就让我们用HTML语言&#xff0c;探索既神秘又浪漫的李峋同款跳动的爱心代码吧。 首先&#xff0c;让我们一起…...

【linux】内核从tcp层调用IP层摸索中

合入代码&#xff1a; 登录 - Gitee.comhttps://gitee.com/r77683962/linux-6.9.0/commit/f5a93955e16d148a70f98e0f300f455b3ab594f3 这是运行日志&#xff1a; https://gitee.com/r77683962/linux-6.9.0/raw/master/test_log/kern_tcp_ip.log 日志截取部分&#xff08;也…...

Python 中的 Pandas(数据分析与处理)

Pandas 是 Python 中最受欢迎的数据处理库之一&#xff0c;其名字源自于“Panel Data”&#xff08;面板数据&#xff09;的缩写。它提供了三种主要的数据结构&#xff1a;Series &#xff0c; DataFrame &#xff0c; Panel&#xff08;在新版本已经被弃用&#xff09; 数…...

【文档智能 RAG】RAG增强之路-智能文档解析关键技术难点及PDF解析工具PDFlux

前言 在私域知识问答和企业知识工程领域&#xff0c;结合Retrieval-Augmented Generation&#xff08;RAG&#xff09;模型和大型语言模型&#xff08;LLM&#xff09;已成为主流方法。然而&#xff0c;企业中存在着大量的PDF文件&#xff0c;PDF解析的低准确性显著影响了基于…...

边缘计算医疗风险自查APP开发方案

核心目标:在便携设备(智能手表/家用检测仪)部署轻量化疾病预测模型,实现低延迟、隐私安全的实时健康风险评估。 一、技术架构设计 #mermaid-svg-iuNaeeLK2YoFKfao {font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;fill:#333;}#mermaid-svg…...

FFmpeg 低延迟同屏方案

引言 在实时互动需求激增的当下&#xff0c;无论是在线教育中的师生同屏演示、远程办公的屏幕共享协作&#xff0c;还是游戏直播的画面实时传输&#xff0c;低延迟同屏已成为保障用户体验的核心指标。FFmpeg 作为一款功能强大的多媒体框架&#xff0c;凭借其灵活的编解码、数据…...

el-switch文字内置

el-switch文字内置 效果 vue <div style"color:#ffffff;font-size:14px;float:left;margin-bottom:5px;margin-right:5px;">自动加载</div> <el-switch v-model"value" active-color"#3E99FB" inactive-color"#DCDFE6"…...

什么是EULA和DPA

文章目录 EULA&#xff08;End User License Agreement&#xff09;DPA&#xff08;Data Protection Agreement&#xff09;一、定义与背景二、核心内容三、法律效力与责任四、实际应用与意义 EULA&#xff08;End User License Agreement&#xff09; 定义&#xff1a; EULA即…...

三体问题详解

从物理学角度&#xff0c;三体问题之所以不稳定&#xff0c;是因为三个天体在万有引力作用下相互作用&#xff0c;形成一个非线性耦合系统。我们可以从牛顿经典力学出发&#xff0c;列出具体的运动方程&#xff0c;并说明为何这个系统本质上是混沌的&#xff0c;无法得到一般解…...

【p2p、分布式,区块链笔记 MESH】Bluetooth蓝牙通信 BLE Mesh协议的拓扑结构 定向转发机制

目录 节点的功能承载层&#xff08;GATT/Adv&#xff09;局限性&#xff1a; 拓扑关系定向转发机制定向转发意义 CG 节点的功能 节点的功能由节点支持的特性和功能决定。所有节点都能够发送和接收网格消息。节点还可以选择支持一个或多个附加功能&#xff0c;如 Configuration …...

LOOI机器人的技术实现解析:从手势识别到边缘检测

LOOI机器人作为一款创新的AI硬件产品&#xff0c;通过将智能手机转变为具有情感交互能力的桌面机器人&#xff0c;展示了前沿AI技术与传统硬件设计的完美结合。作为AI与玩具领域的专家&#xff0c;我将全面解析LOOI的技术实现架构&#xff0c;特别是其手势识别、物体识别和环境…...

ubuntu22.04有线网络无法连接,图标也没了

今天突然无法有线网络无法连接任何设备&#xff0c;并且图标都没了 错误案例 往上一顿搜索&#xff0c;试了很多博客都不行&#xff0c;比如 Ubuntu22.04右上角网络图标消失 最后解决的办法 下载网卡驱动&#xff0c;重新安装 操作步骤 查看自己网卡的型号 lspci | gre…...

从物理机到云原生:全面解析计算虚拟化技术的演进与应用

前言&#xff1a;我的虚拟化技术探索之旅 我最早接触"虚拟机"的概念是从Java开始的——JVM&#xff08;Java Virtual Machine&#xff09;让"一次编写&#xff0c;到处运行"成为可能。这个软件层面的虚拟化让我着迷&#xff0c;但直到后来接触VMware和Doc…...

【WebSocket】SpringBoot项目中使用WebSocket

1. 导入坐标 如果springboot父工程没有加入websocket的起步依赖&#xff0c;添加它的坐标的时候需要带上版本号。 <dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-websocket</artifactId> </dep…...