Spring extension point 2: Analysis of the principle of custom beanPostProcessor

beanPostProcessor is one of the interfaces that I have seen the most extensions in learning spring source code, such as: aop, spring transaction, initialization method callback, all of which are extensions and implementations of this interface, except for the framework of spring itself, such as Dubbo's ReferenceAnnotationBeanPostProcessor, This extended class is a post processor, used to parse the @Reference annotation

Bean post processor, in the process of initializing the bean, spring has defined which method of the post processor will be executed first, and which method will be executed later. Therefore, when we expand, we must be familiar with the execution location and sequence of these methods. Sequence, according to these, to clarify at which step your business needs need to be expanded

We only need to implement it according to different beanPostProcess subclasses

Preface

No matter which extension class we implement, we need to consider two questions:
1. After we extend, if we put our custom extension class in the spring container
2. After putting it in the container, will it follow the steps we envisioned? To call
For the first point, we can directly pass the @Component annotation, put the beanPostProcessor as an ordinary bean in the beanDefinitionMap, because in the spring startup process, there is a step to register and initialize all the post-processing separately is,
therefore, the first point, we only need to remember, as long as the beanPostProcessor as a bean can be added to the beanDefinitionMap, spring will automatically help us to initialize the postprocessor

Regarding the second point, after we provide an implementation class, how does spring apply the beanPostProcessor we define to the initialization process? It is also related to the registered beanPostProcessor mentioned above. After spring initializes all the post processors, it will put the initialized post processors in a collection, and spring will call the post processor method every time At this time, all eligible post processors will be obtained from this list set to filter

In fact, for the principle of the extension mechanism of the post processor in spring, I think that if I understand these two sentences, I will understand it all.

Regarding the first point, how to put the post processor we provide into the spring container, you can refer to the previous note Spring source code: Registering post processor

Register post processor

The second point:
Let’s first talk about our custom post processor, where is it stored in
org.springframework.context.support.PostProcessorRegistrationDelegate#registerBeanPostProcessors()
This method is spring to initialize all post processors, then After the initialization is complete, there is a more critical operation
registerBeanPostProcessors(beanFactory, orderedPostProcessors);
registerBeanPostProcessors(beanFactory, nonOrderedPostProcessors);
registerBeanPostProcessors(beanFactory, internalPostProcessors);

These three lines of code call the same logic, but the input parameters are different. Look at the specific processing logic of the method

private static void registerBeanPostProcessors(
      ConfigurableListableBeanFactory beanFactory, List<BeanPostProcessor> postProcessors) {
    
    

    for (BeanPostProcessor postProcessor : postProcessors) {
    
    
      beanFactory.addBeanPostProcessor(postProcessor);
    }
  }


  @Override
  public void addBeanPostProcessor(BeanPostProcessor beanPostProcessor) {
    
    
    Assert.notNull(beanPostProcessor, "BeanPostProcessor must not be null");
    // Remove from old position, if any
    this.beanPostProcessors.remove(beanPostProcessor);
    // Track whether it is instantiation/destruction aware
    if (beanPostProcessor instanceof InstantiationAwareBeanPostProcessor) {
    
    
      this.hasInstantiationAwareBeanPostProcessors = true;
    }
    if (beanPostProcessor instanceof DestructionAwareBeanPostProcessor) {
    
    
      this.hasDestructionAwareBeanPostProcessors = true;
    }
    // Add to end of list
    this.beanPostProcessors.add(beanPostProcessor);
  }

The most important thing here is the last line of code, put beanPostProcess into the private final List beanPostProcessors = new CopyOnWriteArrayList<>(); in this collection, this collection is in the source code later, we will see, first have an impression

How does the custom post processor take effect

Let’s take the fifth post-processor method org.springframework.beans.factory.config.InstantiationAwareBeanPostProcessor#postProcessAfterInstantiation
as an example. This method is called before attribute injection to determine whether attribute injection is required.
1. If this method returns false, it means that the current bean does not need attribute injection.
2. So if I have a requirement at this time, I need to process the PayOrderService class. There is no need for attribute injection in this class. Here I just give an example. At this time, I can provide an implementation class of InstantiationAwareBeanPostProcessor by myself, and then implement it. In the postProcessAfterInstantiation() method of the class, it is judged that if the currently initialized bean is payOrderService, it returns false.
3. It should be noted that if we extend the implementation class ourselves, we must add the judgment of the bean to the implementation method. Otherwise, all beans will not perform property injection, why? Because each bean will call our own implementation class when it is initialized to determine whether to inject properties

Here is a point to explain, why is the InstantiationAwareBeanPostProcessor method, because InstantiationAwareBeanPostProcessor inherits BeanPostProcessor, so this is also an extension interface of the post processor;
for the third point, we must determine whether the bean is to skip attribute injection by itself Bean, you can look at the spring source code. The default implementation method basically returns true, which requires attribute injection.

org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory#populateBean

boolean continueWithPropertyPopulation = true;

if (!mbd.isSynthetic() && hasInstantiationAwareBeanPostProcessors()) {
    
    
  for (BeanPostProcessor bp : getBeanPostProcessors()) {
    
    
    if (bp instanceof InstantiationAwareBeanPostProcessor) {
    
    
      InstantiationAwareBeanPostProcessor ibp = (InstantiationAwareBeanPostProcessor) bp;
      if (!ibp.postProcessAfterInstantiation(bw.getWrappedInstance(), beanName)) {
    
    
        continueWithPropertyPopulation = false;
        break;
      }
    }
  }
}

if (!continueWithPropertyPopulation) {
    
    
  return;
}

This piece of code is the processing of postProcessAfterInstantiation. As you can see, in the source code, it will first determine whether the current beanDefinition is a synthetic beanDefinition, and then determine whether there is an implementation class of InstantiationAwareBeanPostProcessor in the current container.

protected boolean hasInstantiationAwareBeanPostProcessors() {
    
    
  return this.hasInstantiationAwareBeanPostProcessors;
}

When is hasInstantiationAwareBeanPostProcessors assigned? Register the post processor above in the addBeanPostProcessor method here

After judging these, it will go to traverse the list collection returned by getBeanPostProcessors()

public List<BeanPostProcessor> getBeanPostProcessors() {
    
    
	return this.beanPostProcessors;
}

As mentioned earlier, the list of beanPostProcessors will appear and be used later, which is here.
So here is an explanation. How does our custom beanPostProcess implementation class take effect?
In the spring source code, every time the post processor method is called, it will traverse all the post processors in the container and call the post processor methods in turn for processing.

to sum up

Finally, make a small summary. If we want to extend a beanPostProcess implementation class, this implementation class should implement different beanPostProcess interfaces according to what we want to do, and then inject the implementation class into the spring container through the @Component annotation. There is no need to do other operations. Spring will help us complete the call for the rest.
However, when we extend, we need to understand how our extended business logic is implemented.

Guess you like

Origin blog.csdn.net/CPLASF_/article/details/115079069