生命周期BeanPostProcessor(3)---Spring源码从入门到精通(九)

2023-11-15

上篇文章主要介绍了Bean生命周期,bean生命周期:创建bean--->初始化init--->销毁destory,而初始化和销毁是可以用@Bean指定的,或者用@PostCoustruct@preDestory注解,或者用InitializingBean和DisposableBean接口都能指定调用的初始化和销毁方法:

Bean生命周期(2)---Spring源码从入门到精通(八)

这篇主要介绍BeanPostProcessor,在spring框架非常重要,里面有两个接口,一个是postProcessBeforeInitialization 和 postProcessAfterInitialization两个方法,顾名思义,前者在类初始化前调用,后者在类初始化之后调用。

下面主要分为三个部分:

1、BeanPostProcessor实用。

2、BeanPostProcessor源码解析。

3、Spring底层使用BeanPostProcessor。

1、BeanPostProcessor实用

先自定义类MyBeanPostProcessor实现接口,会重写里面的两个方法,可以打印出当前初始化的类。


/**
 * 自定义类实现beanPostProcessor接口,两个重写的方法在bean初始化前后调用。
 *
 * 初始化之前用populateBean()方法,给bean属性赋值
 * 初始化开始:
 * 「
 * applyBeanPostProcessorsBeforeInitialization()初始化之前调用的方法 , 接口BeanPostProcessor
 * invokeInitMethods()方法初始化 ,执行bean初始化
 * applyBeanPostProcessorsAfterInitialization()初始化之后调用的方法 , 接口BeanPostProcessor
 * 」
 *
 * @author keying
 */
@Component
public class MyBeanPostProcessor implements BeanPostProcessor {
    public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
        System.out.println(
            "postProcessBeforeInitialization.....Before..." + bean.getClass() + ",【beanName】=" + beanName);
        return bean;
    }

    public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
        System.out.println(
            "postProcessAfterInitialization.....After..." + bean.getClass() + ",【beanName】=" + beanName);
        return bean;
    }
}

junitTest还和上篇文章一样不变,直接运行,为了方便理解,再贴一遍:

 @Test
    public void test() {
        AnnotationConfigApplicationContext annotationConfigApplicationContext = new AnnotationConfigApplicationContext(
            ConfigLifeCycle.class);
        System.out.println("容器创建完毕");
        //多实例情况下,需要获取组件,才会初始化,并且不会销毁
        //Object carObject = annotationConfigApplicationContext.getBean("car");

        //getDefinitionNames(annotationConfigApplicationContext);
        annotationConfigApplicationContext.close();
    }

控制台打印如下,我们创建的三个bean在初始化的前后都会打印:

2、BeanPostProcessor源码解析。

1、刚开始AnnotationConfigApplicationContext主要调用refresh()方法

2、点进去之后,refresh主要调用finishBeanFactoryInitialization方法,初始化所有单实例对象        3、点进去之后,调用下图的beanFactory.preInstantiateSingletons方法

4、初始化单实例 bean之后,点进去此方法,可以看到getBean方法5、点进getBean之后,可以看到下图方法,获取单实例,若获取不到,就会createBean创建对象并且返回。6、createBean里有个doCreateBean,点进此方法,里面有个populateBean方法作用是在初始化对象之前,给bean注入信息,bean名,工厂名,之后下面的initializeBean方法,后面的方法就是处理器的调用。

7、点进initializaBean方法可以看到,里面有三个方法,中间invokeInitMethods方法就是初始化bean,applyBeanPostProcessorsBeforeInitialization方法为初始化之前调用的,applyBeanPostProcessorsAfterInitialization方法为初始化之后调用的。8、点击applyBeanPostProcessorsBeforeInitialization方法,进入可以看到,遍历获取容器所有的beanPostProcessors,挨个执行beforeInitialization若返回为 null,则跳出for循环,不会执行后面的postBeforeBeforeInitialization方法。        

3、Spring底层使用BeanPostProcessor

可以传递ApplicationContext对象,用bean实现ApplicationContextAware方法,代码如下:

@Component
public class Cat implements ApplicationContextAware {

    private ApplicationContext applicationContext;

    public Cat(){
        System.out.println("Cat...construct");
    }

    /**
     * construct 构造函数创建对象之后执行
     */
    @PostConstruct
    public void init(){
        System.out.println("cat ...PostConstruct.");
    }

    /**
     * 销毁之前调用
     */
    @PreDestroy
    public void destory(){
        System.out.println("cat ...PreDestroy");
    }

    public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
        this.applicationContext = applicationContext;
    }
}

源码如下,ApplicationContextAwareProcessor类就是集成了此接口,里面可以设置代码里的ApplicationContext。

BeanValidationPostProcessor类,作用在bean初始化前后进行效验,源码如下。

public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
        if (!this.afterInitialization) {
            this.doValidate(bean);
        }

        return bean;
    }

    public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
        if (this.afterInitialization) {
            this.doValidate(bean);
        }

        return bean;
    }

之前用的@PostConstruct,和@PreDestroy注解也是因为BeanPostProcessor才运行的,在InitDestroyAnnotationBeanPostProcessor类里,调用invokeInitMethods方法点进invokeInitmethods方法可以看到,会用反射调用element.invoke方法,找到对应的bean。

还有AutowiredAnnotationBeanPostProcessor类,就是在对象创建完之后,处理@Autowired注解获取到bean对象。

所有@Bean注入对象,其他方法注入组件,@Autowired,生命周期注解,@Async异步注解等等,都是基本BeanPostProcessor接口实现的。

简单总结:spring生命周期,主要为bean创建--->init初始化--->销毁,

单实例在容器加载完毕前,创建和初始化,多实例在获取bean的时候才会创建bean和初始化。@Bean注释可以指定init-method和destory-method来初始化和销毁,@PostConstruct注解和接口也可以实现,这些都基于BeanPostRrocessor接口,控制生命周期,并且实现此接口,可以在bean初始化前后处理事务。

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

生命周期BeanPostProcessor(3)---Spring源码从入门到精通(九) 的相关文章

  • 如何在谷歌地图中使用latlng字符串数组绘制多边形

    在我的应用程序中 我有包含 imagview 的 recyclerview 并且该 imageview 通过使用我存储在 sqlite 中的坐标包含静态地图图像 当我单击该图像时 我将该字符串数组格式的坐标传递给其他地图活动 然后使用该字符
  • Junit Mockito 测试一切

    我现在正在寻找更多时间但没有结果 请帮忙 这是我要测试的课程 public class DBSelectSchema extends Database private static final Logger LOG Logger getLo
  • 为什么 hibernate 在一张表中保存两个 @OneToMany 列表?

    想象一下使用 Hibernate 和 JPA 的简化代码如下 Entity class C Id GeneratedValue public long id MappedSuperclass abstract class A Id Gene
  • 使用 google-api-java-client 的 2 足 OAuth

    有谁知道如何将 2 legged OAuth 与 google api java client 一起使用 我正在尝试访问 Google Apps 配置 API 以获取特定域的用户列表 以下不起作用 HttpTransport transpo
  • 通过 JDBC 连接到 DB2 时的用户和密码

    我正在尝试连接到本地 DB2 10 5 Express C 服务器 这是一个测试环境 所以我不关心安全性 我能够连接到命令行处理器 在 Windows 上运行 并且我更改了配置设置AUTHENTICATION CLIENT and TRUS
  • Maven 2 未运行 Junit 4 测试

    我在确保运行 Junit4 测试时遇到问题 同样的问题也被报告在https stackoverflow com questions 2021771 sort newest sort top https stackoverflow com q
  • 如何让 HttpClient 返回状态码和响应正文?

    我试图让 Apache HttpClient 触发 HTTP 请求 然后显示 HTTP 响应代码 200 404 500 等 以及 HTTP 响应正文 文本字符串 重要的是要注意我正在使用v4 2 2因为大多数 HttpClient 示例都
  • 在 SWT 中单击鼠标触发事件?

    在SWT中 对于MouseListener接口 可用的方法有mouseUp mouseDown and mouseDoubleClick 如何根据用户点击触发事件 我们可以通过结合来做到这一点mouseUp and mouseDown 但没
  • 如何知道 glassfish 是什么 - 完整平台或网络配置文件?

    我已经安装了glassfish 我可以跑 asadmin version 它显示了它是什么版本 但如何知道它是 完整平台 还是 Web 配置文件 你可以使用 glassfish4 bin gt asadmin list containers
  • 处理 ANTLR 4 中的错误

    遵循后接受的答案 https stackoverflow com a 18137301 2279200的指示处理 ANTLR4 中的错误 https stackoverflow com q 18132078 2279200问题 我遇到了以下
  • 属性文件中的字符串主机名:Java

    这听起来可能是一个非常简单的问题 但我无法找到解决方法 我有一个 config properties 文件 其中包含两个键值 IP 地址和端口号 我读取此配置文件以提取字符串格式的键值 但是 当我尝试使用这些值时 我无法连接到从配置文件中检
  • 在 JavaFX 中更改 ListView 字体大小

    我想知道如何更改 JavaFx 中的列表视图项目文本字体大小 每行文本的大小会有所不同 我尝试使用细胞因子属性 但我不知道如何使用它 有人可以帮我吗 类似的问题在这里 如何更改JavaFX中ListView的字体大小 https stack
  • 为什么java(>=7版本)不支持运行没有main方法的程序? [关闭]

    Closed 这个问题是无法重现或由拼写错误引起 help closed questions 目前不接受答案 class WithoutMain static System out println Without main class Sy
  • 读取不失真的灰度 PNG 图像文件

    我需要读取和处理大量的灰度 PNG 文件 我的意思是 如果它们在 Photoshop 或 GIMP 中打开 则图像模式为灰度 而不是具有灰度值的 RGB 图像 ImageIO 似乎没有实现这一点 它似乎将所有图像文件视为 sRGB 这会破坏
  • Elasticsearch NodeBuilder 与 TransportClient

    对于其他 Elasticsearch 开发人员来说 这可能是一个非常简单 而且愚蠢 的问题 这两者之间有什么区别 我正在从 Java Web 应用程序连接到远程 Elasticsearch 服务器 到目前为止我一直在使用 Transport
  • 如何发现另一个应用程序的意图

    我正在尝试构建一个应用程序来接收来自 StumbleUpon 应用程序的共享 此时 我可以接收浏览器的 共享网址 但是当从 StumbleUpon 共享时 我的应用程序不会显示在列表中 我想我可能没有在清单中注册正确的意图 有什么方法可以找
  • 将字符串转换为字符并按降序排序(ascii)

    我正在创建一个程序 该程序将使用户输入整数 一个接一个 存储在数组中并按降序显示整数 该程序还要求用户输入一个字符串 使用以下命令将其转换为字符string toCharArray 我已经正确地按降序显示整数 问题是我不知道如何按降序显示字
  • logcat 信息出现在 Android Studio 的“运行”选项卡中

    我的 android studio 运行选项卡很简单 然后它变得更难并给我更多信息 例如 logcat 中的信息 如何禁用或删除第二张图片中出现的更多信息并返回到第一张图片中的第一个外观 我只需要正在运行的 flutter 应用程序的日志输
  • Java 应用程序启动,ProcessBuilder 一段时间后被阻止

    我正在开发一个 Java 桌面应用程序 我们称之为控制台 包含 3 个按钮 其中两个启动 Win32 应用程序 第三个应该启动一个可执行的 jar ProcessBuilder pb new ProcessBuilder java jar
  • 将 JSON 发送到 Spring MVC 控制器

    我正在尝试将 JSON 发送到 Spring MVC 控制器 在 Spring MVC 方面 一切都配置正确 下面是代码 但似乎没有运行

随机推荐

  • Unity实现鼠标点击指定位置导航角色

    实现目标 使用组件 一个场地 导航代理 摄像机 实现 进入游戏 鼠标左键点击场景的任意位置 导航代理将自动前往指向位置 步骤 首先我们需要一个场景 新建一平面作为场景地面 如果需要额外的障碍物则自己设置 这里不额外添加 然后在平面上放置一胶
  • Kubernetes(k8s)读记(一)

    Kubernetes 概述 Kubernetes 源于希腊语 意为 舵手 或 飞行员 k8s 这个缩写是因为 k 和 s 之间有八个字符的关系 Google 在 2014 年开源了 Kubernetes 项目 开源 用于管理云平台中多个主机
  • RabbitMQ-死信队列

    文章目录 前言 简介 使用Java代码创建和配置死信队列 死信队列的优缺点 总结 前言 当涉及到处理消息队列中无法正常消费的消息时 RabbitMQ的死信队列 Dead Letter Queue DLQ 是一个关键概念 在这篇博客中 我们将
  • 个人买保险扫盲

    1 购买保险原则总结 一般人都是有医保的 小孩也可以去社区买 这个是最基础的保障 一定要买 推荐的商业保险顺序 意外险 医疗险 gt 重疾险 gt 定期寿险 然后再是其他种类的保险等 意外和重大疾病是最有可能突然需要大笔资金花费的 对于普通
  • 图像识别中——目标分割、目标识别、目标检测和目标跟踪的区别

    计算机视觉旨在识别和理解图像 视频中的内容 包含四大基本任务 分类 图a 定位 检测 图b 语义分割 图c 和实例分割 图d 这四个任务需要对图像的理解逐步深入 给定一张输入图像 图像分类任务旨在判断该图像所属类别 目标定位是在图像分类的基
  • WebLogic Server 远程代码执行漏洞复现 (CVE-2023-21839)

    1 产品简介 Oracle WebLogic Server是一个统一的可扩展平台 用于在本地和云端开发 部署和运行企业应用程序 例如 Java WebLogic Server提供了Java Enterprise Edition EE 和Ja
  • Chatgpt介绍及搭建步骤

    ChatGPT是一个基于自然语言处理技术的聊天机器人 它使用了深度学习和语义分析技术 可以与用户进行自然 流畅的对话 ChatGPT可以回答各种问题 包括常见问题 娱乐 健康 技术 旅游 金融等领域 ChatGPT的核心技术是GPT Gen
  • java用正则表达式脱敏手机号

    一种正则形式 在Java开发中有时候需要对敏感字段数据脱敏 废话不多说 直接上代码 脱敏手机号 param str return 脱敏后字符串 public static String maskPhone String str return
  • Java变量的作用域:静态变量、全局变量和局部变量

    变量的作用域规定了变量所能使用的范围 只有在作用域范围内变量才能被使用 根据变量声明地点的不同 变量的作用域也不同 根据作用域的不同 一般将变量分为不同的类型 成员变量和局部变量 下面对这几种变量进行详细说明 成员变量 Java 的成员变量
  • Linux环境下PostgreSQL9.6+PostGIS2.5安装

    空间数据库原理上机实习要用 安了好久终于成功辽 由于在腾讯云上买好了服务器 所以直接远程登录了 一 PostgreSQL安装 1 导入yum源 sudo yum install y https download postgresql org
  • C++实现定时器

    定时器的主要数据 1 一个线程变量 保存定时器线程 2 一个互斥锁 配合条件变量使用 3 一个条件变量 结合互斥锁 可以是线程不执行任务时 睡眠一段时间 在退出调用时 可以唤醒线程完成退出 4 定时执行函数 具体的定时执行业务操作 5 间隔
  • 1核2G/2核4G的服务器centos安装哪个版本

    虽然目前的centos 8系统将会在今年停止更新维护 所以很多人担心和纠结该选择什么系统作为自己的服务器系统呢 不管是服务器是计算型共享型还是通用型服务器配置 都可以选择centos 8 x 具体关于通用型计算型和共享型服务器的介绍可以参考
  • python读取oracle数据库数据报编码错误

    UnicodeDecodeError gbk codec can t decode byte 0xa7 in position 2 illegal multibyte sequence 解决方法 根据数据库不同的编码设定 编写的python
  • webview中h5高德定位没有权限的问题Geolocation permission Denied

    网上都是说添加这两个东西 settings setDatabaseEnabled true settings setDomStorageEnabled true mWebView setWebChromeClient new WebChro
  • 02-工厂模式

    文章目录 1 简单工厂模式 2 工厂方法模式 3 抽象工厂模式 4 模式扩展 5 工厂模式在JDK中的应用 需求 设计一个咖啡店点餐系统 设计一个咖啡类 Coffee 并定义其两个子类 美式咖啡 AmericanCoffee 和拿铁咖啡 L
  • qt5中信号和槽连接,对于多种参数重载的处理

    因为QSpinBox的valueChanged信号有重载 为避免二义性 需要通过声明函数指针方式 来进行信号和槽的连接 void QSpinBox p int QSpinBox valueChanged 函数指针p前要加类名作用域符号 co
  • 假设u~N(0, 1), X

    假设 N 0 1 X
  • API HOOK

    本来这个方法是API HOOK中经常用到 但是我想试试在单个程序中实现 为何运行时总是错误 本来是一个函数跳另外一个的 我又后退了一步 只是用一个函数自己的前面8字节修改自己 还是会错误了 void CJmpDlg OnButton1 对应
  • JDBC 连接池配置文件 解决了already close问题

    XML文件 DataSource配置
  • 生命周期BeanPostProcessor(3)---Spring源码从入门到精通(九)

    上篇文章主要介绍了Bean生命周期 bean生命周期 创建bean gt 初始化init gt 销毁destory 而初始化和销毁是可以用 Bean指定的 或者用 PostCoustruct preDestory注解 或者用Initiali