Spring has been one of the best Java development frameworks since its inception, and Spring is often mentioned in job interviews, so mastering it is an inevitable hurdle. The most important thing in Spring is the IOC container, which manages a large number of beans. Are these beans simply instantiated and managed by Spring? Certainly not. Spring provides a number of extension points for developers to customize their beans in the process of instantiating beans, so how to extend these beans is the focus of this article.

Rear processor

The backend processor, BeanPostProcessor, is the interface Spring provides for extending beans. In Spring, either internally provided or developer-provided back-end processors are an implementation class for this interface.

public interface BeanPostProcessor {

	@Nullable
	default Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
		return bean;
	}

	@Nullable
	default Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
		returnbean; }}Copy the code

The interface defines two methods, both of which by default do nothing and return the Bean passed in directly.

Including postProcessBeforeInitialization () method is invoked before initialization Bean, in this case, the initialization is not instantiated, but to the Bean defined in the initialization callback methods, such as: The afterPropertiesSet() method in the InitializingBean interface, the @postConstruct modified method. PostProcessBeforeInitialization () method is executed before the initialization callback methods.

While postProcessAfterInitialization () method is called after the initialization Bean. But this method may be executed twice in a FactoryBean, once by the FactoryBean itself and once by the Bean created by the FactoryBean. The backend processor can decide if it wants to execute this method for both beans.

Register the post-processor

The post-processor also exists in Spring as a Bean, so the post-processor is no different from the regular beans we put into Spring, and is managed in the IOC container.

So when does Spring register these post-processors? How do we register a custom post-processor ourselves?

Let’s start with the first question. When did Spring register the post-processor?

Spring has several BeanPostProcessors registered in multiple places. The first place is in the ApplicationContext constructor:

public AnnotationConfigApplicationContext(Class
       ... componentClasses) {
    // In the constructor, six beandefinitions are registered:
    // 1.ConfigurationClassPostProcessor
    // 2.AutowiredAnnotationBeanPostProcessor
    / / 3. com monAnnotationBeanPostProcessor support JSP - 250 will be registered
    / / 4. PersistenceAnnotationBeanPostProcessor supports Jpa will register
    // 5.EventListenerProcessor
    // 6.EventListenerFactory
    this(a); register(componentClasses); refresh(); }Copy the code

The comment says that six BeanDefinitions are registered, but only 2-4 are the actual post-processors that implement the BeanPostProcessor interface. Note that this is just registering the BeanDefinition, not actually instantiating the post-handlers, which will happen later.

Real registration method is: the three rear the processor registerAnnotationConfigProcessors ().

public static Set<BeanDefinitionHolder> registerAnnotationConfigProcessors(
      BeanDefinitionRegistry registry, @Nullable Object source) {

   DefaultListableBeanFactory beanFactory = unwrapDefaultListableBeanFactory(registry);
  
   Set<BeanDefinitionHolder> beanDefs = new LinkedHashSet<>(8);

    / / register AutowiredAnnotationBeanPostProcessor
   if(! registry.containsBeanDefinition(AUTOWIRED_ANNOTATION_PROCESSOR_BEAN_NAME)) { RootBeanDefinition def =new RootBeanDefinition(AutowiredAnnotationBeanPostProcessor.class);
      def.setSource(source);
      beanDefs.add(registerPostProcessor(registry, def, AUTOWIRED_ANNOTATION_PROCESSOR_BEAN_NAME));
   }

   / / only conform to the JSR - 250 specification CommonAnnotationBeanPostProcessor registration
   if(jsr250Present && ! registry.containsBeanDefinition(COMMON_ANNOTATION_PROCESSOR_BEAN_NAME)) { RootBeanDefinition def =new RootBeanDefinition(CommonAnnotationBeanPostProcessor.class);
      def.setSource(source);
      beanDefs.add(registerPostProcessor(registry, def, COMMON_ANNOTATION_PROCESSOR_BEAN_NAME));
   }

   / / only detected under the condition of the JPA PersistenceAnnotationBeanPostProcessor registration
   if(jpaPresent && ! registry.containsBeanDefinition(PERSISTENCE_ANNOTATION_PROCESSOR_BEAN_NAME)) { RootBeanDefinition def =new RootBeanDefinition();
      try {
         def.setBeanClass(ClassUtils.forName(PERSISTENCE_ANNOTATION_PROCESSOR_CLASS_NAME,
               AnnotationConfigUtils.class.getClassLoader()));
      }
      catch (ClassNotFoundException ex) {
         throw new IllegalStateException(
               "Cannot load optional framework class: " + PERSISTENCE_ANNOTATION_PROCESSOR_CLASS_NAME, ex);
      }
      def.setSource(source);
      beanDefs.add(registerPostProcessor(registry, def, PERSISTENCE_ANNOTATION_PROCESSOR_BEAN_NAME));
   }

   / / register EventListenerMethodProcessor
   if(! registry.containsBeanDefinition(EVENT_LISTENER_PROCESSOR_BEAN_NAME)) { RootBeanDefinition def =new RootBeanDefinition(EventListenerMethodProcessor.class);
      def.setSource(source);
      beanDefs.add(registerPostProcessor(registry, def, EVENT_LISTENER_PROCESSOR_BEAN_NAME));
   }

   return beanDefs;
}
Copy the code

The second and third places are in the famous Refresh() method, which is already annotated. I won’t post the actual registered statements here.

public void refresh(a) throws BeansException, IllegalStateException {
   synchronized (this.startupShutdownMonitor) {
      // Tell the subclass to refresh the internal bean factory.
      ConfigurableListableBeanFactory beanFactory = obtainFreshBeanFactory();

      // Register three BeanPostProcessors:
      // ApplicationListenerDetector
      // ApplicationContextAwareProcessor
      Will only be registered / / LoadTimeWeaverAwareProcessor meet the specified conditions
      prepareBeanFactory(beanFactory);

      try {
         // Register 1 BeanPostProcessor:
         // ImportAwareBeanPostProcessor
         invokeBeanFactoryPostProcessors(beanFactory);

         // Register 1 BeanPostProcessor:
         // ApplicationListenerDetector
         // Instantiate BeanPostProcessor:
         // AutowiredAnnotationBeanPostProcessor
         // CommonAnnotationBeanPostProcessor
         // ApplicationListenerDetector
         / /...
         // The registered backend handlers must have been converted to BeanDefinition in the previous steps
         // Otherwise, the Bean will not be successfully registered, and the registered post-processor will be used when instantiating the Bean
         registerBeanPostProcessors(beanFactory);

         // instantiate a non-lazy-loaded singleton
         finishBeanFactoryInitialization(beanFactory);
      }

      catch (BeansException ex) {
    
      }
   }
}
Copy the code

We can see from the above code that the BeanDefinition of BeanPostProcessor is registered. This is just a class that holds Bean properties, but it is not the Bean we really need. So, we also need to instantiate our real post-processor objects through these BeanDefinitions. And this operation is in registerBeanPostProcessors () the process of this method. This method instantiates the post-processor by calling the getBean() method, and then puts it into the container.

summary

There are a total of seven post-processors registered within Spring itself, and this is Spring

Rear processor role Registration requirements
AutowiredAnnotationBeanPostProcessor It is used to handle @autowired, @Value, @Inject, @lookup
CommonAnnotationBeanPostProcessor Used to handle annotations under the Javax. annotation package, such as @resource. It can also handle @WebServiceref and @EJB JSR – 250 support
PersistenceAnnotationBeanPostProcessor Used for JPA JPA supports
ApplicationListenerDetector Detects whether the Bean implements the ApplicationListener interface and registers the Bean as a listener if it does
ApplicationContextAwareProcessor Implement the methods in the Aware interface of the Bean implementation
LoadTimeWeaverAwareProcessor Detects whether the Bean implements the LoadTimeWeaverAware interface and executes methods under that interface if it does The container needs to contain a Bean named loadTimeWeaver.
ImportAwareBeanPostProcessor The post-processor has two functions: one is to detect whether the Bean implements the EnhancedConfiguration interface, and if so, to execute the methods under the interface; The other is to check whether the ImportAware interface is implemented, and if so, to execute the methods under the interface.

The seven postprocessors above are ultimately registered with the container, but they themselves implement not only The BeanPostProcessor, but many other BeanPostProcessor subinterfaces as well.

Such as: AutowiredAnnotationBeanPostProcessor, its UML diagram below

Through UML diagrams can know AutowiredAnnotationBeanProcessor rear implements multiple processor interface, the interface is very important.

Custom rear processor

It’s very easy to customize the post-processor. As we mentioned earlier, the post-processor and our regular beans are managed by the IOC container, so we just need Spring to be able to scan our post-processor.

@Component
public class MyBeanPostProcessor implements BeanPostProcessor {
	@Override
	public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
		System.out.println("Execute custom post-processor");
		returnbean; }}Copy the code

After Spring scans this class, it registers it with our container as a post-processor.

How to extend beans

To extend a Bean, we need to know the Bean’s life cycle, and the life cycle is tied to the post-processors, so we need to know what post-processors Spring executes when, and what they do. Once we know this, we know how to extend beans.

Spring uses postprocessors in a total of nine places, and these postprocessors indicate that they are executed during Bean instantiation. We’re going to find all nine of them.

The first place

AbstractAutowireCapableBeanFactory::createBean(String beanName, RootBeanDefinition mbd, @Nullable Object[] args)

// Snippet 1
try {
    // The first extension point in which a proxy bean can be returned
    Object bean = resolveBeforeInstantiation(beanName, mbdToUse);
    if(bean ! =null) {
        returnbean; }}catch (Throwable ex) {
    throw new BeanCreationException(mbdToUse.getResourceDescription(), beanName,
                                    "BeanPostProcessor before instantiation of bean failed", ex);
}
Copy the code
// Snippet 2
protected Object resolveBeforeInstantiation(String beanName, RootBeanDefinition mbd) {
    Object bean = null;
    if(! Boolean.FALSE.equals(mbd.beforeInstantiationResolved)) {// Make sure bean class is actually resolved at this point.
        if(! mbd.isSynthetic() && hasInstantiationAwareBeanPostProcessors()) { Class<? > targetType = determineTargetType(beanName, mbd);if(targetType ! =null) {
                bean = applyBeanPostProcessorsBeforeInstantiation(targetType, beanName);
                if(bean ! =null) { bean = applyBeanPostProcessorsAfterInitialization(bean, beanName); } } } mbd.beforeInstantiationResolved = (bean ! =null);
    }
    return bean;
}
Copy the code

Mainly resolveBeforeInstantiation () method will execute InstantiationAwareBeanPostProcessor inside the post processor postProcessBeforeInstantiation () Method, which returns null by default.

The main purpose of this method is to return an instance of a Bean. We through the code fragment above 2, if return a Bean here, you will direct execution InstantiationAwareBeanPostProcessor this post processor postProcessAfterInstantiation () method, The Bean passed in is returned by default. When performing a complete resolveBeforeInstantiation () method, we look at the code fragment 1, it determine if there is a return value, return the Bean directly, that means Bean creation process will stop.

As a result, the instantiation of the Bean lifecycle is over here (not including the use and destruction of life cycle), a total execution InstantiationAwareBeanPostProcessor inside of two methods.

The main purpose of this post-processor is to instantiate the Bean itself, without Spring doing the instantiation for us. You can also use this post-processor to return the Bean’s proxy.

There are three inner classes that implement the post-processor:

  • ImportAwareBeanPostProcessor, unoverridden method, returns the default value
  • CommonAnnotationBeanPostProcessor, unoverridden method, returns the default value
  • AutowiredAnnotationBeanPostProcessor, unoverridden method, returns the default value

So, by default, no class is instantiated by a subsequent handler to return a Bean.

In the second place

AbstractAutowireCapableBeanFactory::determineConstructorsFromBeanPostProcessors(Class<? > beanClass, String beanName)

@Nullable
protectedConstructor<? >[] determineConstructorsFromBeanPostProcessors(@NullableClass<? > beanClass, String beanName)throws BeansException {

    if(beanClass ! =null && hasInstantiationAwareBeanPostProcessors()) {
        for(SmartInstantiationAwareBeanPostProcessor bp : getBeanPostProcessorCache().smartInstantiationAware) { Constructor<? >[] ctors = bp.determineCandidateConstructors(beanClass, beanName);if(ctors ! =null) {
                returnctors; }}}return null;
}
Copy the code

Here to perform a second post processor SmartInstantiationAwareBeanPostProcessor, the rear determineCandidateConstructors processors inside a method (), This method is used to determine the constructor used by the instantiated bean before it is instantiated. By default, null is returned, indicating that the no-argument constructor is used.

There is only one class that implements this interface:

  • AutowiredAnnotationBeanPostProcessor, overrides the method to select the appropriate constructor.

In the third place

AbstractAutowireCapableBeanFactory::applyMergedBeanDefinitionPostProcessors(RootBeanDefinition mbd, Class<? > beanType, String beanName)

protected void applyMergedBeanDefinitionPostProcessors(RootBeanDefinition mbd, Class
        beanType, String beanName) {
    for(MergedBeanDefinitionPostProcessor processor : getBeanPostProcessorCache().mergedDefinition) { processor.postProcessMergedBeanDefinition(mbd, beanType, beanName); }}Copy the code

Here is the third post processor MergedBeanDefinitionPostProcessor of execution, the post processor postProcessMergedBeanDefinition () method is very important, it is instantiated Bean after implementation, It deals with fields and methods in beans that are annotated, such as @autowired, @Value, and so on

It retrieves the fields and methods decorated with the above annotations, wraps and caches the objects to be injected, and then pulls them out of cache for dependency injection.

Three classes implement this interface:

  • CommonAnnotationBeanPostProcessorGet the objects decorated with @WebServiceref, @EJB, and @Resource and cache them
  • AutowiredAnnotationBeanPostProcessorGet the objects decorated by @AutoWired, @Value, @Inject and cache them
  • ApplicationListenerDetectorIf the bean type isApplicationListenerPut this beanName into the Map of singletonNames

The first around

AbstractAutowireCapableBeanFactory::getEarlyBeanReference(String beanName, RootBeanDefinition mbd, Object bean)

protected Object getEarlyBeanReference(String beanName, RootBeanDefinition mbd, Object bean) {
    Object exposedObject = bean;
    if(! mbd.isSynthetic() && hasInstantiationAwareBeanPostProcessors()) {for(SmartInstantiationAwareBeanPostProcessor bp : getBeanPostProcessorCache().smartInstantiationAware) { exposedObject = bp.getEarlyBeanReference(exposedObject, beanName); }}return exposedObject;
}
Copy the code

Post processor is SmartInstantiationAwareBeanPostProcessor is executed, the post processor getEarlyBeanReference is mainly used to solve rely on circulation, the purpose is to delay as long as the proxy object is created, This method wraps the Bean into an ObjectFactory object and stores it in the second-level cache. When a dependency loop occurs, the ObjectFactory object is taken out of the second-level cache. This object is used to create a Bean, which can be a primitive object or a proxy object. See my other article on how to do this. Does Spring solve loop dependencies and need level 3 caching? .

The class that implements this interface rewrites the getEarlyBeanReference method:

  • AbstractAdvisorAutoProxyCreatorThis is an abstract class that all AOP is associated with.

At this point, Spring has completed the Bean’s instantiation, and now there are two steps left: the population of properties, or dependency injection; The other is the initialization Bean, which executes the initialization functions and interface methods defined in the Bean.

The fifth place

AbstractAutowireCapableBeanFactory::populateBean(String beanName, RootBeanDefinition mbd, @Nullable BeanWrapper bw)

.if(! mbd.isSynthetic() && hasInstantiationAwareBeanPostProcessors()) {for (InstantiationAwareBeanPostProcessor bp : getBeanPostProcessorCache().instantiationAware) {
        if(! bp.postProcessAfterInstantiation(bw.getWrappedInstance(), beanName)) {return; }}}...Copy the code

Enforce a InstantiationAwareBeanPostProcessor here, the post processor also has appeared in the first place, is mainly performed in the first place postProcessBeforeInstantiation () method, Is executed before the Bean is instantiated. Here mainly perform postProcessAfterInstantiation () method, which is the Bean instantiation, fill before execution. Its return value indicates whether field injection is to be skipped.

Its main function is to allow developers to customize field injection, meaning that field injection is completely done manually by the developer, rather than automatically by Spring. If we inject fields manually, the subsequent Spring automatic injection will not be performed.

This method returns true by default, indicating that the properties should be automatically injected into the Bean; If false is returned, automatic property injection is skipped.

Implements this interface and rewrite postProcessAfterInstantiation () classes:

  • CommonAnnotationBeanPostProcessorBut it also returns true when overwritten. I don’t know why.

The sixth place

AbstractAutowireCapableBeanFactory::populateBean(String beanName, RootBeanDefinition mbd, @Nullable BeanWrapper bw)

.if (hasInstAwareBpps) {
    if (pvs == null) {
        pvs = mbd.getPropertyValues();
    }
    for (InstantiationAwareBeanPostProcessor bp : getBeanPostProcessorCache().instantiationAware) {
        PropertyValues pvsToUse = bp.postProcessProperties(pvs, bw.getWrappedInstance(), beanName);
        if (pvsToUse == null) {
            if (filteredPds == null) {
                filteredPds = filterPropertyDescriptorsForDependencyCheck(bw, mbd.allowCaching);
            }
            pvsToUse = bp.postProcessPropertyValues(pvs, filteredPds, bw.getWrappedInstance(), beanName);
            if (pvsToUse == null) {
                return; } } pvs = pvsToUse; }}...Copy the code

Sixth place is still in populateBean approach, still is rear InstantiationAwareBeanPostProcessor processors, but the execution method is postProcessProperties, The purpose of this method is to inject bean-dependent properties.

Bean depend on what attribute is in the third place in the rear MergedBeanDefinitionPostProcessor processors get and cached, postProcessProperties () method need only from the cache access to its dependence on which attributes, Then take the objects with these properties in the container and inject them into the Bean.

The post processor and a method is also used for dependency injection postProcessPropertyValues (), but this method has been abandoned.

Seventh and eighth

AbstractAutowireCapableBeanFactory::initializeBean(final String beanName, final Object bean, @Nullable RootBeanDefinition mbd)

protected Object initializeBean(final String beanName, final Object bean, @Nullable RootBeanDefinition mbd) {
    if(System.getSecurityManager() ! =null) {
        AccessController.doPrivileged((PrivilegedAction<Object>) () -> {
            invokeAwareMethods(beanName, bean);
            return null;
        }, getAccessControlContext());
    }
    else {
        // Implement various Aware interface methods: BeanNameAware etc
        invokeAwareMethods(beanName, bean);
    }

    Object wrappedBean = bean;
    if (mbd == null| |! mbd.isSynthetic()) {// Place the 7th post-processor at @postconstruct
        wrappedBean = applyBeanPostProcessorsBeforeInitialization(wrappedBean, beanName);
    }

    try {
        // Perform an initialization method, such as afterPropertiesSet in InitializingBean interface, init-method
        invokeInitMethods(beanName, wrappedBean, mbd);
    }
    catch (Throwable ex) {
        throw newBeanCreationException( (mbd ! =null ? mbd.getResourceDescription() : null),
            beanName, "Invocation of init method failed", ex);
    }
    if (mbd == null| |! mbd.isSynthetic()) {// Place 8 rear processor
        wrappedBean = applyBeanPostProcessorsAfterInitialization(wrappedBean, beanName);
    }

    return wrappedBean;
}
Copy the code

The first seven post processor is a BeanPostProcessor interface postProcessBeforeInitialization () method, the method is to call before initialization beans, we can in this method to strengthen our object, Such as returning a proxy object.

The BeanPostProcessor interface, the parent of all postprocessors, overrides the class for this method:

  • ApplicationContextAwareProcessorIf the bean implements the following interface, then the callback method in the interface is executed:
    • EnvironmentAware
    • EmbeddedValueResolverAware
    • ResourceLoaderAware
    • ApplicationEventPublisherAware
    • MessageSourceAware
    • ApplicationContextAware
  • ImportAwareBeanPostProcessorIf the bean is implementedImportAware, the related information is set
  • BeanPostProcessorCheckerDirectly returns the bean
  • CommonAnnotationBeanPostProcessorTo implement the @postconstruct annotation

Eighth place in the post processor is a BeanPostProcessor interface postProcessAfterInitialization () method, this method is called after the initialization Bean. It is also in this method that Spring creates proxies for beans by default (if there are no dependency loops, the Bean will be pre-created with the ObjectFactory created in the fourth place).

The BeanPostProcessor interface, the parent of all postprocessors, overrides the class for this method:

  • BeanPostProcessorChecker, prints the log, and returns the bean
  • ApplicationListenerDetectorIf the bean is implementedApplicationListener, add the bean to the application listener

The ninth place

Post processor is DestructionAwareBeanPostProcessor, the post processor is mainly perform @ PreDestroy annotation modification method.

Classes that implement this interface are:

  • CommonAnnotationBeanPostProcessorThe parent classInitDestroyAnnotationBeanPostProcessorPerforms the @predestroy annotated method.

conclusion

Here is the life cycle of beans in Spring, and once we are familiar with the life cycle, we can extend the life cycle for our business.

Example: Spring implements AOP by adding a post-processor. Spring will be registered in the first place a rear AnnotationAwareAspectJAutoProxyCreator processor, the post processor will to proxy objects need to be in the eighth place finish agent, and return to the proxy objects.

! [Lite Cycle of Spring Bean](cdn.dengqiuying.cn/Lite Cycle of Spring Bean.png)