Spring核心模块—— BeanFactoryPostProcessorBeanPostProcessor(后处理器)
创始人
2024-05-29 05:14:15
0

后置处理器

  • 前言
    • Spring的后处理器
    • BeanFactoryPostProcessor(工厂后处理器)
      • 执行节点
      • 作用
      • 基本信息
      • 经典场景
      • 子接口——BeanDefinitiRegistryPostProcessor
        • 基本介绍
        • 用途
        • 具体原理
        • 例子——注册BeanDefinition
        • 使用Spring的BeanFactoryPostProcessor扩展点完成自定义注解扫描
    • BeanPostPrecessor (后处理器)
        • 基本原理
        • 运用的场景
        • 经典例子——时间日志增强
      • BeanFactoryPostProcessor&&BeanPostProcessor的不同点
    • 结尾

前言

Spring的后处理器是Spring对外开发的重要扩展点,允许我们介入到Bean的整个实例化流程中来,以达到动态注册BeanDefinition,动态修改BeanDefinition,以及动态修改Bean的作用。
如果你不太清楚BeanDefinition是干嘛的,推进你看看我写的另外一篇文章,相信可以帮助到你:Spring核心模块解析—BeanDifinition。

Spring的后处理器

Sping的后处理器是Spring对外开发的重要扩展点,允许我们介入到Bean的整个实例化流程中来,以达到动态注册BeanDefinition,以及动态修改Bean的作用,那么Spring主要有两种后处理器,下面我们分别进行介绍他们的基本概念和业务场景。希望你可以更好的理解。

BeanFactoryPostProcessor(工厂后处理器)

执行节点

在BeanDefinitDefinitionMap填充完毕,Bean实例化之前执行。

作用

1.允许我们在Spring容器加载Bean定义之后,对Bean定义进行修改,从而影响到容器中实际实例化的Bean。
2.主要用途是应用程序上下文准备就绪前,修改或添加Bean定义。
3.也可以用来执行自定义的Bean验证或Bean初始化逻辑。

基本信息

beanFactoryPostProcessor是一个接口规范,实现了该接口的类只要交由Spring容器管理的话,那么Spring就会回调该接口的方法,用于对BeanDefinition注册和修改的功能

@FunctionalInterface
public interface BeanFactoryPostProcessor {void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) throws BeansException;}

我们先来关注一下接口里面方法的参数:ConfigurableListableBeanFactory
本质来说,这个参数其实是BeanFacotry的子接口,我们看一下这层关系:

public interface ConfigurableListableBeanFactoryextends ListableBeanFactory, AutowireCapableBeanFactory, ConfigurableBeanFactory 

然后进入到ListableBeanFactory中:

public interface ListableBeanFactory extends BeanFactory 

经典场景

业务场景:配置文件中的占位符替换为实际值的情况。比如将配置文件中的数据库连接URL,用户名和密码等信息替换为实际的值。
经典用途是用它实现属性占位符的解析,通过实现BeanFactoryPostProcessor接口并重写postProcessBeanFactory(),我们使用Spring的占位符解析机制(如${…})来解析Bean定义中的属性占位符,并将其替换为实际的属性值。
下面我们来介绍一下代码实现:
1.首先在Spring配置文件中定义PropertyPlaceholderConfigurer实例,用来解析占位符。



上面的配置中,PropertyPlaceholderConfigurer实例用于解析jdbc.properties文件中的占位符。
2.实现一个BeanFactoryPostProcessor接口的实现类,用于在应用程序上下文准备就绪之前替换Bean定义中的占位符,例如:

public class PropertyPlaceholderReplacer implements BeanFactoryPostProcessor {@Overridepublic void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) throws BeansException {// 获取名为 "org.springframework.beans.factory.config.PropertyPlaceholderConfigurer#0" 的 PropertyPlaceholderConfigurer 对象// 该对象用于解析配置文件中的占位符,并将解析后的值设置回相应的 Bean 定义中PropertyPlaceholderConfigurer configurer = (PropertyPlaceholderConfigurer)beanFactory.getBean("org.springframework.beans.factory.config.PropertyPlaceholderConfigurer#0");// 获取所有的 Bean 名称String[] beanNames = beanFactory.getBeanDefinitionNames();for (String beanName : beanNames) {// 获取 Bean 的定义BeanDefinition beanDefinition = beanFactory.getBeanDefinition(beanName);// 获取 Bean 的属性值MutablePropertyValues propertyValues = beanDefinition.getPropertyValues();PropertyValue[] propertyValueArray = propertyValues.getPropertyValues();for (PropertyValue propertyValue : propertyValueArray) {Object value = propertyValue.getValue();// 如果属性值是一个字符串类型,那么就将其转换为实际的值if (value instanceof String) {// 调用 PropertyPlaceholderConfigurer 的 convertPropertyValue() 方法将占位符解析为实际的值Object convertedValue = configurer.convertPropertyValue((String) value);// 将转换后的值设置回属性值中propertyValue.setConvertedValue(convertedValue);}}}}
}

3.最后在Spring配置文件中注册PropertyPlaceholderReplacer实例,让它参与应用程序上下文创建过程:


Spring容器启动时,PropertyPlaceholderReplacer实例会被创建并自动调用postProcessBeanFactory方法,在此方法中实现占位符的解析,然后将解析后的实际值设置回相应的Bean定义中。这样,应用程序中的占位符就会被正确地替换为实际的值。

子接口——BeanDefinitiRegistryPostProcessor

基本介绍

它是Spring框架的一个扩展点,用于对Bean定义的注册过程进行干预和定制。
继承BeanFactoryPostProcessor接口,并在其基础上扩展了一个新的方法,即:postProcessBeanDefinitionRegistry()方法。

用途

在Spring容器初始化时,首先会读取应用程序中的配置文件,并解析出所有的Bean定义,然后将这些Bean定义注册到容器中。
在这个过程中,BeanDefinitionRegistryProcessor提供了一种机制,允许开发人员在Bean定义注册之前和之后对Bean定义进行自定义处理,例如添加,修改或删除Bean定义等。

具体原理

具体来说,BeanDefinitionRegistryPostProcessor提供了以下两个方法:

  1. postProcessBeanDefinitionRegistry(BeanDefinitionRegistry registry):该方法在所有Bean定义加载完成之后,Bean实例化之前被调用,允许开发人员对Bean定义进行自定义修改,例如添加,修改或删除Bean定义等。
  2. postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory): 该方法是继承自BeanFactoryPostProcessor接口的方法,用于在BeanFactory完成实例化之后对BeanFactory进行后置处理。
    那么我们通过BeanDefinitionRegistryPostProcessor接口,开发人员可以在Spring容器启动时干预Bean的注册过程,从而实现对Bean的自定义处理。
    例如:
    可以通过该接口来动态注册Bean定义,从而实现基于注解或者其他方式的自动发现和注册Bean。
    同时,该接口也提供了一种扩展点,允许开发人员在Bean定义注册之后再进行后置处理,例如对Bean的属性进行统一设置,验证等操作。

例子——注册BeanDefinition

BeanDefinitionRegistryPostProcessor接口主要用于注册和修改BeanDefinition
postProcessBeanDefinitionRegistry()方法中,开发人员可以通过BeanDefinitionRegistry对象注册新的BeanDefinition,例如:

import org.springframework.beans.BeansException;
import org.springframework.beans.factory.config.BeanDefinition;
import org.springframework.beans.factory.config.BeanDefinitionHolder;
import org.springframework.beans.factory.config.ConfigurableListableBeanFactory;
import org.springframework.beans.factory.support.BeanDefinitionRegistry;
import org.springframework.beans.factory.support.BeanDefinitionRegistryPostProcessor;
import org.springframework.beans.factory.support.RootBeanDefinition;/*** 自定义的BeanDefinitionRegistryPostProcessor*/
public class MyBeanDefinitionRegistryPostProcessor implements BeanDefinitionRegistryPostProcessor {/*** 重写BeanDefinitionRegistryPostProcessor的postProcessBeanDefinitionRegistry方法*/@Overridepublic void postProcessBeanDefinitionRegistry(BeanDefinitionRegistry registry) throws BeansException {// 创建一个RootBeanDefinition实例,该实例对应的BeanClass是MyBeanRootBeanDefinition beanDefinition = new RootBeanDefinition(MyBean.class);// 向BeanDefinitionRegistry注册MyBean的BeanDefinitionregistry.registerBeanDefinition("myBean", beanDefinition);}/*** 重写BeanDefinitionRegistryPostProcessor的postProcessBeanFactory方法*/@Overridepublic void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) throws BeansException {// do nothing}/*** 自定义的Bean*/public static class MyBean {private String message = "Hello, World!";public String getMessage() {return message;}public void setMessage(String message) {this.message = message;}}
}

在应用程序的Spring配置文件中,我们可以通过下面的方式来注册MyBeanDefinitionRegistryPostProcessor


在容器启动时,Spring会自动检测到MyBeanDefinitionRegistryPostProcessor并将其实例化和注册到容器中。在容器启动完成后,我们的myBean就可以在容器中被其他的Bean所依赖和使用了。

后面针对这个执行顺序,我们引用一个图来说明,相信看到这你就明白啦:请添加图片描述
你以为到这就结束啦吗?咱们No,再来一个Demo收尾!

使用Spring的BeanFactoryPostProcessor扩展点完成自定义注解扫描

——todo晚上回宿舍补上

BeanPostPrecessor (后处理器)

Bean实例化之后,到最终缓存到名为singletonObjects的单例池之前,中间会经过Bean的初始化过程。例如:属性的填充,初始化init的执行等,其中有一个对外进行扩展的点BeanPostProcessor,它允许在Bean的初始化流程中插入自定义的逻辑。我们称之为BeanPostProcessor,会在流程节点上被Spring自动调用。

基本原理

它定义了两个方法:
postProcessBeforeInitialization(Object bean, String beanName):在 Bean 初始化之前调用。
postProcessAfterInitialization(Object bean, String beanName):在 Bean 初始化之后调用。

我们可以通过实现BeanPostProcessor接口,并将其注册到Spring容器中,来实现对Bean初始化过程的控制和定制。
在这两个方法中,我们可以根据需要对Bean进行一些自定义操作,例如:修改属性值,注入依赖,动态代理等等。

在 Spring 容器启动的过程:
1.当一个 Bean 被实例化后,Spring 容器会按照一定的顺序调用注册在容器中的所有 BeanPostProcessor 实现的postProcessBeforeInitialization 方法,
2.然后调用 Bean 的 init 方法,最后再按照相反的顺序调用所有 BeanPostProcessor 实现的 postProcessAfterInitialization 方法。
这个过程中,BeanPostProcessor 扮演着一个监听器的角色,允许开发人员在 Bean 初始化的过程中干预和修改 Bean 的行为,从而实现对 Spring 容器的定制和扩展。

运用的场景

  • 日志记录:
    可以使用BeanPostProcessor来实现在Bean实例化后、初始化前后打印日志,从而实现记录Bean生命周期的目的。

  • 数据库连接管理:
    可以使用BeanPostProcessor来在Bean实例化后、初始化前后获取并设置数据库连接,从而实现数据库连接的管理和复用。

  • 安全检查:
    可以使用BeanPostProcessor来实现在Bean实例化后、初始化前后对Bean的属性进行安全检查,例如检查是否有不安全的属性或敏感的数据,从而保证系统的安全性。

  • AOP(面向切面编程):
    可以使用BeanPostProcessor来在Bean实例化后、初始化前后进行动态代理,从而实现AOP编程,例如实现事务控制、日志记录等功能。

  • 自定义注解:
    可以使用BeanPostProcessor来实现在Bean实例化后、初始化前后扫描并解析自定义注解,从而实现自定义注解的功能。例如,可以在Bean实例化后、初始化前后,扫描并解析所有的@MyAnnotation注解,并根据注解的内容进行相应的操作。

经典例子——时间日志增强

要求:

  • Bean的方法执行之前控制台打印当前时间。
  • Bean的方法执行之后控制台打印当前时间。
    分析:
  • 对方法进行增强主要是代理设计模式和包装设计模式
  • 由于Bean方法不确定,所以使用动态代理在运行期间执行增强操作
  • 在Bean实例创建完毕后,进入到单例池之前,使用Proxy代替真正的目标Bean。

——todo晚上回宿舍补上

最后梳理一下,如果你前面耐心看完,这张图不用多解释了,一看就明白了🫡:
请添加图片描述

BeanFactoryPostProcessor&&BeanPostProcessor的不同点

BeanFactoryPostProcessor是Spring容器中用于在Bean定义加载到容器后、实例化之前对Bean的定义进行修改和扩展的扩展点。
它可以通过实现BeanFactoryPostProcessor接口来注册自己的处理逻辑,对所有的Bean定义进行修改和扩展,包括修改Bean的属性值、修改Bean的依赖关系、注册新的Bean定义等等。
通常情况下,我们可以使用BeanFactoryPostProcessor来实现一些与Bean定义相关的操作,例如通过解析外部配置文件动态修改Bean的属性值、实现Bean依赖的自动装配、注册新的Bean定义等等。

BeanPostProcessor是Spring容器中用于在Bean实例化后、初始化前后对Bean进行自定义处理的扩展点。
它可以通过实现BeanPostProcessor接口来注册自己的处理逻辑,对所有的Bean实例进行修改和扩展,包括修改Bean的属性值、动态代理Bean、实现AOP编程、记录日志等等。
通常情况下,我们可以使用BeanPostProcessor来实现一些与Bean实例相关的操作,例如实现Bean的自定义初始化逻辑、记录Bean的生命周期、实现Bean的动态代理等等。

结尾

这块知识,无论是学Bean的生命周期还是刷新逻辑都很重要,希望你可以学会,如果有哪些地方觉得总结的不好,欢迎留言。🙏

相关内容

热门资讯

斗篷山导游词最新 斗篷山导游词最新范文  作为一位不辞辛劳的导游,就不得不需要编写导游词,导游词是讲解当地的基本情况,...
云南省大理概况导游词 云南省大理概况导游词(精选5篇)  作为一无名无私奉献的导游,通常会被要求编写导游词,导游词是导游员...
武当山南岩宫导游词 武当山南岩宫导游词(精选12篇)  作为一名可信赖的导游人员,常常需要准备导游词,导游词具有极强的实...
合肥包公园导游词 合肥包公园导游词  包公园,位于安徽省合肥市芜湖路72号,始建于北宋嘉祐七年,是为纪念北宋著名清官包...
景点贵阳花溪公园导游词 景点贵阳花溪公园导游词  作为一位兢兢业业的旅游从业人员,时常需要用到导游词,借助导游词可以更好地宣...
孔庙导游词   孔庙导游词(一)  尊敬的各位来宾:  你们好!我受旅游、接待部门的委托,对光临名城曲阜参观游览...
石家庄驼梁景区导游词 石家庄驼梁景区导游词尊敬的各位游客:  大家好!  欢迎大家来到驼梁,我是中游旅行社的一名导游员,我...
介绍傣家竹楼导游词300 傣家竹楼是傣族固有的典型建筑。下层高约七八尺,四无遮栏,牛马拴束于柱上。上层近梯处有一露台,转进为长...
电视剧《乱世佳人》简介及经典... 电视剧《乱世佳人》简介及经典台词  电视剧简介:  《乱世佳人》亦可称为民国版《美人心计》,由唐嫣饰...
丹东鸭绿江导游词 丹东鸭绿江导游词  鸭绿江是我们中国和朝鲜的分界线,各位导游,请看下面的丹东鸭绿江导游词,希望可以帮...
幼儿园运动会闭幕式主持词 幼儿园运动会闭幕式主持词  主持人在台上表演的灵魂就表现在主持词中。随着社会一步步向前发展,各种场合...
70大寿主持词 70大寿主持词  主持词的写作需要将主题贯穿于所有节目之中。现今社会在不断向前发展,主持人的需求越来...
个人领奖感谢词 个人领奖感谢词(精选7篇)  获得奖励或者嘉奖,不仅是一份荣誉,更是一份激励。你知道怎么写感谢词吗,...
重阳节经典致辞 关于重阳节经典致辞(精选6篇)  在生活、工作和学习中,大家都不可避免地会接触到致辞吧,致辞要求风格...
幼儿园元旦文艺汇演主持词 男小主持:尊敬的家长,亲爱的老师女小主持:可爱的小朋友合:大家新年好!男小主持:春夏秋冬,黑夜清晨女...
大话西游降妖篇2台词 大话西游降妖篇2台词  导语:《西游伏妖篇》也是继春节档周星驰执导电影《美人鱼》中徐克客串表演之后,...
晚会活动主持词   引导语:晚会最重要的一点就是主持,而有关晚会活动的主持词要怎么写呢?接下来是小编为你带来收集整理...
周年庆活动主持词 周年庆活动主持词9篇  借鉴诗词和散文诗是主持词的一种写作手法。在人们越来越多的参与各种活动的今天,...
《手机》经典台词 《手机》经典台词  砖头媳妇:装得跟头会想事的猪一样。  于文娟:老费吃了不管用,说明他不是不能,而...
公司工会代表大会主持词 公司工会代表大会主持词  各位代表:  请大家坐好,会议马上就要开始了,公司工会代表大会主持词。(待...