preface

InvokeBeanFactoryPostProcessors executes the BeanFactory post processor. If you look at this, you have a question:

  1. What is BeanFactoryPostProcessor?
  2. How can BeanfactoryPostProcessor be used?

Know the answer to both questions above, have the knowledge of spring BeanFactoryPostProcessor, deep source then, continue reading invokeBeanFactoryPostProcessors this method.

role

The answer can be found on the official website:

The Spring IoC container allows the BeanFactoryPostProcessor to read configuration metadata and possibly change it before the container instantiates any beans other than the BeanFactoryPostProcessor instance.

The BeanFactoryPostProcessor can also be Ordered using the Ordered interface.

Pay attention to

BeanFactoryPostProcessor operates on BeanDefinition, or metadata. It is also possible to instantiate beans by obtaining the BeanFactory, but this is not recommended on the official website.

The sample

The use of spring BeanFactoryPostProcessor

@Component
public class MyBeanFactoryPostProcessor implements BeanFactoryPostProcessor {

    @Override
    public void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) throws BeansException {

        // Modify the BeanDefinition information
        BeanDefinition userComponentBeanDefinition = beanFactory.getBeanDefinition("userComponent");
        userComponentBeanDefinition.setLazyInit(true);

        // Modify the Bean information
        // XXX strongly does not recommend premature instantiation of beans by beanfactory.getBean
        UserComponent bean = beanFactory.getBean(UserComponent.class);
        bean.setUserName("liuzhihang-01"); }}Copy the code

Create your own BeanFactoryPostProcessor and implement the BeanFactoryPostProcessor interface by adding annotations.

In addition to implementing the BeanFactoryPostProcessor interface, there are other interfaces:

Using BeanDefinitionRegistryPostProcessor

BeanDefinitionRegistryPostProcessor inherited spring BeanFactoryPostProcessor, extend the increased postProcessBeanDefinitionRegistry method at the same time. It is possible to operate on a BeanDefinition after it has been registered and before the Bean is instantiated.

@Component
public class MyBeanDefinitionRegistryPostProcessor implements BeanDefinitionRegistryPostProcessor {
    @Override
    public void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) throws BeansException {
        // Modify the BeanDefinition information
        BeanDefinition userComponentBeanDefinition = beanFactory.getBeanDefinition("userComponent");
        userComponentBeanDefinition.setLazyInit(true);

        // Modify the Bean information
        // XXX strongly does not recommend premature instantiation of beans by beanfactory.getBean
        UserComponent bean = beanFactory.getBean(UserComponent.class);
        bean.setUserName("liuzhihang-01");
    }

    @Override
    public void postProcessBeanDefinitionRegistry(BeanDefinitionRegistry registry) throws BeansException {

        // Register a BeanDefinition
        BeanDefinitionBuilder builder = BeanDefinitionBuilder.genericBeanDefinition(OrderComponent.class);

        AbstractBeanDefinition orderComponentBeanDefinition = builder.getBeanDefinition();

        registry.registerBeanDefinition("orderComponent", orderComponentBeanDefinition); }}Copy the code

Here is a screenshot of the test code:

The OrderComponent class does not add any annotations, and after registering as a BeanDefinition, OrderComponent can be retrieved from the container.

How do I modify field properties

It is not recommended to instantiate beans in BeanFactoryPostProcessor.

You can do this by fetching MutablePropertyValues:

@Component
public class MyBeanFactoryPostProcessor implements BeanFactoryPostProcessor {

    @Override
    public void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) throws BeansException {

        // Modify the BeanDefinition information
        BeanDefinition userComponentBeanDefinition = beanFactory.getBeanDefinition("userComponent");
        userComponentBeanDefinition.setLazyInit(true);

        MutablePropertyValues userComponentPropertyValues = userComponentBeanDefinition.getPropertyValues();

        userComponentPropertyValues.addPropertyValue("userName"."liuzhihang-02");

        // Modify the Bean information
        // XXX strongly does not recommend premature instantiation of beans by beanfactory.getBean
        // UserComponent bean = beanFactory.getBean(UserComponent.class);
        // bean.setUserName("liuzhihang-01");}}Copy the code

invokeBeanFactoryPostProcessors

Now I think I know what BeanFactoryPostProcessor does, and the main purpose of this step is to instantiate all beanFactoryPostProcessors.

Enter the source code:

protected void invokeBeanFactoryPostProcessors(ConfigurableListableBeanFactory beanFactory) {
    PostProcessorRegistrationDelegate.invokeBeanFactoryPostProcessors(beanFactory, getBeanFactoryPostProcessors());

    // Detect a LoadTimeWeaver and prepare for weaving, if found in the meantime
    // (e.g. through an @Bean method registered by ConfigurationClassPostProcessor)
    if(! IN_NATIVE_IMAGE && beanFactory.getTempClassLoader() ==null && beanFactory.containsBean(LOAD_TIME_WEAVER_BEAN_NAME)) {
        beanFactory.addBeanPostProcessor(new LoadTimeWeaverAwareProcessor(beanFactory));
        beanFactory.setTempClassLoader(newContextTypeMatchClassLoader(beanFactory.getBeanClassLoader())); }}Copy the code

The spring BeanFactoryPostProcessor getBeanFactoryPostProcessors method to obtain their add. What does that mean?

public List<BeanFactoryPostProcessor> getBeanFactoryPostProcessors(a) {
    return this.beanFactoryPostProcessors;
}
Copy the code

To see the source is directly from beanFactoryPostProcessors get, and how to add?

Container addBeanFactoryPostProcessor method actually call.

Continue reading the key code invokeBeanFactoryPostProcessors:

Notice how long this code is!

public static void invokeBeanFactoryPostProcessors( ConfigurableListableBeanFactory beanFactory, List
       
         beanFactoryPostProcessors)
        {

    // Invoke BeanDefinitionRegistryPostProcessors first, if any.
    Set<String> processedBeans = new HashSet<>();

    // Determine whether it is BeanDefinitionRegistry
    / / the debug incoming is DefaultListableBeanFactory found here
    / / DefaultListableBeanFactory BeanDefinitionRegistry is realized
    if (beanFactory instanceof BeanDefinitionRegistry) {
        BeanDefinitionRegistry registry = (BeanDefinitionRegistry) beanFactory;

        // Create two lists to store processors
        / / BeanDefinitionRegistryPostProcessor spring BeanFactoryPostProcessor as part of the interface
        / / BeanDefinitionRegistryPostProcessor BeanDefinition additional processing, add BeanDefinition
        // See examples for the usage
        List<BeanFactoryPostProcessor> regularPostProcessors = new ArrayList<>();
        List<BeanDefinitionRegistryPostProcessor> registryProcessors = new ArrayList<>();

        / / beanFactoryPostProcessors cycles
        / / beanFactoryPostProcessors is to use the API context. AddBeanFactoryPostProcessor added
        for (BeanFactoryPostProcessor postProcessor : beanFactoryPostProcessors) {

            / / added to registryProcessors BeanDefinitionRegistryPostProcessor to separate
            if (postProcessor instanceof BeanDefinitionRegistryPostProcessor) {
                BeanDefinitionRegistryPostProcessor registryProcessor =
                        (BeanDefinitionRegistryPostProcessor) postProcessor;

                // Process Bean information
                registryProcessor.postProcessBeanDefinitionRegistry(registry);
                registryProcessors.add(registryProcessor);
            } else{ regularPostProcessors.add(postProcessor); }}// Do not initialize FactoryBeans here: We need to leave all regular beans
        // uninitialized to let the bean factory post-processors apply to them!
        // Separate between BeanDefinitionRegistryPostProcessors that implement
        // PriorityOrdered, Ordered, and the rest.
        / / the above circulation is to perform BeanDefinitionRegistryPostProcessor we call API to add
        / / execute next Spring's own BeanDefinitionRegistryPostProcessor collection
        // Execute first those that implement the PriorityOrdered interface, then Ordered the interface, and finally execute the rest
        List<BeanDefinitionRegistryPostProcessor> currentRegistryProcessors = new ArrayList<>();

        // First, invoke the BeanDefinitionRegistryPostProcessors that implement PriorityOrdered.
        / / the first step to call BeanDefinitionRegistryPostProcessors it implements PriorityOrdered
        / / when the initialization reader In the registered ConfigurationClassPostProcessor into the container
        / / BeanDefinitionRegistryPostProcessor BeanDefinitionRegistryPostProcessor is realized
        String[] postProcessorNames =
                beanFactory.getBeanNamesForType(BeanDefinitionRegistryPostProcessor.class, true.false);
        for (String ppName : postProcessorNames) {
            if (beanFactory.isTypeMatch(ppName, PriorityOrdered.class)) {
                / / add bean
                currentRegistryProcessors.add(beanFactory.getBean(ppName, BeanDefinitionRegistryPostProcessor.class));
                // Just add the name after it to determine who has already executedprocessedBeans.add(ppName); }}/ / sorting
        sortPostProcessors(currentRegistryProcessors, beanFactory);
        registryProcessors.addAll(currentRegistryProcessors);

        / / loop execution processors postProcessBeanDefinitionRegistry method
        // This will have to be looked at carefully
        // Debug sees that after this step, another class annotated with @Component is registered in Registry
        invokeBeanDefinitionRegistryPostProcessors(currentRegistryProcessors, registry, beanFactory.getApplicationStartup());
        / / remove
        currentRegistryProcessors.clear();

        // Next, invoke the BeanDefinitionRegistryPostProcessors that implement Ordered.
        // Process the Ordered processor
        postProcessorNames = beanFactory.getBeanNamesForType(BeanDefinitionRegistryPostProcessor.class, true.false);
        for (String ppName : postProcessorNames) {
            // Only those that are not included are executed, and processedBeans are added after execution
            if (!processedBeans.contains(ppName) && beanFactory.isTypeMatch(ppName, Ordered.class)) {
                currentRegistryProcessors.add(beanFactory.getBean(ppName, BeanDefinitionRegistryPostProcessor.class));
                processedBeans.add(ppName);
            }
        }
        / / same as above
        sortPostProcessors(currentRegistryProcessors, beanFactory);
        registryProcessors.addAll(currentRegistryProcessors);
        invokeBeanDefinitionRegistryPostProcessors(currentRegistryProcessors, registry, beanFactory.getApplicationStartup());
        currentRegistryProcessors.clear();

        // Finally, invoke all other BeanDefinitionRegistryPostProcessors until no further ones appear.
        // Execute the rest
        boolean reiterate = true;
        while (reiterate) {
            reiterate = false;
            postProcessorNames = beanFactory.getBeanNamesForType(BeanDefinitionRegistryPostProcessor.class, true.false);
            for (String ppName : postProcessorNames) {
                // Only those that are not included are executed, and processedBeans are added after execution
                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, beanFactory.getApplicationStartup());
            currentRegistryProcessors.clear();
        }

        // Now, invoke the postProcessBeanFactory callback of all processors handled so far.
        / / the above treatment is postProcessBeanDefinitionRegistry is in - > BeanDefinitionRegistryPostProcessor
        PostProcessBeanFactory -> In BeanFactoryPostProcessor
        invokeBeanFactoryPostProcessors(registryProcessors, beanFactory);
        invokeBeanFactoryPostProcessors(regularPostProcessors, beanFactory);
    } else {
        // Invoke factory processors registered with the context instance.
        / / not BeanDefinitionRegistry is the BeanFactory direct execution beanFactoryPostProcessors can
        invokeBeanFactoryPostProcessors(beanFactoryPostProcessors, beanFactory);
    }

    // Do not initialize FactoryBeans here: We need to leave all regular beans
    // uninitialized to let the bean factory post-processors apply to them!

    // Part 2
    / / it is BeanDefinitionRegistryPostProcessor execution
    // Start BeanFactoryPostProcessor
    String[] postProcessorNames =
            beanFactory.getBeanNamesForType(BeanFactoryPostProcessor.class, true.false);

    // Separate between BeanFactoryPostProcessors that implement PriorityOrdered,
    // Ordered, and the rest.
    // Execute in order
    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
            // This is done
        } 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); }}// First, invoke the BeanFactoryPostProcessors that implement PriorityOrdered.
    // Execute that implements PriorityOrdered
    sortPostProcessors(priorityOrderedPostProcessors, beanFactory);
    invokeBeanFactoryPostProcessors(priorityOrderedPostProcessors, beanFactory);

    // Next, invoke the BeanFactoryPostProcessors that implement 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);

    // Finally, invoke all other BeanFactoryPostProcessors.
    List<BeanFactoryPostProcessor> nonOrderedPostProcessors = new ArrayList<>(nonOrderedPostProcessorNames.size());
    for (String postProcessorName : nonOrderedPostProcessorNames) {
        nonOrderedPostProcessors.add(beanFactory.getBean(postProcessorName, BeanFactoryPostProcessor.class));
    }
    invokeBeanFactoryPostProcessors(nonOrderedPostProcessors, beanFactory);

    // Clear cached merged bean definitions since the post-processors might have
    // modified the original metadata, e.g. replacing placeholders in values...
    // Clear unnecessary metadata information
    beanFactory.clearMetadataCache();
}
Copy the code

The above overall can be divided into two parts:

  1. Perform BeanDefinitionRegistryPostProcessor interface in two methods: postProcessBeanDefinitionRegistry and postProcessBeanFactory.
  2. Execute the postProcessBeanFactory method in the BeanFactoryPostProcessor interface.

Take the first part:

  1. First determine if the passed BeanFactory is BeanDefinitionRegistry
    1. Declare two sets of List regularPostProcessors to store BeanFactoryPostProcessor. RegistryProcessors used to store BeanDefinitionRegistryPostProcessor
      1. Circulation beanFactoryPostProcessors, this is the way we use the API spring BeanFactoryPostProcessor added.
      2. BeanDefinitionRegistryPostProcessor postProcessBeanDefinitionRegistry will be executed in the cycle, that is my example that add BeanDefinition demonstration method will be executed.
    2. Start Spring BeanDefinitionRegistryPostProcessor, processing order for PriorityOrdered, Ordered, and the rest
      1. Cycle, add the corresponding BeanDefinitionRegistryPostProcessor to the currentRegistryProcessors set and processedBeans set said to have treatment.
      2. Sort them and add them to the registryProcessors in step 1.
      3. Call invokeBeanDefinitionRegistryPostProcessors perform all the inside of the Processor postProcessBeanDefinitionRegistry method
    3. After perform 1 and 2, all postProcessBeanDefinitionRegistry has been performed, But the postProcessBeanFactory method in the two collections (registryProcessors and regularPostProcessors) has not been executed yet. And then it loops.
  2. If not BeanDefinitionRegistry type, the direct execution of incoming beanFactoryPostProcessors can.

Below is a screenshot of the corresponding code

This is just the first half of this method, the implementation of the BeanDefinitionRegistryPostProcessor postProcessBeanDefinitionRegistry and postProcessBeanFactory inside.

Since there are also processors that directly implement the BeanFactoryPostProcessor, let’s start with the BeanFactoryPostProcessor processor. The process is similar.

conclusion

By reading more about invokeBeanFactoryPostProcessors (the beanFactory); This step summarizes the method.

Spring BeanFactoryPostProcessor role

The Main function of BeanFactoryPostProcessor is to modify the BeanDefinition information after the BeanDefinition is registered and before the Bean is initialized.

Spring BeanFactoryPostProcessor implementation called BeanDefinitionRegistryPostProcessor, it can be extra register new BeanDefinition into the container.

Description of the process

  1. This step mainly deals with BeanFactoryPostProcessor and is divided into two steps.
  2. Perform BeanDefinitionRegistryPostProcessor interface in two methods: postProcessBeanDefinitionRegistry and postProcessBeanFactory.
  3. Execute the postProcessBeanFactory method in the BeanFactoryPostProcessor interface.

Related to recommend

  • PrepareBeanFactory and postProcessBeanFactory
  • Spring source learning 09: Refresh about the process
  • Spring source code 08: Register the configuration class