Springboot extension point series_SmartInstantiationAwareBeanPostProcessor

Features

The following figure shows the UML class diagram of the SmartInstantiationAwareBeanPostProcessor extension point. It can be seen that SmartInstantiationAwareBeanPostProcessor inherits the InstantiationAwareBeanPostProcessor interface, and the InstantiationAwareBeanPostProcessor interface inherits BeanPostProcessor. For the functional characteristics, implementation examples, and working principles of the InstantiationAwareBeanPostProcessor and BeanPostProcessor interfaces, see Springboot extension point Instanti ationAwareBeanPostProcessor and The Springboot extension point BeanPostProcessor has been shared in detail in the two articles. Interested guys can go to favorites + follow. In this article, we focus on sharing the unique extension methods of the SmartInstantiationAwareBeanPostProcessor interface.

img

1. The SmartInstantiationAwareBeanPostProcesso interface has three extension points, namely predictBeanType(), determineCandidateConstructors(), and getEarlyBeanReference();

2. predictBeanType() is used to predict the final returned Class type before Bean instantiation. The triggering time is before InstantiationAwareBeanPostProcessor#postProcessBeforeInstantiation(). If it cannot be predicted, null or the correct Class is returned; if a wrong Class is predicted, then The program will report an error (for example: if the formal parameter beanClass is Student.class, and it is changed to Teacher.class when returning, there is no doubt that the error is reported; then the question is: What is the meaning of such a prediction? This point I I don’t quite understand. If anyone knows, please tell me.);

3. determineCandidateConstructors() determines which constructor to use to construct the Bean. If not specified, the default is null, which is the parameter-free construction method of the bean; (I feel that this extension point is of little significance. In fact, constructors are divided into two categories: parameter-free construction Method, there is a parameter construction method, it is nothing more than a parameter construction method with at least one parameter. I feel that there is not much difference in which constructor is used to construct the Bean. For example: eating with an ordinary bowl and eating with a golden bowl, for some people There may be a difference. For me, it’s good as long as I’m full. I don’t care what kind of bowl it is, haha. What do you think, guys?)

4. getEarlyBeanReference() obtains the bean reference exposed in advance, which is mainly used to solve the Spring circular dependency problem. If the circular dependency cannot be detected in Spring, this method will not be called; when there is a Spring circular dependency, it will be called in Executed after the InstantiationAwareBeanPostProcessor#postProcessBeforeInstantiation method triggers execution;

public interface SmartInstantiationAwareBeanPostProcessor extends InstantiationAwareBeanPostProcessor {<!-- -->
    //Predict the Bean type and return the first successfully predicted Class type. If it cannot be predicted, return null;
    default Class<?> predictBeanType(Class<?> beanClass, String beanName) throws BeansException {<!-- -->
      return null;
   }
    //Determine which constructor to use to construct the Bean. If not specified, the default is null, which is the parameterless construction method of the bean;
   default Constructor<?>[] determineCandidateConstructors(Class<?> beanClass, String beanName)
         throws BeansException {<!-- -->
 
      return null;
   }
    //Obtain bean references exposed in advance, mainly used to solve Spring circular dependency problems;
   default Object getEarlyBeanReference(Object bean, String beanName) throws BeansException {<!-- -->
      return bean;
   }
}

Implementation

Student.java

Define a Student class and then inject a Teacher class;

@Slf4j
@Component
public class Student {<!-- -->
    private String name="xiao ming";
    @Autowired
    private teacher teacher;
 
    public Student() {<!-- -->
        log.info("----student's parameterless constructor is executed");
    }
 
    public Student(String name) {<!-- -->
        this.name = name;
        log.info("----student's parameterized constructor is executed");
    }
 
    public Student(Teacher teacher) {<!-- -->
        this.teacher = teacher;
        log.info("----student's parameterized constructor (teacher) is executed");
    }
 
    public Student(String name, Teacher teacher) {<!-- -->
        this.name = name;
        this.teacher = teacher;
        log.info("----student's parameterized constructor (name, teacher) is executed");
    }
 
    public String getName() {<!-- -->
        return name;
    }
 
    public void setName(String name) {<!-- -->
        this.name = name;
    }
 
    public Teacher getTeacher() {<!-- -->
        return teacher;
    }
 
    public void setTeacher(Teacher teacher) {<!-- -->
        log.info("----The setTeacher method in student is called");
        this.teacher = teacher;
    }
}

Teacher.java

Define a Teacher class, and then inject a Student class into the Teacher class, so that the Student class and the Teacher class form a circular dependency, making it easier to verify the execution of MySmartInstantiationAwareBeanPostProcessor#getEarlyBeanReference later;

@Component
@Slf4j
public class Teacher {<!-- -->
    private String name="li lao shi";
    @Autowired
    private student student;
    public Teacher() {<!-- -->
        log.info("----Teacher's parameterless constructor is executed");
    }
 
    public String getName() {<!-- -->
        return name;
    }
 
    public void setName(String name) {<!-- -->
        this.name = name;
    }
 
    public Student getStudent() {<!-- -->
        return student;
    }
 
    public void setStudent(Student student) {<!-- -->
        log.info("----The setStudent method in teacher is called");
        this.student = student;
    }
}

MySmartInstantiationAwareBeanPostProcessor

Define the MySmartInstantiationAwareBeanPostProcessor class and implement the predictBeanType method, determineCandidateConstructors method, getEarlyBeanReference method, and postProcessBeforeInstantiation method of the SmartInstantiationAwareBeanPostProcessor interface;

@Component
@Slf4j
public class MySmartInstantiationAwareBeanPostProcessor implements SmartInstantiationAwareBeanPostProcessor {<!-- -->
    @Override
    public Class<?> predictBeanType(Class<?> beanClass, String beanName) throws BeansException {<!-- -->
        if (beanName.equals("student")) {<!-- -->
            log.info("----predictBeanType method is executed," + beanName);
            return Student.class;
        }
        return null;
    }
    //There are four constructors in the student class. There are actually two constructors you can choose from:
    //A parameterless constructor, the other is a formal parameter of Teacher type
    @Override
    public Constructor<?>[] determineCandidateConstructors(Class<?> beanClass, String beanName) throws BeansException {<!-- -->
        if (beanName.equals("student") ) {<!-- -->
            log.info("----determineCandidateConstructors method is executed," + beanName);
            Constructor<?> constructor = beanClass.getConstructors()[3];
            Constructor<?>[] constructors={<!-- -->constructor};
            return constructors;
        }
        return null;
    }
 
    @Override
    public Object getEarlyBeanReference(Object bean, String beanName) throws BeansException {<!-- -->
        if (beanName.equals("student") ) {<!-- -->
            log.info("----getEarlyBeanReference method is executed," + beanName);
        }
        return bean;
    }
 
    @Override
    public Object postProcessBeforeInstantiation(Class<?> beanClass, String beanName) throws BeansException {<!-- -->
        if (beanName.equals("student")) {<!-- -->
            log.info("----postProcessBeforeInstantiation method is executed, beanName:" + beanName);
            return null;
        }
        return null;
    }
}

Unit test verification

 @Component
@Slf4j
public class MySmartInstantiationAwareBeanPostProcessor implements SmartInstantiationAwareBeanPostProcessor {<!-- -->
    @Override
    public Class<?> predictBeanType(Class<?> beanClass, String beanName) throws BeansException {<!-- -->
        if (beanName.equals("student")) {<!-- -->
            log.info("----predictBeanType method is executed," + beanName);
            return Student.class;
        }
        return null;
    }
    //There are four constructors in the student class. There are actually two constructors you can choose from:
    //A parameterless constructor, the other is a formal parameter of Teacher type
    @Override
    public Constructor<?>[] determineCandidateConstructors(Class<?> beanClass, String beanName) throws BeansException {<!-- -->
        if (beanName.equals("student") ) {<!-- -->
            log.info("----determineCandidateConstructors method is executed," + beanName);
            Constructor<?> constructor = beanClass.getConstructors()[3];
            Constructor<?>[] constructors={<!-- -->constructor};
            return constructors;
        }
        return null;
    }
 
    @Override
    public Object getEarlyBeanReference(Object bean, String beanName) throws BeansException {<!-- -->
        if (beanName.equals("student") ) {<!-- -->
            log.info("----getEarlyBeanReference method is executed," + beanName);
        }
        return bean;
    }
 
    @Override
    public Object postProcessBeforeInstantiation(Class<?> beanClass, String beanName) throws BeansException {<!-- -->
        if (beanName.equals("student")) {<!-- -->
            log.info("----postProcessBeforeInstantiation method is executed, beanName:" + beanName);
            return null;
        }
        return null;
    }
}

Summary

The above content is the entire content of Springboot’s SmartInstantiationAwareBeanPostProcessor extension point. It mainly shares the functional features and implementation methods. The reason why I did not introduce its working principle is because I found that this extension point is actually useless. It is used internally by Spring, but it is also used internally by Spring. There are very few and it is difficult to use in actual business development, so it is meaningless to introduce its working principle in a long way.