自拍偷在线精品自拍偷,亚洲欧美中文日韩v在线观看不卡

Springboot擴展點之BeanFactoryPostProcessor

數(shù)據(jù)庫 其他數(shù)據(jù)庫
對敏感信息的解密處理,比如數(shù)據(jù)庫連接信息加密和解密:在實際的業(yè)務開發(fā)中,在配置文件中明文配置mysq,redis的密碼實際上是不安全的,需要配置加密后的密碼信息;但是把加密后的密碼信息注入的數(shù)據(jù)源中,去連接mysql數(shù)據(jù)庫肯定會連接異常,因為mysql并不知道你的加密方式和加密方法。

前言

圖片圖片

功能特性

  • 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容器中加密信息。

責任編輯:武曉燕 來源: 凡夫編程
相關推薦

2023-12-01 07:28:40

SpringbootBean

2023-11-27 07:26:42

Springboot容器

2023-09-28 08:49:41

springBean

2021-04-12 06:09:38

Spring擴展點應用

2021-12-30 08:17:27

Springboot數(shù)據(jù)訪問DataSourceB

2020-10-15 12:52:46

SpringbootJava編程語言

2023-11-06 11:13:58

Bean占位符標記

2009-08-13 18:00:48

Eclipse重構功能擴展點

2009-08-28 13:57:29

virtual ove擴展點

2023-11-24 08:00:00

2010-09-13 15:06:36

2022-05-30 09:32:07

Spring容器

2017-05-09 10:34:21

Spring BootDubbo Activ擴展

2017-04-28 08:32:40

Spring BootDubbo Activ使用

2025-04-18 05:50:59

Spring接口Aware

2024-02-01 08:28:28

2009-12-24 17:10:42

WPF動畫類

2023-12-05 07:48:23

SpringBoot

2012-01-17 10:00:34

2020-06-09 10:15:38

Javasynchronize代碼
點贊
收藏

51CTO技術棧公眾號