Springboot extension point BeanDefinitionRegistryPostProcessor

Insert image description here
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

Preface

Through this article, I would like to share with you another Springboot extension point, BeanDefinitionRegistryPostProcessor. This type of extension point is generally called a container-level post-processor. The other type is a Bean-level post-processor; a container-level post-processor. It will be executed once after the Spring container is initialized and before refreshing. The Bean-level reset processor will be executed before and after each Bean is instantiated.

1. Functional features

  1. The postProcessBeanDefinitionRegistry() method can add, delete, modify and check BeanDefintion through BeanDefinitionRegistry;

  2. Inherits BeanFactoryPostProcessor, which is a container-level extension interface. The org.springframework.beans.factory.config.BeanFactoryPostProcessor#postProcessBeanFactory method is executed after the container is instantiated and before the container is refreshed. That is, you can make some more changes to the BeanDefintion before the container is refreshed. operate;

public interface BeanDefinitionRegistryPostProcessor extends BeanFactoryPostProcessor {
    
    
   void postProcessBeanDefinitionRegistry(BeanDefinitionRegistry registry) throws BeansException;
}
@FunctionalInterface
public interface BeanFactoryPostProcessor {
    
    
   void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) throws BeansException;
}

To sum up, after all BeanDefinitions are loaded and before the Bean is actually instantiated, you can perform some customized operations on the BeanDefinition by implementing the BeanDefinitionRegistryPostProcessor interface, such as modifying the BeanDefinition properties of a bean and manually registering some complex Beans.

Friends who are not familiar with Spring principles may be a little confused when they see this. What is BeanDefinition? What is BeanDefinitionRegistry? What is ConfigurableListableBeanFactory? Don't worry, I'll give you a brief explanation here, and your understanding of the entire article will be smoother.

1.1 BeanDefinition

As we all know, one of the cores of Spring is IOC (Inversion of Control). The reason why Spring can achieve the inversion of bean control is because of Spring's container function. Before the beans are included in Spring container management, all beans will be abstractly encapsulated. into a BeanDefinition instance, and then the bean will be instantiated at different times based on the BeanDefinition instance information.

Simply put, Dog.java describes the attributes and behaviors of animals such as dogs, and BeanDefinition describes the Dog.java class.

1.2 BeanDefinitionRegistry

BeanDefinitionRegistry literally means the registration of bean definition information. In fact, the function of this class is the same as the literal meaning, which is to manage BeanDefinition (add, delete, modify and check);

public interface BeanDefinitionRegistry extends AliasRegistry {
    
    
    //注册beanDefinition
   void registerBeanDefinition(String beanName, BeanDefinition beanDefinition)
         throws BeanDefinitionStoreException;
    //移除指定的beanDefinition
   void removeBeanDefinition(String beanName) throws NoSuchBeanDefinitionException;
    //根据beanName查询beanDefinition
   BeanDefinition getBeanDefinition(String beanName) throws NoSuchBeanDefinitionException;
    //判断某个beanDefinition是否已经注册
   boolean containsBeanDefinition(String beanName);
    //获取所有已注册的beanDefinition
   String[] getBeanDefinitionNames();
    //获取所有已注册的beanDefinition的数量
   int getBeanDefinitionCount();
    //判断某个beanDefinition是否已经被使用
   boolean isBeanNameInUse(String beanName);
}

1.3 ConfigurableListableBeanFactory

Spring's container was mentioned above. One of the cores of Spring is IOC, so Spring's container design is the core of the core. Spring's containers have many forms. The most basic form is BeanFactory. ConfigurableListableBeanFactory indirectly inherits BeanFactory. Therefore, in addition to the functions of the Spring basic version container, the ConfigurableListableBeanFactory implementation class also has some advanced functions. The default actual implementation of Springboot is DefaultListableBeanFactory. Interested friends can use this as an entry point to delve deeper, but I won’t go into details here.

Insert image description here

2. Custom implementation

2.1 MyBeanDefinitionRegistryPostProcessor

The following uses a specific class MyBeanDefinitionRegistryPostProcessor to implement the BeanDefinitionRegistryPostProcessor interface to explore the initialization and execution process of the BeanDefinitionRegistryPostProcessor implementation class.

When the postProcessBeanDefinitionRegistry() method is called, the BeanDefinition information of the Dog class is manually registered in Spring;

When the postProcessBeanFactory() method is called, retrieve the BeanDefinition information of the Dog class and the instance of the Dog class from the Spring container;

@Data
public class Dog {
    
    
    private String name;
    private String color;
}
@Component
public class MyBeanDefinitionRegistryPostProcessor implements BeanDefinitionRegistryPostProcessor {
    
    
    @Override
    public void postProcessBeanDefinitionRegistry(BeanDefinitionRegistry registry) throws BeansException {
    
    
        //手工定义一个beanDefinition实例
        RootBeanDefinition beanDefinition = new RootBeanDefinition();
        //给beanDefinition填充属性
        beanDefinition.setBeanClass(Dog.class);
        MutablePropertyValues propertyValues = new MutablePropertyValues();
        PropertyValue propertyValue1 = new PropertyValue("name", "旺财");
        PropertyValue propertyValue2 = new PropertyValue("color", "黑色");
        propertyValues.addPropertyValue(propertyValue1);
        propertyValues.addPropertyValue(propertyValue2);
        beanDefinition.setPropertyValues(propertyValues);
        //注册手工定义的beanDefinition
        registry.registerBeanDefinition("dog", beanDefinition);
    }
    @Override
    public void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) throws BeansException {
    
    
        System.out.println("-----------start------------");
        //根据类名取出手工注册的beanDefinition
        BeanDefinition beanDefinition = beanFactory.getBeanDefinition("dog");
        System.out.println(beanDefinition.getBeanClassName());
        //根据类从容器中取出手工注册的beanDefinition所描述的实例bean
        Dog dog = beanFactory.getBean(Dog.class);
        System.out.println(dog.getName());
        System.out.println(dog.getColor());
        System.out.println("-----------end------------");
    }
}

unit test

@Test
public void test(){
    
    
    AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext("com.fanfu");
    Dog dog = ((Dog) context.getBean("dog"));
    System.out.println(dog.getName());
    System.out.println(dog.getColor());
}

2.2 UML class diagram

It can be seen from the BeanDefinitionRegistryPostProcessorUML class diagram that BeanDefinitionRegistryPostProcessor inherits BeanFactoryPostProcessor, the postProcessBeanDefinitionRegistry() method belongs to BeanDefinitionRegistryPostProcessor, and postProcessBeanFactory() belongs to BeanFactoryPostProcessor. All implementation classes that implement the BeanDefinitionRegistryPostProcessor interface need to implement these two methods as extension points of Springboot. one of The logic of its expansion is also in these two methods.

Insert image description here

3. Initialization and execution timing

Through the customized MyBeanDefinitionRegistryPostProcessor class, the BeanDefinitionRegistryPostProcessor interface is implemented. Starting from the project startup, the execution process is as follows:

  1. Executing the main class of the project, org.springframework.boot.SpringApplication#run is called;

  2. After entering the boot.SpringApplication#run method, there are some configuration operations for Spring container initialization at the beginning, until org.springframework.boot.SpringApplication#refreshContext is executed, the container refresh starts, and the critical stage is entered;

  3. In SpringApplication#refreshContext, the actual refresh logic is in the org.springframework.context.support.AbstractApplicationContext#refresh method;

  4. In the AbstractApplicationContext#refresh method, call org.springframework.context.support.AbstractApplicationContext#invokeBeanFactoryPostProcessors to start initializing and executing postProcessBeanDefinitionRegistry() and postProcessBeanFactory() that implement the BeanDefinitionRegistryPostProcessor interface;

  5. Entering the AbstractApplicationContext#invokeBeanFactoryPostProcessors method, we found that org.springframework.context.support.PostProcessorRegistrationDelegate#invokeBeanFactoryPostProcessors() was called again;

  6. In the PostProcessorRegistrationDelegate#invokeBeanFactoryPostProcessors() method, postProcessBeanDefinitionRegistry() and postProcessBeanFactory() are not directly initialized and executed, but a series of judgments are made. The order of judgment is: 1. BeanDefinitionRegistryPostProcessor implementation registered in advance through AbstractApplicationContext#addBeanFactoryPostProcessor Class; 2. Implements the PriorityOrdered interface; 3. Whether Ordered is implemented; 4. The remaining other BeanDefinitionRegistryPostProcessor implementation classes; the customized MyBeanDefinitionRegistryPostProcessor belongs to the 4th category, so it is executed later among all implementations. If you want To be executed in advance, you can consider the previous three methods;

  7. After executing the MyBeanDefinitionRegistryPostProcessor#postProcessBeanDefinitionRegistry method in the PostProcessorRegistrationDelegate#invokeBeanFactoryPostProcessors() method, the MyBeanDefinitionRegistryPostProcessor#postProcessBeanFactory method begins to execute; from the entire calling process, postProcessBeanDefinitionRegistry() is executed earlier than the postProcessBeanFactory() method;

Below is a timing diagram I drew based on the entire calling process. The process is indeed complicated, but the logic is relatively clear, so it is not difficult to understand. If you want to really understand the entire process, the best way is to follow this diagram and execute it yourself. Once again, observe the execution process of each key node through debugging.
Insert image description here

4. Internal implementation class

The built-in implementation classes in spring-boot-starter-web include CachingMetadataReaderFactoryPostProcessor, ConfigurationClassPostProcessor, ConfigurationWarningsPostProcessor, EmbeddedDataSourceBeanFactoryPostProcessor, ImportsCleanupPostProcessor, TestRestTemplateRegistrar, WebTestClientRegistrar, WsdlDefinitionBeanFactoryPostProcessor. Observe each implementation class. Found: They are all similar, these built-in implementation classes are all in Springboot The internal classes of BeanDefinitionRegistryPostProcessor register some special BeanDefinitions in the Spring container through these BeanDefinitionRegistryPostProcessor internal implementation classes. If we expand and talk about these Beans in detail, I may not be able to finish it all day and night. Interested friends can learn more about it here. It won't expand anymore.

5. Summary

By sorting out the entire process, the most critical thing is actually one sentence: after the Spring container is initialized and before refreshing, that is, after the Bean has been scanned and registered as a BeanDefinition, but before it is formally instantiated, you can perform some additional operations by implementing BeanDefinitionRegistryPostProcessor.
——————————————
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/128538625

Guess you like

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