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;}

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.rhkb.cn/news/353996.html

如若内容造成侵权/违法违规/事实不符,请联系长河编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

RK3588 Android12音频驱动分析全网最全

最近没有搞音频相关的了&#xff0c;在搞BMS, 把之前的经验总结一下。 一、先看一下Android 12音频总架构 从这张图可以看到音频数据流一共经过了3个用户空间层的进程&#xff0c;然后才流到kernel驱动层。Android版本越高&#xff0c;通用性越高&#xff0c;耦合性越低&#…

hdfs文件系统增删查原理

目录 1、hdfs读取文件原理 1.1、读取流程图解 1.2、架构层面读取流程详解 1.3、源码层面读取流程详解 2、hdfs写入文件原理 2.1、写入流程图解 2.2、架构层面写入流程 2.3、源码层面写入流程 3、hdfs删除文件原理 3.1、删除文件图解 3.2、架构层面删除流程 3.3、源码…

【Java】已解决java.lang.UnsupportedOperationException异常

文章目录 问题背景可能出错的原因错误代码示例正确代码示例注意事项 已解决java.lang.UnsupportedOperationException异常 在Java编程中&#xff0c;java.lang.UnsupportedOperationException是一个运行时异常&#xff0c;通常表示尝试执行一个不支持的操作。这种异常经常发生…

Word2Vec基本实践

系列文章目录 提示&#xff1a;这里可以添加系列文章的所有文章的目录&#xff0c;目录需要自己手动添加 例如&#xff1a;第一章 Python 机器学习入门之pandas的使用 提示&#xff1a;写完文章后&#xff0c;目录可以自动生成&#xff0c;如何生成可参考右边的帮助文档 文章目…

MATLAB入门知识

目录 原教程链接&#xff1a;数学建模清风老师《MATLAB教程新手入门篇》https://www.bilibili.com/video/BV1dN4y1Q7Kt/ 前言 历史记录 脚本文件&#xff08;.m&#xff09; Matlab帮助系统 注释 ans pi inf无穷大 -inf负无穷大 i j虚数单位 eps浮点相对精度 0/&a…

【AI】通义千问使用指南:让你快速上手,成为问题解决高手!

大家好&#xff0c;我是木头左。 近日&#xff0c;继文心一言和讯飞星火之后&#xff0c;阿里虽迟但到&#xff0c;直接宣布开源两款“通义千问”大模型。作为国内首个开源且可商用的人工智能大模型&#xff0c;这会给我们带来哪些变化呢&#xff1f; 如何申请阿里通义千问&am…

JupyterLab使用指南(六):JupyterLab的 Widget 控件

1. 什么是 Widget 控件 JupyterLab 中的 Widget 控件是一种交互式的小部件&#xff0c;可以用于创建动态的、响应用户输入的界面。通过使用 ipywidgets 库&#xff0c;用户可以在 Jupyter notebook 中创建滑块、按钮、文本框、选择器等控件&#xff0c;从而实现数据的交互式展…

springboot集成积木报表,怎么将平台用户信息传递到积木报表

springboot集成积木报表后怎么将平台用户信息传递到积木报表 起因是因为需要研究在积木报表做数据筛选的时候需要拿到系统当前登录用户信息做筛选新的模块 起因是因为需要研究在积木报表做数据筛选的时候需要拿到系统当前登录用户信息做筛选 官网有详细介绍怎么集成进去的&…

力扣每日一题 6/19 排序+动态规划

博客主页&#xff1a;誓则盟约系列专栏&#xff1a;IT竞赛 专栏关注博主&#xff0c;后期持续更新系列文章如果有错误感谢请大家批评指出&#xff0c;及时修改感谢大家点赞&#x1f44d;收藏⭐评论✍ 2713.矩阵中严格递增的单元格数【困难】 题目&#xff1a; 给你一个下标从…

爆赞!GitHub首本Python开发实战背记手册,标星果然百万名不虚传

Python (发音:[ paiθ(ə) n; (US) paiθɔn ] n. 蟒蛇&#xff0c;巨蛇 )&#xff0c;是一种面向对象的解释性的计算机程序设计语言&#xff0c;也是一种功能强大而完善的通用型语言&#xff0c;已经具有十多年的发展历史&#xff0c;成熟且稳定。Python 具有脚本语言中最丰富…

无问芯穹Qllm-Eval:制作多模型、多参数、多维度的量化方案

前言 近年来&#xff0c;大语言模型&#xff08;Large Models, LLMs&#xff09;受到学术界和工业界的广泛关注&#xff0c;得益于其在各种语言生成任务上的出色表现&#xff0c;大语言模型推动了各种人工智能应用&#xff08;例如ChatGPT、Copilot等&#xff09;的发展。然而…

list集合自定义排序

一、基本类型排序 1.list中只有数字或字符串 //升序排序 List<T> ,T为数字或字符串 Collections.sort(list); //降序排序 Collections.sort(list,Collections.reverseOrder());2.list中为对象 基于jdk.18 import lombok.Data;Data public class User {private int i…

Android网络性能监控方案 android线上性能监测

1 Handler消息机制 这里我不会完整的从Handler源码来分析Android的消息体系&#xff0c;而是从Handler自身的特性引申出线上卡顿监控的策略方案。 1.1 方案确认 首先当我们启动一个App的时候&#xff0c;是由AMS通知zygote进程fork出主进程&#xff0c;其中主进程的入口就是Ac…

linux环境编程基础学习

Shell编程&#xff1a; 相对的chmod -x xx.sh可以移除权限 想获取变量的值要掏点dollar&#xff08;&#xff04;&#xff09; 多位的话要加个花括号 运算&#xff1a;expr 运算时左右两边必须要加空格 *号多个含义必须加转义符 双引号可以加反单&#xff0c;但是发过来就不行 …

【2024最新华为OD-C/D卷试题汇总】[支持在线评测] LYA 的幸运游戏(100分) - 三语言AC题解(Python/Java/Cpp)

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

Idea连接GitLab的过程以及创建在gitlab中创建用户和群组

上期讲述了如何部署GitLab以及修复bug&#xff0c;这期我们讲述&#xff0c;如何连接idea。 首先安装gitlab插件 下载安装idea上并重启 配置ssh免密登录 使用管理员打开命令行输入&#xff1a;ssh-keygen -t rsa -C xxxaaa.com 到用户目录下.ssh查看id_rsa.pub文件 打开复制…

算法第六天:力扣第977题有序数组的平方

一、977.有序数组的平方的链接与题目描述 977. 有序数组的平方的链接如下所示&#xff1a;https://leetcode.cn/problems/squares-of-a-sorted-array/description/https://leetcode.cn/problems/squares-of-a-sorted-array/description/ 给你一个按 非递减顺序 排序的整数数组…

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

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

ArcGIS for js 4.x FeatureLayer 点选查询

示例&#xff1a; 代码如下&#xff1a; <template><view class"map" id"mapView"></view></template><script setup> import "arcgis/core/assets/esri/themes/light/main.css"; import Map from "arcgis/…

没有名为 keras.preprocessing 的模块

估计是因为版本原因 我安装的是 3.3.3版本 >>> import keras >>> print(keras.__version__) 3.3.3 keras.preprocessing.image 将 keras.preprocessing.image 改为 from keras_preprocessing.image 之后报image_type啥的错误&#xff0c;后面查找之后…