One of BeanPostProcessors in spring: InstantiationAwareBeanPostProcessor (01)

Keywords: Spring

beanPostProcessor is an absolute pioneering product in spring, giving programmers a lot of autonomy. beanPostProcessor is often referred to as the bean postprocessor.

1. Overview

Let's start with InstantiationAwareBeanPostProcessor, which is a subinterface of BeanPostProcessor and inherits from BeanPostProcessor. Let's look at the methods in BeanPostProcessor.

Looking at the methods in InstantiationAwareBeanPostProcessor,

You can see that InstantiationAwareBeanPostProcessor extends the BeanPostProcessor interface and adds four new methods. Look at the postProcessAfterInstantiation method today.

default boolean postProcessAfterInstantiation(Object bean, String beanName) throws BeansException {
        return true;
    }

The change method has a default return value of true.

2. Details

The postProcessAfterInstantiation method in InstantiationAwareBeanPostProcessor does what, what, and where.When you look at the spring source, you see this code for property injection, which is done in the populateBean method, where a call to the postProcessAfterInstatitation method appears, and only the code associated with the populateBean method is pasted here.

boolean continueWithPropertyPopulation = true;
 //call beanFactory Registered beanPostProcessors That is bean Post-processor to determine if InstantiationAwareBeanPostProcessor Type of, if executed postProcessAfterInstantiation
        if (!mbd.isSynthetic() && hasInstantiationAwareBeanPostProcessors()) {
            for (BeanPostProcessor bp : getBeanPostProcessors()) {
                if (bp instanceof InstantiationAwareBeanPostProcessor) {
                    InstantiationAwareBeanPostProcessor ibp = (InstantiationAwareBeanPostProcessor) bp;
//If the return value is false then the assignment below will be true, then the property injection will be interrupted
if (!ibp.postProcessAfterInstantiation(bw.getWrappedInstance(), beanName)) { continueWithPropertyPopulation = false; break; } } } } //1 if (!continueWithPropertyPopulation) { return; }

The logic above is to loop through the registered beanPostProcessor, find the type of InstantiationAwareBeanPostProcessor, and execute its postProcessAfterInstantiation method. By looking at the registered beanPostProcessor, you can see that its return values are all true. From the analysis above, only the postProcessAfterInstantiation method returns false, and the populateBean method willReturn, property injection is interrupted, that is, no value is injected.

How can I ensure that the postProcessAfterInstantiation method returns false Name, where only I register an InstantiationAwareBeanPostProcessor with spring, and here is one of my postprocessors.

package cn.com.my.test;

import org.springframework.beans.BeansException;
import org.springframework.beans.factory.config.InstantiationAwareBeanPostProcessor;
import org.springframework.stereotype.Component;
@Component
public class MyInstantiationAwareBeanPostProcessor implements InstantiationAwareBeanPostProcessor {

    @Override
    public boolean postProcessAfterInstantiation(Object bean, String beanName) throws BeansException {
        // TODO Auto-generated method stub
        System.out.println("beanName: "+beanName);
        if("userService".equals(beanName)) {
            return false;
        }
        return InstantiationAwareBeanPostProcessor.super.postProcessAfterInstantiation(bean, beanName);
    }
}

The custom beanPostProcessor only implements the postProcessAfterInstantiation method. From the code logic above, you can see that only if the beanName is userService, the change method will return false, otherwise the interface method invoked will return the default value true.

Look at my test class below.

package cn.com.my.test;

import org.springframework.context.annotation.AnnotationConfigApplicationContext;

public class Test {

    public static void main(String[] args) {
        // TODO Auto-generated method stub

        AnnotationConfigApplicationContext ac=new AnnotationConfigApplicationContext(Config.class);
        
        UserService us=ac.getBean(UserService.class);
        System.out.println("us.roleService:"+us.getRoleService());
    }

}

Below is my UserService class,

package cn.com.my.test;

import org.springframework.beans.BeansException;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.config.InstantiationAwareBeanPostProcessor;
import org.springframework.stereotype.Component;

@Component
public class UserService {

    @Autowired
    private RoleService roleService;
    
    

    public RoleService getRoleService() {
        return roleService;
    }

    public void setRoleService(RoleService roleService) {
        this.roleService = roleService;
    }
}

From the UserService class, you can see that there is an annotated roleService property that normally automatically injects changed properties, but after my custom beanPostProcessor, see the following results

Magic thing happened, null returned by the property of us.roleService.

That's why, let's look at this code in populateBean.

boolean continueWithPropertyPopulation = true;
        //call beanPostProcessors That is bean Postprocessor,
        if (!mbd.isSynthetic() && hasInstantiationAwareBeanPostProcessors()) {
            for (BeanPostProcessor bp : getBeanPostProcessors()) {
                if (bp instanceof InstantiationAwareBeanPostProcessor) {
                    InstantiationAwareBeanPostProcessor ibp = (InstantiationAwareBeanPostProcessor) bp;
                    if (!ibp.postProcessAfterInstantiation(bw.getWrappedInstance(), beanName)) {
                        continueWithPropertyPopulation = false;
                        break;
                    }
                }
            }
        }

        if (!continueWithPropertyPopulation) {
            return;
        }

Since we have registered a beanPostProcessor with the beanFactory, my postProcessAfterInstantiation post-processor must be executed when looping here, and I have made a judgement in the post-processor that the postProcessAfterInstantiation method returns false when injecting a property into the beanName for the userService, so the above continueWithPropertyPopulation is false, causing it to enter the following if, the method returns directly, and the property injection is aborted, so the value of roleService in the UserService class is null.

3. Application occasions

When you need to implement the postProcessAfterInstantiation method of InstantiationAwareBeanPostProcessor, if you don't want to use spring's automatic injection (provided you've used the @Autowired annotation), you can register a beanPostProcessor for special beans to inject in your own way.

 

The original is not easy, there are inappropriate, welcome to correct, thank you!

Posted by Quest on Sun, 05 Apr 2020 21:54:09 -0700