濟南網(wǎng)站建設(shè)山東聚搜網(wǎng)推薦深圳百度關(guān)鍵
后置處理器
- 前言
- Spring的后處理器
- BeanFactoryPostProcessor(工廠后處理器)
- 執(zhí)行節(jié)點
- 作用
- 基本信息
- 經(jīng)典場景
- 子接口——BeanDefinitiRegistryPostProcessor
- 基本介紹
- 用途
- 具體原理
- 例子——注冊BeanDefinition
- 使用Spring的BeanFactoryPostProcessor擴展點完成自定義注解掃描
- BeanPostPrecessor (后處理器)
- 基本原理
- 運用的場景
- 經(jīng)典例子——時間日志增強
- BeanFactoryPostProcessor&&BeanPostProcessor的不同點
- 結(jié)尾
前言
Spring的后處理器是Spring對外開發(fā)的重要擴展點,允許我們介入到Bean的整個實例化流程中來,以達到動態(tài)注冊BeanDefinition,動態(tài)修改BeanDefinition,以及動態(tài)修改Bean的作用。
如果你不太清楚BeanDefinition是干嘛的,推進你看看我寫的另外一篇文章,相信可以幫助到你:Spring核心模塊解析—BeanDifinition。
Spring的后處理器
Sping的后處理器是Spring對外開發(fā)的重要擴展點,允許我們介入到Bean的整個實例化流程中來,以達到動態(tài)注冊BeanDefinition,以及動態(tài)修改Bean的作用,那么Spring主要有兩種后處理器,下面我們分別進行介紹他們的基本概念和業(yè)務(wù)場景。希望你可以更好的理解。
BeanFactoryPostProcessor(工廠后處理器)
執(zhí)行節(jié)點
在BeanDefinitDefinitionMap填充完畢,Bean實例化之前執(zhí)行。
作用
1.允許我們在Spring容器加載Bean定義之后,對Bean定義進行修改,從而影響到容器中實際實例化的Bean。
2.主要用途是應(yīng)用程序上下文準(zhǔn)備就緒前,修改或添加Bean定義。
3.也可以用來執(zhí)行自定義的Bean驗證或Bean初始化邏輯。
基本信息
beanFactoryPostProcessor是一個接口規(guī)范,實現(xiàn)了該接口的類只要交由Spring容器管理的話,那么Spring就會回調(diào)該接口的方法,用于對BeanDefinition注冊和修改的功能。
@FunctionalInterface
public interface BeanFactoryPostProcessor {void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) throws BeansException;}
我們先來關(guān)注一下接口里面方法的參數(shù):ConfigurableListableBeanFactory
本質(zhì)來說,這個參數(shù)其實是BeanFacotry的子接口,我們看一下這層關(guān)系:
public interface ConfigurableListableBeanFactoryextends ListableBeanFactory, AutowireCapableBeanFactory, ConfigurableBeanFactory
然后進入到ListableBeanFactory
中:
public interface ListableBeanFactory extends BeanFactory
經(jīng)典場景
業(yè)務(wù)場景:配置文件中的占位符替換為實際值的情況。比如將配置文件中的數(shù)據(jù)庫連接URL,用戶名和密碼等信息替換為實際的值。
經(jīng)典用途是用它實現(xiàn)屬性占位符的解析,通過實現(xiàn)BeanFactoryPostProcessor
接口并重寫postProcessBeanFactory()
,我們使用Spring的占位符解析機制(如${…})來解析Bean定義中的屬性占位符,并將其替換為實際的屬性值。
下面我們來介紹一下代碼實現(xiàn):
1.首先在Spring配置文件中定義PropertyPlaceholderConfigurer
實例,用來解析占位符。
<bean class="org.springframework.beans.factory.config.PropertyPlaceholderConfigurer"><property name="location" value="classpath:jdbc.properties"/>
</bean>
上面的配置中,PropertyPlaceholderConfigurer
實例用于解析jdbc.properties
文件中的占位符。
2.實現(xiàn)一個BeanFactoryPostProcessor
接口的實現(xiàn)類,用于在應(yīng)用程序上下文準(zhǔn)備就緒之前替換Bean定義中的占位符,例如:
public class PropertyPlaceholderReplacer implements BeanFactoryPostProcessor {@Overridepublic void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) throws BeansException {// 獲取名為 "org.springframework.beans.factory.config.PropertyPlaceholderConfigurer#0" 的 PropertyPlaceholderConfigurer 對象// 該對象用于解析配置文件中的占位符,并將解析后的值設(shè)置回相應(yīng)的 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();// 如果屬性值是一個字符串類型,那么就將其轉(zhuǎn)換為實際的值if (value instanceof String) {// 調(diào)用 PropertyPlaceholderConfigurer 的 convertPropertyValue() 方法將占位符解析為實際的值Object convertedValue = configurer.convertPropertyValue((String) value);// 將轉(zhuǎn)換后的值設(shè)置回屬性值中propertyValue.setConvertedValue(convertedValue);}}}}
}
3.最后在Spring配置文件中注冊PropertyPlaceholderReplacer
實例,讓它參與應(yīng)用程序上下文創(chuàng)建過程:
<bean class="com.example.PropertyPlaceholderReplacer"/>
Spring容器啟動時,PropertyPlaceholderReplacer
實例會被創(chuàng)建并自動調(diào)用postProcessBeanFactory
方法,在此方法中實現(xiàn)占位符的解析,然后將解析后的實際值設(shè)置回相應(yīng)的Bean
定義中。這樣,應(yīng)用程序中的占位符就會被正確地替換為實際的值。
子接口——BeanDefinitiRegistryPostProcessor
基本介紹
它是Spring框架的一個擴展點,用于對Bean定義的注冊過程進行干預(yù)和定制。
繼承BeanFactoryPostProcessor
接口,并在其基礎(chǔ)上擴展了一個新的方法,即:postProcessBeanDefinitionRegistry()
方法。
用途
在Spring容器初始化時,首先會讀取應(yīng)用程序中的配置文件,并解析出所有的Bean定義,然后將這些Bean定義注冊到容器中。
在這個過程中,BeanDefinitionRegistryProcessor
提供了一種機制,允許開發(fā)人員在Bean定義注冊之前和之后對Bean定義進行自定義處理,例如添加,修改或刪除Bean定義等。
具體原理
具體來說,BeanDefinitionRegistryPostProcessor
提供了以下兩個方法:
postProcessBeanDefinitionRegistry(BeanDefinitionRegistry registry)
:該方法在所有Bean定義加載完成之后,Bean實例化之前被調(diào)用,允許開發(fā)人員對Bean定義進行自定義修改,例如添加,修改或刪除Bean定義等。postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory)
: 該方法是繼承自BeanFactoryPostProcessor
接口的方法,用于在BeanFactory完成實例化之后對BeanFactory進行后置處理。
那么我們通過BeanDefinitionRegistryPostProcessor
接口,開發(fā)人員可以在Spring容器啟動時干預(yù)Bean的注冊過程,從而實現(xiàn)對Bean的自定義處理。
例如:
可以通過該接口來動態(tài)注冊Bean定義,從而實現(xiàn)基于注解或者其他方式的自動發(fā)現(xiàn)和注冊Bean。
同時,該接口也提供了一種擴展點,允許開發(fā)人員在Bean定義注冊之后再進行后置處理,例如對Bean的屬性進行統(tǒng)一設(shè)置,驗證等操作。
例子——注冊BeanDefinition
BeanDefinitionRegistryPostProcessor
接口主要用于注冊和修改BeanDefinition
。
在postProcessBeanDefinitionRegistry()
方法中,開發(fā)人員可以通過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 {/*** 重寫B(tài)eanDefinitionRegistryPostProcessor的postProcessBeanDefinitionRegistry方法*/@Overridepublic void postProcessBeanDefinitionRegistry(BeanDefinitionRegistry registry) throws BeansException {// 創(chuàng)建一個RootBeanDefinition實例,該實例對應(yīng)的BeanClass是MyBeanRootBeanDefinition beanDefinition = new RootBeanDefinition(MyBean.class);// 向BeanDefinitionRegistry注冊MyBean的BeanDefinitionregistry.registerBeanDefinition("myBean", beanDefinition);}/*** 重寫B(tài)eanDefinitionRegistryPostProcessor的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;}}
}
在應(yīng)用程序的Spring配置文件中,我們可以通過下面的方式來注冊MyBeanDefinitionRegistryPostProcessor
<bean class="com.example.MyBeanDefinitionRegistryPostProcessor"/>
在容器啟動時,Spring會自動檢測到MyBeanDefinitionRegistryPostProcessor
并將其實例化和注冊到容器中。在容器啟動完成后,我們的myBean
就可以在容器中被其他的Bean所依賴和使用了。
后面針對這個執(zhí)行順序,我們引用一個圖來說明,相信看到這你就明白啦:
你以為到這就結(jié)束啦嗎?咱們No,再來一個Demo收尾!
使用Spring的BeanFactoryPostProcessor擴展點完成自定義注解掃描
——todo晚上回宿舍補上
BeanPostPrecessor (后處理器)
Bean實例化之后,到最終緩存到名為singletonObjects的單例池之前,中間會經(jīng)過Bean的初始化過程。例如:屬性的填充,初始化init的執(zhí)行等,其中有一個對外進行擴展的點BeanPostProcessor,它允許在Bean的初始化流程中插入自定義的邏輯。我們稱之為BeanPostProcessor,會在流程節(jié)點上被Spring自動調(diào)用。
基本原理
它定義了兩個方法:
postProcessBeforeInitialization(Object bean, String beanName)
:在 Bean 初始化之前調(diào)用。
postProcessAfterInitialization(Object bean, String beanName)
:在 Bean 初始化之后調(diào)用。
我們可以通過實現(xiàn)BeanPostProcessor
接口,并將其注冊到Spring容器中,來實現(xiàn)對Bean初始化過程的控制和定制。
在這兩個方法中,我們可以根據(jù)需要對Bean進行一些自定義操作,例如:修改屬性值,注入依賴,動態(tài)代理等等。
在 Spring 容器啟動的過程:
1.當(dāng)一個 Bean 被實例化后,Spring 容器會按照一定的順序調(diào)用注冊在容器中的所有 BeanPostProcessor
實現(xiàn)的postProcessBeforeInitialization
方法,
2.然后調(diào)用 Bean 的 init 方法,最后再按照相反的順序調(diào)用所有 BeanPostProcessor
實現(xiàn)的 postProcessAfterInitialization
方法。
這個過程中,BeanPostProcessor
扮演著一個監(jiān)聽器的角色,允許開發(fā)人員在 Bean 初始化的過程中干預(yù)和修改 Bean 的行為,從而實現(xiàn)對 Spring 容器的定制和擴展。
運用的場景
-
日志記錄:
可以使用BeanPostProcessor來實現(xiàn)在Bean實例化后、初始化前后打印日志,從而實現(xiàn)記錄Bean生命周期的目的。 -
數(shù)據(jù)庫連接管理:
可以使用BeanPostProcessor來在Bean實例化后、初始化前后獲取并設(shè)置數(shù)據(jù)庫連接,從而實現(xiàn)數(shù)據(jù)庫連接的管理和復(fù)用。 -
安全檢查:
可以使用BeanPostProcessor來實現(xiàn)在Bean實例化后、初始化前后對Bean的屬性進行安全檢查,例如檢查是否有不安全的屬性或敏感的數(shù)據(jù),從而保證系統(tǒng)的安全性。 -
AOP(面向切面編程):
可以使用BeanPostProcessor來在Bean實例化后、初始化前后進行動態(tài)代理,從而實現(xiàn)AOP編程,例如實現(xiàn)事務(wù)控制、日志記錄等功能。 -
自定義注解:
可以使用BeanPostProcessor來實現(xiàn)在Bean實例化后、初始化前后掃描并解析自定義注解,從而實現(xiàn)自定義注解的功能。例如,可以在Bean實例化后、初始化前后,掃描并解析所有的@MyAnnotation注解,并根據(jù)注解的內(nèi)容進行相應(yīng)的操作。
經(jīng)典例子——時間日志增強
要求:
- Bean的方法執(zhí)行之前控制臺打印當(dāng)前時間。
- Bean的方法執(zhí)行之后控制臺打印當(dāng)前時間。
分析: - 對方法進行增強主要是代理設(shè)計模式和包裝設(shè)計模式
- 由于Bean方法不確定,所以使用動態(tài)代理在運行期間執(zhí)行增強操作
- 在Bean實例創(chuàng)建完畢后,進入到單例池之前,使用Proxy代替真正的目標(biāo)Bean。
——todo晚上回宿舍補上
最后梳理一下,如果你前面耐心看完,這張圖不用多解釋了,一看就明白了🫡:
BeanFactoryPostProcessor&&BeanPostProcessor的不同點
BeanFactoryPostProcessor
是Spring容器中用于在Bean定義加載到容器后、實例化之前對Bean的定義進行修改和擴展的擴展點。
它可以通過實現(xiàn)BeanFactoryPostProcessor
接口來注冊自己的處理邏輯,對所有的Bean定義進行修改和擴展,包括修改Bean的屬性值、修改Bean的依賴關(guān)系、注冊新的Bean定義等等。
通常情況下,我們可以使用BeanFactoryPostProcessor
來實現(xiàn)一些與Bean定義相關(guān)的操作,例如通過解析外部配置文件動態(tài)修改Bean的屬性值、實現(xiàn)Bean依賴的自動裝配、注冊新的Bean定義等等。
BeanPostProcessor
是Spring容器中用于在Bean實例化后、初始化前后對Bean進行自定義處理的擴展點。
它可以通過實現(xiàn)BeanPostProcessor
接口來注冊自己的處理邏輯,對所有的Bean實例進行修改和擴展,包括修改Bean的屬性值、動態(tài)代理Bean、實現(xiàn)AOP編程、記錄日志等等。
通常情況下,我們可以使用BeanPostProcessor
來實現(xiàn)一些與Bean實例相關(guān)的操作,例如實現(xiàn)Bean的自定義初始化邏輯、記錄Bean的生命周期、實現(xiàn)Bean的動態(tài)代理等等。
結(jié)尾
這塊知識,無論是學(xué)Bean的生命周期還是刷新邏輯都很重要,希望你可以學(xué)會,如果有哪些地方覺得總結(jié)的不好,歡迎留言。🙏