An overview,

BeanFactoryPostProcessor is an important interface to extend spring container functions, such as modifying bean attribute values and implementing bean dynamic proxy. Many frameworks realize the extension of the Spring container through this interface. For example, when Mybatis integrates with Spring, only mapper interface is defined without implementation class, but Spring can complete automatic injection. How to realize these, this article will explore.

Distinguish between:

  • BeanPostProcessor: bean post-processor that intercepts bean-created objects before and after initialization
  • Spring BeanFactoryPostProcessor: The beanFactory post-processor is called after the beanFactory standard has been initialized. At this point, all bean definitions have been saved and loaded into the beanFactory, but the bean instance has not been created. At this point, the bean properties can be modified and extended

Ii. Case analysis

/ / start the class
@Test
public void TestMain(a) {
    // Create an IOC container
    new AnnotationConfigApplicationContext(AppConfig.class);
}

// The bean to inject
public class User {
    public User(a){
        System.out.println("user create"); }}/ / configuration class
@ComponentScan("config")
@Configuration
public class AppConfig {
    @Bean
    public User user(a){
        return newUser(); }}// BeanFactoryPostProcessor implementation class
@Component
public class MyBeanFactoryPostProcessor implements BeanFactoryPostProcessor {
    public void postProcessBeanFactory(ConfigurableListableBeanFactory configurableListableBeanFactory) throws BeansException {
        System.out.println("MyBeanFactoryPostProcessor#postProcessBeanFactory");
        int count = configurableListableBeanFactory.getBeanDefinitionCount();
        String[] names = configurableListableBeanFactory.getBeanDefinitionNames();
        System.out.println("Currently in the BeanFactory" + count + "个Bean"); System.out.println(Arrays.asList(names)); }}Copy the code

Run to start the class, you can see, by getting into the container components, found in beans created before execution MyBeanFactoryPostProcessor postProcessBeanFactory method, thus it can be seen that in the instance of the bean is not created, That is, BeanFactoryPostProcessor is called before initialization, so you can extend the functionality here and modify the bean’s properties.

Third, source code analysis

We use the Debug method to view the method call chain step by step, and set a breakpoint on the postProcessBeanFactory method. Debug runs the start class:

As you can see, entered the refresh () method of invokeBeanFactoryPostProcessors method, that is to say, in invokeBeanFactoryPostProcessors method is executed in the rear of the beanFactory handler method.

public void refresh(a) throws BeansException, IllegalStateException {
    synchronized(this.startupShutdownMonitor) {
        ......
        // The beanFactory afterprocessor is executed in this method
        this.invokeBeanFactoryPostProcessors(beanFactory); . }}Copy the code

To the next method, to invokeBeanFactoryPostProcessors# invokeBeanFactoryPostProcessors method,

public static void invokeBeanFactoryPostProcessors(ConfigurableListableBeanFactory beanFactory, List<BeanFactoryPostProcessor> beanFactoryPostProcessors) {... sortPostProcessors(regularPostProcessors, beanFactory);// execute PostProcessor that implements PriorityOrdered interface
    invokeBeanFactoryPostProcessors((Collection)regularPostProcessors, (ConfigurableListableBeanFactory)beanFactory);
    List<BeanFactoryPostProcessor> orderedPostProcessors = new ArrayList(registryProcessors.size());
    Iterator var21 = registryProcessors.iterator();

    while(var21.hasNext()) {
        String postProcessorName = (String)var21.next();
        orderedPostProcessors.add(beanFactory.getBean(postProcessorName, BeanFactoryPostProcessor.class));
    }

    sortPostProcessors(orderedPostProcessors, beanFactory);
    // Execute the PostProcessor that implements the Ordered interface
    invokeBeanFactoryPostProcessors((Collection)orderedPostProcessors, (ConfigurableListableBeanFactory)beanFactory);
    List<BeanFactoryPostProcessor> nonOrderedPostProcessors = new ArrayList(currentRegistryProcessors.size());
    Iterator var24 = currentRegistryProcessors.iterator();

    while(var24.hasNext()) {
        ppName = (String)var24.next();
        // Get the BeanFactoryPostProcessor name for each PostProcessor from the bean factory
        nonOrderedPostProcessors.add(beanFactory.getBean(ppName, BeanFactoryPostProcessor.class));
    }

    // Execute the beanFactory PostProcessor (last execute the normal interface PostProcessor)
    invokeBeanFactoryPostProcessors((Collection)nonOrderedPostProcessors, (ConfigurableListableBeanFactory)beanFactory);
    beanFactory.clearMetadataCache();
}
Copy the code

As you can see, in this method, is to call the bottom invokeBeanFactoryPostProcessors method performs the beanFactory post processor, ask questions:

How do we find the PostProcessor and implement their methods?

[1] Get PostProcessor

Code above respectively carried out three kinds of interface BeanFactoryPostProcessors, before execution, on the PostProcessor for processing, as follows, separate three PostProcessor placed:

  • PriorityOrderedPostProcessors: place a prioritization of the interface
  • PostProcessorNames orderedPostProcessorNames: place a sort
  • Place ordinary PostProcessorNames nonOrderedPostProcessorNames:
public static void registerBeanPostProcessors(ConfigurableListableBeanFactory beanFactory, AbstractApplicationContext applicationContext) {...for(int var10 = 0; var10 < var9; ++var10) {
        ppName = var8[var10];
        / / will have priority interface in priorityOrderedPostProcessors
        if (beanFactory.isTypeMatch(ppName, PriorityOrdered.class)) {
            pp = (BeanPostProcessor)beanFactory.getBean(ppName, BeanPostProcessor.class);
            priorityOrderedPostProcessors.add(pp);
            if (pp instanceof MergedBeanDefinitionPostProcessor) {
                internalPostProcessors.add(pp);
            }
            There will be sorting interface in orderedPostProcessorNames / /
        } else if (beanFactory.isTypeMatch(ppName, Ordered.class)) {
            orderedPostProcessorNames.add(ppName);
        } else {
            / / put the common interface in nonOrderedPostProcessorNamesnonOrderedPostProcessorNames.add(ppName); }}... }Copy the code

Now we’ve got the PostProcessor, the PriorityOrdered interface, the Ordered interface, the normal interface, and then we’re going to iterate, and we’re going to implement the normal interface, Get the BeanFactoryPostProcessor name for each PostProcessor from the Bean factory

[2] Iterate through and execute PostProcessor

private static void invokeBeanFactoryPostProcessors(Collection<? extends BeanFactoryPostProcessor> postProcessors, ConfigurableListableBeanFactory beanFactory) {
    Iterator var2 = postProcessors.iterator();

    while(var2.hasNext()) {
        BeanFactoryPostProcessor postProcessor = (BeanFactoryPostProcessor)var2.next();
        StartupStep var10000 = beanFactory.getApplicationStartup().start("spring.context.bean-factory.post-process");
        postProcessor.getClass();
        StartupStep postProcessBeanFactory = var10000.tag("postProcessor", postProcessor::toString); postProcessor.postProcessBeanFactory(beanFactory); postProcessBeanFactory.end(); }}Copy the code

Iterate through each PostProcessor, calling back to the postProcessBeanFactory method for each.

Four,

  1. Refresh () : the IOC container creates objects
  2. BeanFactoryPostProcessors invokeBeanFactoryPostProcessors () : perform, i.e. the beanFactory post processor
    1. Direct all types are found in the BeanFactory BeanFactoryPostProcessors components, and perform their methods
    2. Through the source code as you can see, the initialization is in other components (finishBeanFactoryInitialization) before execution