Springboot extension point BeanFactoryPostProcessor

Collection of implementation methods and working principles of Springboot extension point series:

Springboot extension point ApplicationContextInitializer

Springboot extension point BeanFactoryPostProcessor

Springboot extension point BeanDefinitionRegistryPostProcessor

Springboot extension point BeanPostProcessor

Springboot extension point InstantiationAwareBeanPostProcessor

Springboot extension point SmartInstantiationAwareBeanPostProcessor

Springboot extension point ApplicationContextAwareProcessor

Springboot extension point @PostConstruct

Springboot extension point InitializingBean

Springboot extension point SmartInitializingSingleton

Springboot extension point CommandLineRunner and ApplicationRunner

Springboot extension point FactoryBean

Springboot extension point DisposableBean

The end of the Springboot extension point series: Bean life cycle

Insert image description here

1. Functional characteristics

  1. The execution of BeanFactoryPostProcessor is a very important part of the Spring Bean life cycle;
  2. BeanFactory level post-processor, org.springframework.beans.factory.config.BeanFactoryPostProcessor#postProcessBeanFactory will only be executed once during the Spring life cycle;
  3. Allows the BeanDefinition data to be read after the container reads the BeanDefinition data and before the bean is instantiated, and can be modified as needed;

2. Implementation method

Define a Dog class, the name attribute defaults to "Wangcai", and the color defaults to "black";

@Data
@Component
public class Dog {
    
    
    private String name="旺财";
    private String color="黑色";
}

Define an implementation class (MyBeanFactoryPostProcessor), implement the org.springframework.beans.factory.config.BeanFactoryPostProcessor interface, override the postProcessBeanFactory() method, and change the attribute name of the Dog class to "dog egg"; and mark the BeanFactoryPostProcessor interface with the @Component annotation Implementation class (MyBeanFactoryPostProcessor);

@Component
@Slf4j
public class MyBeanFactoryPostProcessor implements BeanFactoryPostProcessor {
    
    
    @Override
    public void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) throws BeansException {
    
    
        log.info("com.fanfu.config.MyBeanFactoryPostProcessor.postProcessBeanFactory被执行");
        ScannedGenericBeanDefinition dog = ((ScannedGenericBeanDefinition) beanFactory.getBeanDefinition("dog"))  ;
        MutablePropertyValues propertyValues = dog.getPropertyValues();
        propertyValues.addPropertyValue("name", "狗蛋儿");
        log.info("修改Dog的BeanDefinition对象中的name属性为狗蛋儿");
    }
}

Write unit tests to verify results;

@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("狗蛋儿"), "属性修改失败");
    }
}

The verification results show that the implementation class of the customized BeanFactoryPostProcessor interface (MyBeanFactoryPostProcessor) can read the BeanDefiniion data after the container reads the BeanDefinition data of the bean and before the bean is instantiated, and modify it as needed, then the customized BeanFactoryPostProcessor What is the working principle of the interface implementation class (MyBeanFactoryPostProcessor)? When is the implementation class of the BeanFactoryPostProcessor interface instantiated? How is the MyBeanFactoryPostProcessor#postProcessBeanFactory method called? Then look down.

3. Working principle

3.1When is the implementation class of the BeanFactoryPostProcessor interface instantiated?

  1. The implementation class of the BeanFactoryPostProcessor interface (MyBeanFactoryPostProcessor) is marked with @Component and will be encapsulated into a BeanDefinition object and registered in the container when the window is started;
    Insert image description here
  2. When the PostProcessorRegistrationDelegate#invokeBeanFactoryPostProcessors() method is executed, the names of all implementation classes of the BeanFactoryPostProcessor type will be found from the Spring container according to the type;
    Insert image description here
  3. After getting the names of all implementation classes of the BeanFactoryPostProcessor type in the previous step, loop again to instantiate the implementation class of BeanFactoryPostProcessor (beanFacotry.getBean() to get the instance of MyBeanFactoryPostProcessor. If it cannot be obtained, create one );
    Insert image description here

3.2How is the MyBeanFactoryPostProcessor#postProcessBeanFactory method called?

  1. An AnnotationConfigApplicationContext object is constructed in the unit test. The construction method of AnnotationConfigApplicationContext is as follows:
public AnnotationConfigApplicationContext(String... basePackages) {
    
    
   this();
   scan(basePackages);
   refresh();
}
  1. From the construction method of AnnotationConfigApplicationContext above, you can see that refresh() is called again. What is actually called here is org.springframework.context.support.AbstractApplicationContext#refresh(). This method is also a key method for starting the Spring container. It is often encountered when analyzing Spring-related source code.

  2. In AbstractApplicationContext#refresh(), calling the org.springframework.context.support.AbstractApplicationContext#invokeBeanFactoryPostProcessors method officially starts the postProcessBeanFactory() method call of all implementation classes of the BeanFactoryPostProcessor interface;

  3. Follow the AbstractApplicationContext#invokeBeanFactoryPostProcessors method and you will find that this is just an entrance. The actual call execution task is the org.springframework.context.support.PostProcessorRegistrationDelegate#invokeBeanFactoryPostProcessors() method;

  4. After following the PostProcessorRegistrationDelegate#invokeBeanFactoryPostProcessors() method, you will find that there is really a hidden world inside, and it is easy to get lost (carry your own questions and analyze the source code to find the answer, don't be confused by things other than your own questions, you will definitely find a bright future) In addition, the implementation class of org.springframework.beans.factory.support.BeanDefinitionRegistryPostProcessor is also called in this method, so this method is very valuable, so I will take it out separately and analyze it carefully. It is recommended to debug and read it step by step and read it several times. You can understand that it is actually very simple. The only difficulty is that this method is a bit long and requires more patience and time.

public static void invokeBeanFactoryPostProcessors(
      ConfigurableListableBeanFactory beanFactory, List<BeanFactoryPostProcessor> beanFactoryPostProcessors) {
    
    
   //之所以说这个方法的含金量很高,
   //是因为在这个方法里是先执行BeanDefinitionRegistryPostProcessor实现类的postProcessBeanDefinitionRegistry方法; 
   //然后才接着执行BeanFactoryPostProcessor接口的实现类的postProcessBeanFactory方法
   //这两个接口很表面上看很类似,实际在执行的时机和功能上是有明显区别的
   Set<String> processedBeans = new HashSet<>();
   //AnnotationConfigApplicationContext继承于GenericApplicationContext,
   //而GenericApplicationContext又实现了BeanDefinitionRegistry接口
   //所以这里会进入if语句中
   if (beanFactory instanceof BeanDefinitionRegistry) {
    
    
      BeanDefinitionRegistry registry = (BeanDefinitionRegistry) beanFactory;
      List<BeanFactoryPostProcessor> regularPostProcessors = new ArrayList<>();
      List<BeanDefinitionRegistryPostProcessor> registryProcessors = new ArrayList<>();
        //这里提前执行的BeanFactoryPostProcessor,是在准备上下文环境时,发布了ApplicationPreparedEvent事件;
        //触发监听器,通过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行,是在执行BeanDefinitionRegistryPostProcessor实现类的postProcessBeanDefinitionRegistry方法;
      //执行的过程也是有点小区折的,分三步,第一,执行实现了PriorityOrdered接口的实现类.
      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();
      // 第二,执行实现了Ordered接口的实现类;
      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();
      //第三,执行剩下其他的BeanDefinitionRegistryPostProcessor实现类;
      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,
      //所以这部分实现类的postProcessBeanFactory()会提前执行
      invokeBeanFactoryPostProcessors(registryProcessors, beanFactory);
      //第26行,非BeanDefinitionRegistryPostProcessor类型的BeanFactoryPostProcessor实现类会在这执行
      invokeBeanFactoryPostProcessors(regularPostProcessors, beanFactory);
   } else {
    
    
      invokeBeanFactoryPostProcessors(beanFactoryPostProcessors, beanFactory);
   }
   //BeanDefinitionRegistryPostProcessor接口的实现类上面已执行执行完了
   //下面开始准备执行BeanFactoryPostProcessor接口的实现类
   String[] postProcessorNames =
         beanFactory.getBeanNamesForType(BeanFactoryPostProcessor.class, true, false);
   // 正式执行前,把BeanFactoryPostProcessor接口的实现类分成了三类,
   //分别是实现了PriorityOrdered接口,实现了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);
      }
   }
   // 分好类,第一,先执行实现了PriorityOrdered接口的实现类; 
   sortPostProcessors(priorityOrderedPostProcessors, beanFactory);
   invokeBeanFactoryPostProcessors(priorityOrderedPostProcessors, beanFactory);
   // 第二,执行实现了Ordered接口的实现类; 
   List<BeanFactoryPostProcessor> orderedPostProcessors = new ArrayList<>(orderedPostProcessorNames.size());
   for (String postProcessorName : orderedPostProcessorNames) {
    
    
      orderedPostProcessors.add(beanFactory.getBean(postProcessorName, BeanFactoryPostProcessor.class));
   }
   sortPostProcessors(orderedPostProcessors, beanFactory);
   invokeBeanFactoryPostProcessors(orderedPostProcessors, beanFactory);
   //第三,执行未实现上面两个接口的实现类,自定义的MyBeanFactoryPostProcessor就是在这里被执行的
   //其实,也很简单的,和BeanDefinitionRegistryPostProcessor接口的实现类的执行过程类似; 
   List<BeanFactoryPostProcessor> nonOrderedPostProcessors = new ArrayList<>(nonOrderedPostProcessorNames.size());
   for (String postProcessorName : nonOrderedPostProcessorNames) {
    
    
      nonOrderedPostProcessors.add(beanFactory.getBean(postProcessorName, BeanFactoryPostProcessor.class));
   }
   invokeBeanFactoryPostProcessors(nonOrderedPostProcessors, beanFactory);
   beanFactory.clearMetadataCache();
}

3.3 Call sequence diagram

Here I have drawn a timing diagram so that you can see the entire calling process more intuitively. You can also follow this diagram and debug step by step to understand the entire process;
Insert image description here

3.4postProcessBeanFactory()postProcessBeanDefinitionRegistry()

By analyzing the PostProcessorRegistrationDelegate#invokeBeanFactoryPostProcessors() method, the difference between postProcessBeanFactory() and postProcessBeanDefinitionRegistry() is already obvious. Here is a summary (if there are any inaccuracies in the summary, please tell me in the comment area so we can make progress together):

  1. The postProcessBeanDefinitionRegistry method of the implementation class of the BeanDefinitionRegistryPostProcessor interface shall be executed prior to the postProcessBeanFactory method of the implementation class of the BeanFactoryPostProcessor interface;

  2. The formal parameter of the postProcessBeanDefinitionRegistry method is BeanDefinitionRegistry, and the formal parameter of the postProcessBeanFactory method is ConfigurableListableBeanFactory. There will be some differences in functions. It should be noted that DefaultListableBeanFactory implements the BeanDefinitionRegistry and ConfigurableListableBeanFactory interfaces;

  3. BeanDefinitionRegistryPostProcessor inherits BeanFactoryPostProcessor. About BeanDefinitionRegistryPostProcessor, you can go here: Springboot extension point BeanDefinitionRegistryPostProcessor ;

4. Application scenarios

Decryption of sensitive information, such as encryption and decryption of database connection information: In actual business development, configuring mysq and redis passwords in clear text in the configuration file is actually unsafe, and encrypted password information needs to be configured; but When the encrypted password information is injected into the data source, connecting to the mysql database will definitely result in an abnormal connection, because mysql does not know your encryption method and encryption method. This will create a requirement: the database information configured in the configuration file needs to be encrypted, but the password information must be decrypted in the program before injecting the password information into the data source.

BeanFactoryPostProcessor can just solve this problem. Before actually using the data source to connect to the database, it reads the encrypted information, performs decryption processing, and then replaces the encrypted information in the Spring container with the decrypted information.
——————————————
Copyright statement: This article is an original article by CSDN blogger “Ordinary Trafficker” and follows the CC 4.0 BY-SA copyright agreement. Please attach the original source link and this copy when reprinting statement.
Original link: https://blog.csdn.net/fox9916/article/details/128823328

Guess you like

Origin blog.csdn.net/tian830937/article/details/132946304