Spring IOC: invokeBeanFactoryPostProcessors call chain

reference material

Spring IoC source code learning: detailed explanation of invokebeanfactoryprocessors

Previously:

Spring IOC: obtainFreshBeanFactory call chain

Written at the beginning: This article is a personal study note. The content is relatively casual and mixed with personal understanding. If there are mistakes, you are welcome to correct them.

catalogue

1, Overview

2, Invokebeanfactoryprocessors

        1,getBeanFactoryPostProcessors

        2,invokeBeanFactoryPostProcessors 

3, Getbeanfactoryprocessors

        1,getBeanFactoryPostProcessors

2. Add custom beanfactoryprocessor

3, Invokebeanfactoryprocessors

1. Distinguish BeanDefinitionRegistryPostProcessor from beanfactoryprocessor

2. Implement BeanDefinitionRegistryPostProcessor according to priority

3. Instantiate the remaining BeanDefinitionRegistryPostProcessors and some beanfactoryprocessors

4. Repeat steps 2 and 3 for beanfactoryprocessor

Summary:

​​​​​​​

1, Overview

The invokebeanfactoryprocessors method instantiates and calls all beanfactoryprocessors (including its subclass BeanDefinitionRegistryPostProcessor).

The beanfactoryprocessor interface is an extension point exposed when Spring initializes BeanFactory. The Spring IoC container allows beanfactoryprocessor to read the bean definition and modify it before the container instantiates any bean.

2, Invokebeanfactoryprocessors

2 important steps:

        1,getBeanFactoryPostProcessors

Get the value in the beanfactoryprocessors variable of the current application context

        2,invokeBeanFactoryPostProcessors 

Instantiate and call all registered beanfactorypost processors

protected void invokeBeanFactoryPostProcessors(ConfigurableListableBeanFactory beanFactory) {
    // Getbeanfactoryprocessors(): get the value in the beanfactoryprocessors variable of the current application context
    // Invokebeanfactoryprocessors: instantiate and call all registered beanfactoryprocessors
    PostProcessorRegistrationDelegate.invokeBeanFactoryPostProcessors(beanFactory, getBeanFactoryPostProcessors());
 

    if (beanFactory.getTempClassLoader() == null && beanFactory.containsBean(LOAD_TIME_WEAVER_BEAN_NAME)) {
        beanFactory.addBeanPostProcessor(new LoadTimeWeaverAwareProcessor(beanFactory));
        beanFactory.setTempClassLoader(new ContextTypeMatchClassLoader(beanFactory.getBeanClassLoader()));
    }
}

3, Getbeanfactoryprocessors

        1,getBeanFactoryPostProcessors

Get the beanfactoryprocessor that has been registered in the current application context. By default, it returns null.

public List<BeanFactoryPostProcessor> getBeanFactoryPostProcessors() {
    return this.beanFactoryPostProcessors;
}

2. Add custom beanfactoryprocessor

In Spring IOC: from ContextLoaderListener to AbstractApplicationContext The customizeContext method described in will read the web through the determineContextInitializerClasses method The parameters in XML (globalInitializerClasses and contextInitializerClasses) initialize the classes that implement the ApplicationContextInitializer interface.

        protected void customizeContext(ServletContext sc, ConfigurableWebApplicationContext wac) {
        //Gets the initializer class collection
        List<Class<ApplicationContextInitializer<ConfigurableApplicationContext>>> initializerClasses =
                determineContextInitializerClasses(sc);
 
        for (Class<ApplicationContextInitializer<ConfigurableApplicationContext>> initializerClass : initializerClasses) {
            Class<?> initializerContextClass =
                    GenericTypeResolver.resolveTypeArgument(initializerClass, ApplicationContextInitializer.class);
            if (initializerContextClass != null && !initializerContextClass.isInstance(wac)) {
                throw new ApplicationContextException(String.format(
                        "Could not apply context initializer [%s] since its generic parameter [%s] " +
                        "is not assignable from the type of application context used by this " +
                        "context loader: [%s]", initializerClass.getName(), initializerContextClass.getName(),
                        wac.getClass().getName()));
            }
            //Instantiate the initializer and add it to the collection
            this.contextInitializers.add(BeanUtils.instantiateClass(initializerClass));
        }
        //Sort and execute. The smaller the number, the earlier the execution
        AnnotationAwareOrderComparator.sort(this.contextInitializers);
        for (ApplicationContextInitializer<ConfigurableApplicationContext> initializer : this.contextInitializers) {
            initializer.initialize(wac);
        }
    }

    protected List<Class<ApplicationContextInitializer<ConfigurableApplicationContext>>>
            determineContextInitializerClasses(ServletContext servletContext) {
 
        List<Class<ApplicationContextInitializer<ConfigurableApplicationContext>>> classes =
                new ArrayList<Class<ApplicationContextInitializer<ConfigurableApplicationContext>>>();
        //Configure globalInitializerClasses through the < context param > attribute to obtain the global initialization class name
        String globalClassNames = servletContext.getInitParameter(GLOBAL_INITIALIZER_CLASSES_PARAM);
        if (globalClassNames != null) {
            for (String className : StringUtils.tokenizeToStringArray(globalClassNames, INIT_PARAM_DELIMITERS)) {
                classes.add(loadInitializerClass(className));
            }
        }
        //Configure contextInitializerClasses through the < context param > attribute to obtain the container initialization class name
        String localClassNames = servletContext.getInitParameter(CONTEXT_INITIALIZER_CLASSES_PARAM);
        if (localClassNames != null) {
            for (String className : StringUtils.tokenizeToStringArray(localClassNames, INIT_PARAM_DELIMITERS)) {
                classes.add(loadInitializerClass(className));
            }
        }
 
        return classes;
    }

    @SuppressWarnings("unchecked")
    private Class<ApplicationContextInitializer<ConfigurableApplicationContext>> loadInitializerClass(String className) {
    try {
        // Instantiate className
        Class<?> clazz = ClassUtils.forName(className, ClassUtils.getDefaultClassLoader());
        if (!ApplicationContextInitializer.class.isAssignableFrom(clazz)) {
            // Verify whether clazz implements the ApplicationContextInitializer interface. If not, throw an exception
            throw new ApplicationContextException(
                    "Initializer class does not implement ApplicationContextInitializer interface: " + clazz);
        }
        // clazz is strongly converted to ApplicationContextInitializer and returns
        return (Class<ApplicationContextInitializer<ConfigurableApplicationContext>>) clazz;
    } catch (ClassNotFoundException ex) {
        throw new ApplicationContextException("Failed to load context initializer class [" + className + "]", ex);
    }
}

We create a new implementation class of ApplicationContextInitializer and rewrite the initialize method to realize personalized logic, in which we manually add MyBeanFactoryPostProcessor that inherits the BeanFactoryPostProcessor interface. And register it in the context through globalInitializerClasses to realize the pre storage function of beanfactoryprocessors.

public class MyApplicationContextInitializer implements ApplicationContextInitializer<ConfigurableApplicationContext>
{

    public void initialize(ConfigurableApplicationContext applicationContext) {
        MyBeanFactoryPostProcessor myBeanFactoryPostProcessor = new MyBeanFactoryPostProcessor();
        applicationContext.addBeanFactoryPostProcessor(myBeanFactoryPostProcessor);
        System.out.println("Will be customized MyBeanFactoryPostProcessor Add to application context");
    }
}
<context-param>
    <param-name>globalInitializerClasses</param-name>
    <param-value>
        com.test.MyApplicationContextInitializer
    </param-value>
</context-param>

        

3, Invokebeanfactoryprocessors

First, let's introduce BeanFactoryPostProcessor and its subclass BeanDefinitionRegistryPostProcessor.

The beanfactoryprocessor interface is an extension point exposed when Spring initializes BeanFactory. The Spring IoC container allows beanfactoryprocessor to read the bean definition and modify it before the container instantiates any bean.

BeanDefinitionRegistryPostProcessor inherits from beanfactoryprocessor and has higher priority than beanfactoryprocessor. It is mainly used to execute before the start of conventional beanfactoryprocessor detection. In particular, you can register some regular beanfactorypost processors through BeanDefinitionRegistryPostProcessor. Because at this time, all conventional beanfactoryprocessor have not started to be processed.

For the introduction of beanfactoryprocessor, please refer to the article I wrote before Portal

Because the whole code of invokebeanfactoryprocessors is long, it is divided into several sections according to the execution steps, as shown in the following figure.

public static void registerBeanPostProcessors(
			ConfigurableListableBeanFactory beanFactory, AbstractApplicationContext applicationContext) {
    1,distinguish BeanDefinitionRegistryPostProcessor And BeanFactoryPostProcessor
    2,Implement according to priority BeanDefinitionRegistryPostProcessor
    3,Instantiate surplus BeanDefinitionRegistryPostProcessors And part BeanFactoryPostProcessor
    4,in the light of BeanFactoryPostProcessor Repeat steps 2 and 3
}

1. Distinguish BeanDefinitionRegistryPostProcessor from beanfactoryprocessor

Traverse the parameter beanfactoryprocessors and distinguish BeanDefinitionRegistryPostProcessor from beanfactoryprocessor. The former directly executes its postProcessBeanDefinitionRegistry method one step more than the latter, and then stores it in registryProcessors and regularPostProcessors respectively.

Note: what is stored and implemented here is the beanfactoryprocessors passed as parameters, that is, the beanfactoryprocessor extended and implemented by ApplicationContextInitializer described earlier, excluding the beanfactoryprocessor registered in the container.

    Set<String> processedBeans = new HashSet<String>();
 
    // Judge whether beanFactory is BeanDefinitionRegistry, and beanFactory is DefaultListableBeanFactory,
    // The DefaultListableBeanFactory implements the BeanDefinitionRegistry interface, so it is true here
    if (beanFactory instanceof BeanDefinitionRegistry) {
        BeanDefinitionRegistry registry = (BeanDefinitionRegistry) beanFactory;
        // It is used to store ordinary beanfactoryprocessor
        List<BeanFactoryPostProcessor> regularPostProcessors = new LinkedList<BeanFactoryPostProcessor>();
        // Used to store BeanDefinitionRegistryPostProcessor
        List<BeanDefinitionRegistryPostProcessor> registryProcessors = new LinkedList<BeanDefinitionRegistryPostProcessor>();
 
        // First, process the bean factorypostprocessors in the parameter
        // Traverse all beanfactoryprocessors to distinguish BeanDefinitionRegistryPostProcessor from ordinary beanfactoryprocessor
        for (BeanFactoryPostProcessor postProcessor : beanFactoryPostProcessors) {
            if (postProcessor instanceof BeanDefinitionRegistryPostProcessor) {
                // If it is BeanDefinitionRegistryPostProcessor
                BeanDefinitionRegistryPostProcessor registryProcessor =
                        (BeanDefinitionRegistryPostProcessor) postProcessor;
                // Directly execute the postProcessBeanDefinitionRegistry method of BeanDefinitionRegistryPostProcessor interface
                registryProcessor.postProcessBeanDefinitionRegistry(registry);
                // Added to registryprocessors (used to finally execute the postProcessBeanFactory method)
                registryProcessors.add(registryProcessor);
            } else {
                // Otherwise, it's just an ordinary beanfactoryprocessor
                // Added to regularpostprocessors (used to execute the postProcessBeanFactory method last)
                regularPostProcessors.add(postProcessor);
            }
        }

2. Implement BeanDefinitionRegistryPostProcessor according to priority

(1) find out the beannames of all beans that implement the BeanDefinitionRegistryPostProcessor interface and store them in postProcessorNames (here, the beanName is found from the beanName registered in the obtainFreshBeanFactory method in the previous step through beanFactory.getBeanNamesForType)

(2) traverse the postProcessorNames and filter out the beanName that implements the PriorityOrdered interface (for sorting).

(3) use beanfactory The getBean method creates the bean object corresponding to the BeanDefinitionRegistryPostProcessor. Store the created bean object in currentRegistryProcessors and the beanName in processedBeans.

(4) sort currentRegistryProcessors according to the implementation of PriorityOrdered interface, and then store currentRegistryProcessors into registryProcessors.

(5) traverse currentRegistryProcessors and execute the postProcessBeanDefinitionRegistry method. After execution, clear currentRegistryProcessors.

(6) repeat steps 1-5, but the postProcessorNames will be retrieved. This is because after executing the postProcessBeanDefinitionRegistry method of BeanDefinitionRegistryPostProcessor above, other beandefinitionregistrypostprocessors may be added, so it needs to be searched again. And this step is for the Ordered interface, not the PriorityOrdered interface.

        // Used to save the BeanDefinitionRegistryPostProcessor executed this time
        List<BeanDefinitionRegistryPostProcessor> currentRegistryProcessors = new ArrayList<BeanDefinitionRegistryPostProcessor>();

        // Call all BeanDefinitionRegistryPostProcessor implementation classes that implement the PriorityOrdered interface
        // Find the beanName of all beans that implement the BeanDefinitionRegistryPostProcessor interface
        String[] postProcessorNames =
                beanFactory.getBeanNamesForType(BeanDefinitionRegistryPostProcessor.class, true, false);
        // Traverse postProcessorNames
        for (String ppName : postProcessorNames) {
            // Verify whether the PriorityOrdered interface is implemented
            if (beanFactory.isTypeMatch(ppName, PriorityOrdered.class)) {
                // Get the bean instance corresponding to ppName and add it to currentRegistryProcessors,
                // beanFactory.getBean: the getBean method here will trigger the creation of the bean object corresponding to ppName, which will not be deeply resolved at present
                currentRegistryProcessors.add(beanFactory.getBean(ppName, BeanDefinitionRegistryPostProcessor.class));
                // Join the processedBeans to be executed to avoid subsequent repeated execution
                processedBeans.add(ppName);
            }
        }
        // Sort (sort according to whether PriorityOrdered, Ordered interface and order value are implemented)
        sortPostProcessors(currentRegistryProcessors, beanFactory);
        // Added to registryprocessors (used to finally execute the postProcessBeanFactory method)
        registryProcessors.addAll(currentRegistryProcessors);
        // Traverse currentRegistryProcessors and execute the postProcessBeanDefinitionRegistry method
        invokeBeanDefinitionRegistryPostProcessors(currentRegistryProcessors, registry);
        // After execution, clear currentRegistryProcessors
        currentRegistryProcessors.clear();
 

        // Call all BeanDefinitionRegistryPostProcessor implementation classes that implement the Ordered interface (the process is basically the same as step 3 above)
        // Find out all classes that implement the BeanDefinitionRegistryPostProcessor interface. Repeat the search here because the BeanDefinitionRegistryPostProcessor above is executed,
        // Other BeanDefinitionRegistryPostProcessor may be added, so it needs to be searched again
        postProcessorNames = beanFactory.getBeanNamesForType(BeanDefinitionRegistryPostProcessor.class, true, false);
        for (String ppName : postProcessorNames) {
            // Verify whether the Ordered interface is implemented and has not been executed
            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);
        // Traverse currentRegistryProcessors and execute the postProcessBeanDefinitionRegistry method
        invokeBeanDefinitionRegistryPostProcessors(currentRegistryProcessors, registry);
        currentRegistryProcessors.clear();

3. Instantiate the remaining BeanDefinitionRegistryPostProcessors and some beanfactoryprocessors

(1) call beanfactory Getbeannamesfortype finds all classes that implement the BeanDefinitionRegistryPostProcessor interface and skips those that have already been executed.

(2) repeat steps 3, 4 and 5 in the previous section.

(3) take out all beandefinitionregistrypostprocessors from registryProcessors and execute its postProcessBeanFactory method.

(4) call the postProcessBeanFactory method of beanfactoryprocessor in beanfactoryprocessors.

        // Finally, call all the remaining BeanDefinitionRegistryPostProcessors.
        boolean reiterate = true;
        while (reiterate) {
            reiterate = false;
            // Find all classes that implement the BeanDefinitionRegistryPostProcessor interface
            postProcessorNames = beanFactory.getBeanNamesForType(BeanDefinitionRegistryPostProcessor.class, true, false);
            for (String ppName : postProcessorNames) {
                // Skip already executed
                if (!processedBeans.contains(ppName)) {
                    currentRegistryProcessors.add(beanFactory.getBean(ppName, BeanDefinitionRegistryPostProcessor.class));
                    processedBeans.add(ppName);
                    // If a BeanDefinitionRegistryPostProcessor is executed, a new BeanDefinitionRegistryPostProcessor may be generated,
                    // Therefore, the value of repeat is set to true, which means that it needs to be searched again
                    reiterate = true;
                }
            }
            sortPostProcessors(currentRegistryProcessors, beanFactory);
            registryProcessors.addAll(currentRegistryProcessors);
            // Traverse currentRegistryProcessors and execute the postProcessBeanDefinitionRegistry method
            invokeBeanDefinitionRegistryPostProcessors(currentRegistryProcessors, registry);
            currentRegistryProcessors.clear();
        }
 

        // 6. Call the postProcessBeanFactory method of all beandefinitionregistrypostprocessors (BeanDefinitionRegistryPostProcessor inherits from beanfactoryprocessor)
        invokeBeanFactoryPostProcessors(registryProcessors, beanFactory);
        // Finally, call the postProcessBeanFactory method of the common BeanFactoryPostProcessor in parameter beanFactoryPostProcessors.
        invokeBeanFactoryPostProcessors(regularPostProcessors, beanFactory);
    } else {
        
        invokeBeanFactoryPostProcessors(beanFactoryPostProcessors, beanFactory);
    }

4. Repeat steps 2 and 3 for beanfactoryprocessor

After the first three steps, all beandefinitionregistrypostprocessors have been processed, including the input beanfactoryprocessors and all registered beanfactoryprocessors in the container. Now start processing all beanfactoryprocessors in the container.

Step 4 imitates the operations of the previous two steps, but replaces BeanDefinitionRegistryPostProcessor with beanfactoryprocessor.

    // Find all the classes that implement the beanfactoryprocessor interface
    String[] postProcessorNames =
            beanFactory.getBeanNamesForType(BeanFactoryPostProcessor.class, true, false);
 
    // It is used to store the beanfactorypost processor that implements the PriorityOrdered interface
    List<BeanFactoryPostProcessor> priorityOrderedPostProcessors = new ArrayList<BeanFactoryPostProcessor>();
    // The beanName used to store the beanfactoryprocessor that implements the Ordered interface
    List<String> orderedPostProcessorNames = new ArrayList<String>();
    // beanName for storing ordinary beanfactoryprocessor
    List<String> nonOrderedPostProcessorNames = new ArrayList<String>();
    // Traverse the postProcessorNames and distinguish the beanfactory postprocessor according to the implementation of PriorityOrdered, the implementation of Ordered interface and ordinary
    for (String ppName : postProcessorNames) {
        // Skip already executed
        if (processedBeans.contains(ppName)) {

        } else if (beanFactory.isTypeMatch(ppName, PriorityOrdered.class)) {
            // Add beanfactoryprocessor that implements the PriorityOrdered interface
            priorityOrderedPostProcessors.add(beanFactory.getBean(ppName, BeanFactoryPostProcessor.class));
        } else if (beanFactory.isTypeMatch(ppName, Ordered.class)) {
            // Add the beanName of beanfactoryprocessor that implements the Ordered interface
            orderedPostProcessorNames.add(ppName);
        } else {
            // Add the beanName of the remaining ordinary beanfactoryprocessor
            nonOrderedPostProcessorNames.add(ppName);
        }
    }
 
    // Call all beanfactoryprocessors that implement the PriorityOrdered interface
    // Sort priorityOrderedPostProcessors
    sortPostProcessors(priorityOrderedPostProcessors, beanFactory);
    // Traverse priorityOrderedPostProcessors and execute the postProcessBeanFactory method
    invokeBeanFactoryPostProcessors(priorityOrderedPostProcessors, beanFactory);
 
    // Call all beanfactoryprocessors that implement the Ordered interface
    List<BeanFactoryPostProcessor> orderedPostProcessors = new ArrayList<BeanFactoryPostProcessor>();
    for (String postProcessorName : orderedPostProcessorNames) {
        // Get the bean instance corresponding to the postProcessorName, add it to orderedPostProcessors, and prepare for execution
        orderedPostProcessors.add(beanFactory.getBean(postProcessorName, BeanFactoryPostProcessor.class));
    }
    // Sort orderedPostProcessors
    sortPostProcessors(orderedPostProcessors, beanFactory);
    // Traverse orderedPostProcessors and execute the postProcessBeanFactory method
    invokeBeanFactoryPostProcessors(orderedPostProcessors, beanFactory);
 
    // Call all remaining beanfactoryprocessor
    List<BeanFactoryPostProcessor> nonOrderedPostProcessors = new ArrayList<BeanFactoryPostProcessor>();
    for (String postProcessorName : nonOrderedPostProcessorNames) {
        // Get the bean instance corresponding to postProcessorName, add it to nonOrderedPostProcessors, and prepare for execution
        nonOrderedPostProcessors.add(beanFactory.getBean(postProcessorName, BeanFactoryPostProcessor.class));
    }
    // Traverse the nonOrderedPostProcessors and execute the postProcessBeanFactory method
    invokeBeanFactoryPostProcessors(nonOrderedPostProcessors, beanFactory);
 
    // Clear the metadata cache (mergedBeanDefinitions, allBeanNamesByType, singletonBeanNamesByType),
    // Because the postprocessor may have modified the original metadata, for example, replacing placeholders in values
    beanFactory.clearMetadataCache();

Summary:

The whole process first obtains globalInitializerClasses and contextInitializerClasses from the context, and manually adds them to beanfactoryprocessor and BeanDefinitionRegistryPostProcessor in the context.

Then store them separately and implement the postProcessBeanDefinitionRegistry method of BeanDefinitionRegistryPostProcessor. Then obtain the BeanDefinitionRegistryPostProcessor registered in beanFactory, filter out the beanName that implements the PriorityOrdered interface, and implement it in turn after sorting. Repeat the same steps for the Ordered interface. Finally, execute the postProcessBeanDefinitionRegistry method successively for the beanName of the remaining BeanDefinitionRegistryPostProcessor type in beanFactory. Finally, call the postProcessBeanFactory method of BeanFactoryPostProcessor in reference beanFactoryPostProcessors.

Then, repeat the process of BeanDefinitionRegistryPostProcessor and replace the object with beanfactoryprocessor.

Keywords: Spring

Added by Atiq on Thu, 27 Jan 2022 14:30:30 +0200