Springboot擴展點之BeanFactoryPostProcessor
前言
圖片
功能特性
- BeanFactoryPostProcessor的執(zhí)行是Spring Bean生命周期非常重要的一部分;
- BeanFactory級別的后置處理器,在Spring生命周期內,org.springframework.beans.factory.config.BeanFactoryPostProcessor#postProcessBeanFactory只會執(zhí)行一次;
- 允許在容器讀取到Bean的BeanDefinition數(shù)據(jù)之后,bean未實例化前,讀取BeanDefiniion數(shù)據(jù),并且可以根據(jù)需要進行修改;
實現(xiàn)方式
1、定義一個Dog類,name屬性默認為“旺財”,顏色默認為“黑色”;
@Data
@Component
public class Dog {
private String name="旺財";
private String color="黑色";
}
2、定義一個實現(xiàn)類(MyBeanFactoryPostProcessor),實現(xiàn)BeanFactoryPostProcessor接口,重寫postProcessBeanFactory()方法,并Dog類的屬性name修改為“狗蛋”;并用@Component注解標記BeanFactoryPostProcessor接口的實現(xiàn)類(MyBeanFactoryPostProcessor)
@Component
@Slf4j
public class MyBeanFactoryPostProcessor implements BeanFactoryPostProcessor {
@Override
public void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) throws BeansException {
log.info("com.fanfu.config.MyBeanFactoryPostProcessor.postProcessBeanFactory被執(zhí)行");
ScannedGenericBeanDefinition dog = ((ScannedGenericBeanDefinition) beanFactory.getBeanDefinition("dog")) ;
MutablePropertyValues propertyValues = dog.getPropertyValues();
propertyValues.addPropertyValue("name", "狗蛋兒");
log.info("修改Dog的BeanDefinition對象中的name屬性為狗蛋兒");
}
}
3、編寫單元測試驗證結果
@SpringBootTest
@Slf4j
public class FanfuApplicationTests {
@Test
public void test(){
AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext("com.fanfu");
Dog dog = ((Dog) context.getBean("dog"));
log.info(dog.getName());
Assert.isTrue(dog.getName().equals("狗蛋兒"), "屬性修改失敗");
}
}
4、驗證結果表明,自定義的BeanFactoryPostProcessor接口的實現(xiàn)類(MyBeanFactoryPostProcessor),可以在容器讀取到Bean的BeanDefinition數(shù)據(jù)之后,bean未實例化前,讀取BeanDefiniion數(shù)據(jù),并且根據(jù)需要進行修改,那么自定義的BeanFactoryPostProcessor接口的實現(xiàn)類(MyBeanFactoryPostProcessor)的工作原理是什么呢?BeanFactoryPostProcessor接口的實現(xiàn)類是什么時候實例化的?MyBeanFactoryPostProcessor#postProcessBeanFactory方法是如何被調用的?接著往下看。
工作原理
BeanFactoryPostProcessor接口的實現(xiàn)類是什么時候實例化的?
1、BeanFactoryPostProcessor接口的實現(xiàn)類(MyBeanFactoryPostProcessor)被@Component標記,在窗口啟動的時候會被封裝成BeanDefinition對象注冊到容器中;
圖片
2、PostProcessorRegistrationDelegate#invokeBeanFactoryPostProcessors()方法被執(zhí)行時,會按照類型從Spring容器中找到所有BeanFactoryPostProcessor類型的實現(xiàn)類的名稱;
圖片
3、在上一步中得到所有BeanFactoryPostProcessor類型的實現(xiàn)類的名稱的名稱后,再循環(huán)一次,來對BeanFactoryPostProcessor的實現(xiàn)類進行實例化 (beanFacotry.getBean()去獲取MyBeanFactoryPostProcessor的實例,如果獲取不到,就創(chuàng)建一個);
圖片
MyBeanFactoryPostProcessor#postProcessBeanFactory方法是如何被調用的?
1、在單元測試中構建了一個AnnotationConfigApplicationContext對象,AnnotationConfigApplicationContext的構造方法如下:
public AnnotationConfigApplicationContext(String... basePackages) { this(); scan(basePackages); refresh(); }
2、從上面的AnnotationConfigApplicationContext的構造方法中,可以看到又調用了refresh(),這里實際最終被調用的是AbstractApplicationContext#refresh(),這個方法也是Spring容器啟動的關鍵方法,在分析Spring相關的源碼時會經(jīng)常碰到。
3、AbstractApplicationContext#refresh()中,調用AbstractApplicationContext#invokeBeanFactoryPostProcessors方法才正式開始了BeanFactoryPostProcessor接口的所有實現(xiàn)類的postProcessBeanFactory()方法調用;
4、跟著AbstractApplicationContext#invokeBeanFactoryPostProcessors方法進去,會發(fā)現(xiàn)這里只是一個入口,實際承擔調用執(zhí)行任務的是PostProcessorRegistrationDelegate#invokeBeanFactoryPostProcessors()方法;
5、跟著PostProcessorRegistrationDelegate#invokeBeanFactoryPostProcessors()方法進去后,會發(fā)現(xiàn)里面真的是別有洞天,很容易迷路(牢牢帶著自己的問題分析源碼找答案,不要被除自己問題以外的東西迷了眼,一定會柳暗花明),另外org.springframework.beans.factory.support.BeanDefinitionRegistryPostProcessor的實現(xiàn)類的調用也在這個方法,所以這個方法的含金量很高,那就單獨拎出來仔細分析一下,建議debug一步一步看,多看幾遍就能明白,其實也很簡單,唯一的難點就是這個方法有點長,需要多點耐心和時間。
public static void invokeBeanFactoryPostProcessors(
ConfigurableListableBeanFactory beanFactory, List<BeanFactoryPostProcessor> beanFactoryPostProcessors) {
//之所以說這個方法的含金量很高,
//是因為在這個方法里是先執(zhí)行BeanDefinitionRegistryPostProcessor實現(xiàn)類的postProcessBeanDefinitionRegistry方法;//然后才接著執(zhí)行BeanFactoryPostProcessor接口的實現(xiàn)類的postProcessBeanFactory方法
//這兩個接口很表面上看很類似,實際在執(zhí)行的時機和功能上是有明顯區(qū)別的
Set<String> processedBeans = new HashSet<>();
//AnnotationConfigApplicationContext繼承于GenericApplicationContext,
//而GenericApplicationContext又實現(xiàn)了BeanDefinitionRegistry接口
//所以這里會進入if語句中
if (beanFactory instanceof BeanDefinitionRegistry) {
BeanDefinitionRegistry registry = (BeanDefinitionRegistry) beanFactory;
List<BeanFactoryPostProcessor> regularPostProcessors = new ArrayList<>();
List<BeanDefinitionRegistryPostProcessor> registryProcessors = new ArrayList<>();
//這里提前執(zhí)行的BeanFactoryPostProcessor,是在準備上下文環(huán)境時,發(fā)布了ApplicationPreparedEvent事件;//觸發(fā)監(jiān)聽器,通過AbstractApplicationContext#addBeanFactoryPostProcessor注冊進來的;//這里并不是這次要重點分析的內容,可以先跳過這;for (BeanFactoryPostProcessor postProcessor : beanFactoryPostProcessors) {
if (postProcessor instanceof BeanDefinitionRegistryPostProcessor) {
BeanDefinitionRegistryPostProcessor registryProcessor =
(BeanDefinitionRegistryPostProcessor) postProcessor;
registryProcessor.postProcessBeanDefinitionRegistry(registry);
registryProcessors.add(registryProcessor);
}
else {
regularPostProcessors.add(postProcessor);
}
}
List<BeanDefinitionRegistryPostProcessor> currentRegistryProcessors = new ArrayList<>();
// 從32行到72行,是在執(zhí)行BeanDefinitionRegistryPostProcessor實現(xiàn)類的postProcessBeanDefinitionRegistry方法;//執(zhí)行的過程也是有點小區(qū)折的,分三步,第一,執(zhí)行實現(xiàn)了PriorityOrdered接口的實現(xiàn)類.
String[] postProcessorNames =
beanFactory.getBeanNamesForType(BeanDefinitionRegistryPostProcessor.class, true, false);
for (String ppName : postProcessorNames) {
if (beanFactory.isTypeMatch(ppName, PriorityOrdered.class)) {
currentRegistryProcessors.add(beanFactory.getBean(ppName, BeanDefinitionRegistryPostProcessor.class));
processedBeans.add(ppName);
}
}
sortPostProcessors(currentRegistryProcessors, beanFactory);
registryProcessors.addAll(currentRegistryProcessors);
invokeBeanDefinitionRegistryPostProcessors(currentRegistryProcessors, registry);
currentRegistryProcessors.clear();
// 第二,執(zhí)行實現(xiàn)了Ordered接口的實現(xiàn)類;postProcessorNames = beanFactory.getBeanNamesForType(BeanDefinitionRegistryPostProcessor.class, true, false);
for (String ppName : postProcessorNames) {
if (!processedBeans.contains(ppName) && beanFactory.isTypeMatch(ppName, Ordered.class)) {
currentRegistryProcessors.add(beanFactory.getBean(ppName, BeanDefinitionRegistryPostProcessor.class));
processedBeans.add(ppName);
}
}
sortPostProcessors(currentRegistryProcessors, beanFactory);
registryProcessors.addAll(currentRegistryProcessors);
invokeBeanDefinitionRegistryPostProcessors(currentRegistryProcessors, registry);
currentRegistryProcessors.clear();
//第三,執(zhí)行剩下其他的BeanDefinitionRegistryPostProcessor實現(xiàn)類;boolean reiterate = true;
while (reiterate) {
reiterate = false;
postProcessorNames = beanFactory.getBeanNamesForType(BeanDefinitionRegistryPostProcessor.class, true, false);
for (String ppName : postProcessorNames) {
if (!processedBeans.contains(ppName)) {
currentRegistryProcessors.add(beanFactory.getBean(ppName, BeanDefinitionRegistryPostProcessor.class));
processedBeans.add(ppName);
reiterate = true;
}
}
sortPostProcessors(currentRegistryProcessors, beanFactory);
registryProcessors.addAll(currentRegistryProcessors);
invokeBeanDefinitionRegistryPostProcessors(currentRegistryProcessors, registry);
currentRegistryProcessors.clear();
}
// BeanDefinitionRegistryPostProcessor繼承了BeanFactoryPostProcessor,
//所以這部分實現(xiàn)類的postProcessBeanFactory()會提前執(zhí)行
invokeBeanFactoryPostProcessors(registryProcessors, beanFactory);
//第26行,非BeanDefinitionRegistryPostProcessor類型的BeanFactoryPostProcessor實現(xiàn)類會在這執(zhí)行
invokeBeanFactoryPostProcessors(regularPostProcessors, beanFactory);
} else {
invokeBeanFactoryPostProcessors(beanFactoryPostProcessors, beanFactory);
}
//BeanDefinitionRegistryPostProcessor接口的實現(xiàn)類上面已執(zhí)行執(zhí)行完了
//下面開始準備執(zhí)行BeanFactoryPostProcessor接口的實現(xiàn)類
String[] postProcessorNames =
beanFactory.getBeanNamesForType(BeanFactoryPostProcessor.class, true, false);
// 正式執(zhí)行前,把BeanFactoryPostProcessor接口的實現(xiàn)類分成了三類,
//分別是實現(xiàn)了PriorityOrdered接口,實現(xiàn)了Ordered接口,其他;
List<BeanFactoryPostProcessor> priorityOrderedPostProcessors = new ArrayList<>();
List<String> orderedPostProcessorNames = new ArrayList<>();
List<String> nonOrderedPostProcessorNames = new ArrayList<>();
for (String ppName : postProcessorNames) {
if (processedBeans.contains(ppName)) {
// skip - already processed in first phase above
}
else if (beanFactory.isTypeMatch(ppName, PriorityOrdered.class)) {
priorityOrderedPostProcessors.add(beanFactory.getBean(ppName, BeanFactoryPostProcessor.class));
}
else if (beanFactory.isTypeMatch(ppName, Ordered.class)) {
orderedPostProcessorNames.add(ppName);
}
else {
nonOrderedPostProcessorNames.add(ppName);
}
}
// 分好類,第一,先執(zhí)行實現(xiàn)了PriorityOrdered接口的實現(xiàn)類;sortPostProcessors(priorityOrderedPostProcessors, beanFactory);
invokeBeanFactoryPostProcessors(priorityOrderedPostProcessors, beanFactory);
// 第二,執(zhí)行實現(xiàn)了Ordered接口的實現(xiàn)類;List<BeanFactoryPostProcessor> orderedPostProcessors = new ArrayList<>(orderedPostProcessorNames.size());
for (String postProcessorName : orderedPostProcessorNames) {
orderedPostProcessors.add(beanFactory.getBean(postProcessorName, BeanFactoryPostProcessor.class));
}
sortPostProcessors(orderedPostProcessors, beanFactory);
invokeBeanFactoryPostProcessors(orderedPostProcessors, beanFactory);
//第三,執(zhí)行未實現(xiàn)上面兩個接口的實現(xiàn)類,自定義的MyBeanFactoryPostProcessor就是在這里被執(zhí)行的
//其實,也很簡單的,和BeanDefinitionRegistryPostProcessor接口的實現(xiàn)類的執(zhí)行過程類似;List<BeanFactoryPostProcessor> nonOrderedPostProcessors = new ArrayList<>(nonOrderedPostProcessorNames.size());
for (String postProcessorName : nonOrderedPostProcessorNames) {
nonOrderedPostProcessors.add(beanFactory.getBean(postProcessorName, BeanFactoryPostProcessor.class));
}
invokeBeanFactoryPostProcessors(nonOrderedPostProcessors, beanFactory);
beanFactory.clearMetadataCache();
}
調用時序圖
這里我畫了一個時序圖,可以更直觀的看到整個調用過程,也可以照著這個圖,一步一步debug來了解整個過程;
圖片
postProcessBeanFactory()與postProcessBeanDefinitionRegistry()
通過分析PostProcessorRegistrationDelegate#invokeBeanFactoryPostProcessors()方法,postProcessBeanFactory()與postProcessBeanDefinitionRegistry()的區(qū)別已經(jīng)很明顯了,這里再總結一下(總結的有不準的地方,還請小伙伴在評論區(qū)告訴我,一塊進步):
- BeanDefinitionRegistryPostProcessor接口的實現(xiàn)類的postProcessBeanDefinitionRegistry方法要優(yōu)先于BeanFactoryPostProcessor接口的實現(xiàn)類的postProcessBeanFactory方法執(zhí)行;
- postProcessBeanDefinitionRegistry方法形參是BeanDefinitionRegistry,postProcessBeanFactory方法的形參是ConfigurableListableBeanFactory,在功能上會有一些區(qū)別;需要注意的是DefaultListableBeanFactory實現(xiàn)了BeanDefinitionRegistry和ConfigurableListableBeanFactory接口;
- BeanDefinitionRegistryPostProcessor繼承了BeanFactoryPostProcessor,關于BeanDefinitionRegistryPostProcessor可以移步這里:Springboot擴展點之BeanDefinitionRegistryPostProcessor;
應用場景
對敏感信息的解密處理,比如數(shù)據(jù)庫連接信息加密和解密:在實際的業(yè)務開發(fā)中,在配置文件中明文配置mysq,redis的密碼實際上是不安全的,需要配置加密后的密碼信息;但是把加密后的密碼信息注入的數(shù)據(jù)源中,去連接mysql數(shù)據(jù)庫肯定會連接異常,因為mysql并不知道你的加密方式和加密方法。這就會產生一個需求:需要在配置文件中配置的數(shù)據(jù)庫信息是加密的,但是在把密碼信息注入數(shù)據(jù)源前在程序里解密處理。
BeanFactoryPostProcessor正好可以解決這個問題,在真正使用到數(shù)據(jù)源去連接數(shù)據(jù)庫前,讀取到加密信息,進行解密處理,再用解密后的信息替換掉Spring容器中加密信息。