Author: Sporadic. (wechat official ID: Fchen), welcome to share, reprint please reserve the source.

When it comes to Spring’s extension points, two processors come to mind: BeanPostProcessor and BeanFactoryPostProcessor, and they are named after the object’s back processor and the factory’s back processor.

Both of these post-processor-related analyses have been more or less covered in previous articles. But, somehow, these two rear processors do have a very important place in Spring. You might say that I don’t normally write extension points like this to implement methods, intervene in Bean factory initialization, influence Bean lifecycle, and so on. But inside Spring, the annotations we use are mostly done through these two extension points.

Don’t know whether you remember ConfigurationClassPostProcessor @ this annotation processing Configuration class. Arguably, of all the classes Spring implements for BeanFactoryPostProcessor, this is the most important. Because of this class, our custom @Configuration annotated class can be processed. The objects we define have a chance to be added to the IoC container.

Don’t know whether you still remember the @autowired annotation processing class AutowiredAnnotationBeanPostProcessor. In this class, dependency injection is done to the injected objects, and the dependency relationship between objects is established. Of course, there are other annotation processing, which is basically a subclass of BeanPostProcessor.

In today’s post I try to compare these two extension points.

1. The similarities

1.1 Design Idea

First, BeanFactoryPostProcessor and BeanPostProcessor both define methods in the form of interfaces for subclasses to implement to do what they want.

The BeanPostProcessor is an extension point of a class provided by the Spring framework called the bean’s post-processor. By implementing the BeanPostProcessor interface, you can intervene in the bean initialization process, reducing the BeanFactory burden.

public interface BeanPostProcessor {

	/** * executes */ before the bean is initialized
	@Nullable
	default Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
		return bean;
	}

	/** * executes */ after the bean is initialized
	@Nullable
	default Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
		returnbean; }}Copy the code

The BeanFactoryPostProcessor is used to intervene in the initialization of the BeanFactory. Affects container formation. ConfigurationClassPostProcessor, for example, in the subclass implementation, completed the parsing of @ the Configuration notes.

public interface BeanFactoryPostProcessor {

	void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) throws BeansException;

}
Copy the code

ConfigurationClassPostProcessor class by implementing the above method, the completed for dynamic proxy configuration class.

1.2 Storage in containers

Since BeanFactoryPostProcessor and BeanPostProcessor are both defined in the container as interfaces, in the IoC container, two collections are defined to house them.

private final List<BeanPostProcessor> beanPostProcessors = new CopyOnWriteArrayList<>();
Copy the code

Use beanPostProcessors to store subclasses of BeanPostProcessor. When you want to retrieve the collection from the container, you can do this:

public List<BeanPostProcessor> getBeanPostProcessors(a) {
		return this.beanPostProcessors;
	}
Copy the code

For Spring BeanFactoryPostProcessor subclass is also similar, the Spring will be stored in: beanFactoryPostProcessors.

private final List<BeanFactoryPostProcessor> beanFactoryPostProcessors = new ArrayList<>();
Copy the code

Through getBeanFactoryPostProcessors () method to get:

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

Here say so, should be not too strict, because getBeanFactoryPostProcessors is () to get the programmer to define it and not to the Spring management of Spring BeanFactoryPostProcessor subclass. Here are not here, can see: invokeBeanFactoryPostProcessors () method of processing there is a detailed explanation.

1.3 Subclass processing

For subclasses that implement these two classes, a batch exists in the container. Each subclass is handled through the for loop, which executes the corresponding method for each subclass.

As you can see, both subclasses are handled the same way, adding them to the corresponding variables when the container is initialized. Take it out when you need it later and cycle through it.

2. The difference between

2.1 Different object oriented

One of these two objects is doing things in front of the BeanFactory. One is the guy who does things with beans? Doesn’t it feel a little abstract? (Try to feel him instead of understanding him. I admit that I was misled by Credo. Forgive me for not being intelligent enough to understand it. There’s a lot to catch up on… Study! That’s okay. I think I can explain that.

To analyze BeanFactoryPostProcessor is to confront BeanFactory. Again, it’s the refresh() method of the container. Before executing the Refresh () method, there was only one BeanDefinitionMap registered for our self-defined objects, and that was our configuration class. Upon completion of invokeBeanFactoryPostProcessors (after the beanFactory), container BeanDefinitionMap contains the we need to define your own in the development of Spring management objects. The writing process are ConfigurationClassPostProcessor class. This makes our container much richer. When you have BD (BeanDefinition) in your container, it opens up the possibility for future operations on getBea(). It should also be noted that classes with @Configuration will be marked in Full mode in their BD, and dynamically propped objects will be generated using CGLIB.

To analyze BeanPostProcessor is bean-facing. I’ll start with an annotation @autowired that I used in development. @AutoWired is designed to do property injection of objects. Handling of dependencies between objects is in the org. Springframework. Beans. Factory. Support. AbstractAutowireCapableBeanFactory# populateBean (String BeanName, RootBeanDefinition MBD, @nullable BeanWrapper bw). In this method there is a piece of code shown in the image above that determines the type of postprocessor and executes the method.

By following a piece of code in AutowiredAnnotationBeanPostProcessor began between object dependency injection, including findAutowiringMetadata () all the injected in the access to the current object attributes, and then do the corresponding processing. I’m not going to go over dependency injection here, but if you’re interested, check out the Spring injection object handling process

public PropertyValues postProcessProperties(PropertyValues pvs, Object bean, String beanName) {
    InjectionMetadata metadata = findAutowiringMetadata(beanName, bean.getClass(), pvs);
    try {
        / / injection
        metadata.inject(bean, beanName, pvs);
    }
    catch (BeanCreationException ex) {
        throw ex;
    }
    catch (Throwable ex) {
        throw new BeanCreationException(beanName, "Injection of autowired dependencies failed", ex);
    }
    return pvs;
}
Copy the code

From the above analysis, it can be understood that BeanFactoryPostProcessor works in front of BeanFactory. Is BeanPostProcessor dealing with beans?

2.2 Use the code to understand

If you still don’t understand the difference between object orientation and BeanFactoryPostProcessor, let’s take a look at the following example. First, we define an implementation class for BeanFactoryPostProcessor. In the subclass implementation, we get the object by getBean(). The object’s test() method is then called.

@Component public class MyFactoryPostProcessor implements BeanFactoryPostProcessor { @Override public void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) throws BeansException { int count = beanFactory.getBeanDefinitionCount(); String[] names = beanFactory.getBeanDefinitionNames(); System.out.println(" current BeanFactory has "+count+" Bean"); System.out.println(Arrays.asList(names)); MyService bean = beanFactory.getBean(MyService.class); System.out.println(bean); bean.test(); }}Copy the code

Define two classes, MyService and MyTest. We’ll start by injecting MyTest into MyService. The test method of MyTest is then called.

@Service public class MyService { @Autowired MyTest myTest; public void test(){ System.out.println("hello test"); myTest.test(); }}Copy the code

With the code above, guess what the result will be? The debugging results are as follows:

I’ve broken this down into three parts. The first part says that BeanDefinitionMap already contains all the objects in our container, because the corresponding @Configuration annotation class has been processed.

In the second part, getBean() triggers a series of operations such as Bean instantiation.

The third part throws a null pointer to indicate that the dependent object has not been injected. At this point, a subclass of BeanFactoryPostProcessor has already intervened in the initialization of the container, affecting the objects in the container. But the object’s post-processor has not yet been added to the container. @AutoWired does the property injection via the object’s back processor, causing the corresponding property not to be injected into the object.

To sum up, I think: BeanFactoryPostProcessor does things in the face of BeanFactory; BeanPostProcessor is dealing with beans. I think I’ve cleared that up.

3. Summary

This article compares and analyzes the similarities and differences between Spring’s extension point BeanFactoryPostProcessor and BeanPostProcessor. The whole thing is to illustrate one thing: BeanFactoryPostProcessor is to do things in front of BeanFactory; BeanPostProcessor is dealing with beans. Of course, the BeanFactoryPostProcessor can also set object properties. I don’t want to make a more detailed distinction here.