In the previous article, we looked in detail at step 4 in doCreateBean() : the loop dependency handling of the singleton pattern, and then we looked at step 5 of doCreateBean(), “Property population,” which is the populateBean() method.
Let’s review the main flow of CreateBean:
- If it is singleton mode, get the BeanWrapper instance object from the factoryBeanInstanceCache cache and remove the cache
- call
createBeanInstance()
Instantiate the bean - Post processing
- Singleton mode loop dependency processing, put level 3 cache
- fill
- Initialize the bean instance object
- Depend on the check
- Register the bean’s destruction method
In this chapter we will focus on Step 5: There are three ways to inject properties in Spring:
- The XML configuration
- Annotation way
- Manual get\set method
XML, such as the default-Autowire attribute in the
node; Annotation methods include @value (), @resource, @Autowire, and @Qualifier. In this article, we will focus on attribute injection in annotation methods
PopulateBean (beanName, MBD, instanceWrapper)
//AbstractAutowireCapableBeanFactory.java
protected void populateBean(String beanName, RootBeanDefinition mbd, @Nullable BeanWrapper bw) {
// Verify the instance
if (bw == null) {
if (mbd.hasPropertyValues()) {
throw new BeanCreationException(
mbd.getResourceDescription(), beanName, "Cannot apply property values to null instance");
}
else {
// Skip property population phase for null instance.
return; }}// Give any InstantiationAwareBeanPostProcessors the opportunity to modify the
// state of the bean before properties are set. This can be used, for example,
// to support styles of field injection.
/ * * before set properties to InstantiationAwareBeanPostProcessors finally a chance to change the bean. * This post reference allows users to customize property injection. * a InstantiationAwareBeanPostProcessor types such as user achieve the post processor, and through the * postProcessAfterInstantiation method to the bean's member variables into the custom information. Of course, if there is no special requirement, just use the information in the configuration to inject. In addition, the Spring is not recommended implementation * InstantiationAwareBeanPostProcessor interface directly, if you want to implement this type of post processor, More advice * through inheritance InstantiationAwareBeanPostProcessorAdapter abstract class implements a custom post processor. * /
boolean continueWithPropertyPopulation = true;
/ / bean is not "synthetic" is not defined by the application itself hold InstantiationAwareBeanPostProcessor &&
<1> if(! mbd.isSynthetic() && hasInstantiationAwareBeanPostProcessors()) {// Run through all BeanPostProcessors
for (BeanPostProcessor bp : getBeanPostProcessors()) {
if (bp instanceof InstantiationAwareBeanPostProcessor) {
InstantiationAwareBeanPostProcessor ibp = (InstantiationAwareBeanPostProcessor) bp;
// Returns whether to continue populating the bean
/ / postProcessAfterInstantiation: if should set properties on the bean returns true, otherwise it returns false
// Normally, it should return true.
/ / returns false, will prevent the Bean instance on this call any subsequent InstantiationAwareBeanPostProcessor instance.
if(! ibp.postProcessAfterInstantiation(bw.getWrappedInstance(), beanName)) { continueWithPropertyPopulation =false;
break; }}}}// If the post-processor issues a stop population command, subsequent operations are terminated
if(! continueWithPropertyPopulation) {return;
}
// Get the Bean property value
PropertyValues pvs = (mbd.hasPropertyValues() ? mbd.getPropertyValues() : null);
// Handle dependency injection
// XML mode is the default-Autowire attribute in the
node in XML
<2> if (mbd.getResolvedAutowireMode() == RootBeanDefinition.AUTOWIRE_BY_NAME ||
mbd.getResolvedAutowireMode() == RootBeanDefinition.AUTOWIRE_BY_TYPE) {
// Encapsulate PropertyValues into a MutablePropertyValues object
// MutablePropertyValues allows simple manipulation of properties and provides constructors to support deep copy and construction of maps.
MutablePropertyValues newPvs = new MutablePropertyValues(pvs);
// Add property values based on autowire by name if applicable.
// Autowiring is autowiring based on the Bean name
if (mbd.getResolvedAutowireMode() == RootBeanDefinition.AUTOWIRE_BY_NAME) {
autowireByName(beanName, mbd, bw, newPvs);
}
// Add property values based on autowire by type if applicable.
// Autowiring is autowiring based on the Bean type
if (mbd.getResolvedAutowireMode() == RootBeanDefinition.AUTOWIRE_BY_TYPE) {
autowireByType(beanName, mbd, bw, newPvs);
}
pvs = newPvs;
}
/ / is already registered InstantiationAwareBeanPostProcessors
boolean hasInstAwareBpps = hasInstantiationAwareBeanPostProcessors();
// Whether dependency checking is required (XML)
booleanneedsDepCheck = (mbd.getDependencyCheck() ! = RootBeanDefinition.DEPENDENCY_CHECK_NONE);// Attribute injection (annotation mode)
// IABP is registered && requires dependency checking
<3> if (hasInstAwareBpps || needsDepCheck) {
if (pvs == null) {
pvs = mbd.getPropertyValues();
}
PropertyDescriptor[] filteredPds = filterPropertyDescriptorsForDependencyCheck(bw, mbd.allowCaching);
if (hasInstAwareBpps) {
for (BeanPostProcessor bp : getBeanPostProcessors()) {
if (bp instanceof InstantiationAwareBeanPostProcessor) {
InstantiationAwareBeanPostProcessor ibp = (InstantiationAwareBeanPostProcessor) bp;
// Handle attribute injection (annotation mode)!! Such as @value (), @resource, @autowire
pvs = ibp.postProcessPropertyValues(pvs, filteredPds, bw.getWrappedInstance(), beanName);
if (pvs == null) {
return; }}}}// Dependency check (XML)
<4> if(needsDepCheck) { checkDependencies(beanName, mbd, filteredPds, pvs); }} <5> if(pvs ! =null) {
// Inject attributes (XML)applyPropertyValues(beanName, mbd, bw, pvs); }}Copy the code
It is mainly divided into the following steps:
- Determines whether there is a custom property injection
- Attribute injection (XML)
- Property injection (annotation style)
- Dependency Checking (XML)
- Inject attributes (XML)
1.1. Determine whether there is custom attribute injection
At code <1> above:
/ * * before set properties to InstantiationAwareBeanPostProcessors finally a chance to change the bean. * This post reference allows users to customize property injection. * a InstantiationAwareBeanPostProcessor types such as user achieve the post processor, and through the * postProcessAfterInstantiation method to the bean's member variables into the custom information. Of course, if there is no special requirement, just use the information in the configuration to inject. In addition, the Spring is not recommended implementation * InstantiationAwareBeanPostProcessor interface directly, if you want to implement this type of post processor, More advice * through inheritance InstantiationAwareBeanPostProcessorAdapter abstract class implements a custom post processor. * /
boolean continueWithPropertyPopulation = true;
/ / bean is not "synthetic" is not defined by the application itself hold InstantiationAwareBeanPostProcessor &&
if(! mbd.isSynthetic() && hasInstantiationAwareBeanPostProcessors()) {// Run through all BeanPostProcessors
for (BeanPostProcessor bp : getBeanPostProcessors()) {
if (bp instanceof InstantiationAwareBeanPostProcessor) {
InstantiationAwareBeanPostProcessor ibp = (InstantiationAwareBeanPostProcessor) bp;
// Returns whether to continue populating the bean
/ / postProcessAfterInstantiation: if should set properties on the bean returns true, otherwise it returns false
// Normally, it should return true.
/ / returns false, will prevent the Bean instance on this call any subsequent InstantiationAwareBeanPostProcessor instance.
if(! ibp.postProcessAfterInstantiation(bw.getWrappedInstance(), beanName)) { continueWithPropertyPopulation =false;
break; }}}}// If the post-processor issues a stop population command, subsequent operations are terminated
if(! continueWithPropertyPopulation) {return;
}
Copy the code
This part of the logic is clearly written in the comments.
1.2. Attribute Injection (XML)
// XML mode is the default-Autowire attribute in the
node in XML
if (mbd.getResolvedAutowireMode() == RootBeanDefinition.AUTOWIRE_BY_NAME ||
mbd.getResolvedAutowireMode() == RootBeanDefinition.AUTOWIRE_BY_TYPE) {
// Encapsulate PropertyValues into a MutablePropertyValues object
// MutablePropertyValues allows simple manipulation of properties and provides constructors to support deep copy and construction of maps.
MutablePropertyValues newPvs = new MutablePropertyValues(pvs);
// Add property values based on autowire by name if applicable.
// Autowiring is autowiring based on the Bean name
if (mbd.getResolvedAutowireMode() == RootBeanDefinition.AUTOWIRE_BY_NAME) {
autowireByName(beanName, mbd, bw, newPvs);
}
// Add property values based on autowire by type if applicable.
// Autowiring is autowiring based on the Bean type
if (mbd.getResolvedAutowireMode() == RootBeanDefinition.AUTOWIRE_BY_TYPE) {
autowireByType(beanName, mbd, bw, newPvs);
}
pvs = newPvs;
}
Copy the code
This part of the code deals with injection of XML-like attributes, such as the default-Autowire attribute in XML
nodes, because this Spring series focuses on annotations and won’t go into detail here. Emotional interest of friends can understand their own interest ~
1.2. Attribute Injection (annotation)
PropertyDescriptor[] filteredPds = filterPropertyDescriptorsForDependencyCheck(bw, mbd.allowCaching);
if (hasInstAwareBpps) {
for (BeanPostProcessor bp : getBeanPostProcessors()) {
if (bp instanceof InstantiationAwareBeanPostProcessor) {
InstantiationAwareBeanPostProcessor ibp = (InstantiationAwareBeanPostProcessor) bp;
// Handle dependency injection (annotations) such as @value (), @resource, @autowire
pvs = ibp.postProcessPropertyValues(pvs, filteredPds, bw.getWrappedInstance(), beanName);
if (pvs == null) {
return; }}}}Copy the code
This code is at the heart of our analysis. First is whether the judge has registered InstantiationAwareBeanPostProcessor (rear instantiation of the Bean processors), if registered, iterate through all the post processor. We first to get to know the InstantiationAwareBeanPostProcessor class diagram of the structure:
InstantiationAwareBeanPostProcessor
Is a callback handler that sets propertyValues before and after an object is instantiated. It has three methods:
// This method is used to return an object (such as a proxy object) directly before the object is instantiated, instead of creating the object through the built-in instantiation process;
@Nullable
default Object postProcessBeforeInstantiation(Class
beanClass, String beanName) throws BeansException {
return null;
}
If false is returned before populateBean is executed after the object is instantiated, Spring will no longer automatically inject the corresponding bean instance.
default boolean postProcessAfterInstantiation(Object bean, String beanName) throws BeansException {
return true;
}
// This callback is performed before spring processes the default member properties and applies them to the specified bean. It can be used to check and modify the properties, and the PropertyValues returned will be applied to the bean
// @autoWired, @Resource, @Value, etc.
@Nullable
default PropertyValues postProcessPropertyValues( PropertyValues pvs, PropertyDescriptor[] pds, Object bean, String beanName) throws BeansException {
return pvs;
}
Copy the code
We basically see the third method postProcessPropertyValues (), this method is through the annotation attributes into concrete realization. There are three main implementations of this method, each with different annotations.
- AutowiredAnnotationBeanPostProcessor can handle @ Autowire, @ the Value
- CommonAnnotationBeanPostProcessor can handle @ the Resource
- RequiredAnnotationBeanPostProcessor can handle @ Required
1.2.1, AutowiredAnnotationBeanPostProcessor
It is the Spring container that specializes in Bean afterprocessors configured with auto-dependency injection assembly annotations (@Autowire, @Value, and other JSR-330 annotations). See Spring annotation @autowired source code analysis for details
1.2.2, CommonAnnotationBeanPostProcessor
CommonAnnotationBeanPostProcessor is commonly used in used in processing JavaEE5 Spring annotations (mainly the EJB related annotation) associated with Java6 on JAX – WS annotations, Handles annotations for @postConstruct, @PreDestroy, and other Bean lifecycle related events. The core of this post-processing is handling @Resource annotations, as well as JAX-WS related annotations. See the Spring annotation @Resource source code analysis for details
conclusionCopy the code
At this point, all attributes of the annotation mode have been injected.