We have seen how bean instances are created. We have seen how bean instances are created. Today we’ll look at the implementation of the populateBean method on one of the key points: dependency injection resolution.

The profile

Mainly from today to explore the parsing of dependency injection to see AbstractAutowireCapableBeanFactory# populateBean method of implementation, the method is mainly divided into the following four points:

  1. Support for external custom property injection, which controls whether to continue to set property values for the Bean
  2. Inject properties into PropertyValues (assemble by name or assemble by type)
  3. Properties of parsing out but not set reprocessing (postProcessPropertyValues)
  4. Set the PropertyValues in PropertyValues to BeanWrapper

Source code analysis

AbstractAutowireCapableBeanFactory#populateBean

Without further ado, take a look at the source implementation of the populateBean method:

protected void populateBean(String beanName, RootBeanDefinition mbd, @Nullable BeanWrapper bw) {.../ / to InstantiationAwareBeanPostProcessors last chance before the property into modified Bean attribute value, can also control whether to fill the Bean
	/ / by calling the specific postProcessAfterInstantiation method, if the call returns false, said don't need to continue the dependency injection, returned directly
	// Attribute injection can be customized by the user. Implement a InstantiationAwareBeanPostProcessor types such as user's post processor,
	/ / and through postProcessAfterInstantiation method to the bean's member variables into the custom information.
	if(! mbd.isSynthetic() && hasInstantiationAwareBeanPostProcessors()) {for (BeanPostProcessor bp : getBeanPostProcessors()) {
			if (bp instanceof InstantiationAwareBeanPostProcessor) {
				InstantiationAwareBeanPostProcessor ibp = (InstantiationAwareBeanPostProcessor) bp;
				if(! ibp.postProcessAfterInstantiation(bw.getWrappedInstance(), beanName)) {return; }}}}// PVS is a MutablePropertyValues instance that implements the PropertyValues interface,
	// Provides read/write operations on properties, and deep copy can be implemented by calling constructors
	BeanDefinition = BeanDefinition = BeanDefinition = BeanDefinition
	PropertyValues pvs = (mbd.hasPropertyValues() ? mbd.getPropertyValues() : null);
	// The default is 0, which means that all dependency injection needs to be explicitly configured in the XML file
	// If the related dependency assembly mode is set, the properties of the Bean will be traversed to complete the corresponding injection by type or name, no additional configuration is required
	int resolvedAutowireMode = mbd.getResolvedAutowireMode();
	if (resolvedAutowireMode == AUTOWIRE_BY_NAME || resolvedAutowireMode == AUTOWIRE_BY_TYPE) {
		MutablePropertyValues newPvs = new MutablePropertyValues(pvs);
		// Set autowiring based on beanName
		// ps: 
      
		if (resolvedAutowireMode == AUTOWIRE_BY_NAME) {
			autowireByName(beanName, mbd, bw, newPvs);
		}
		// Autowiring is processed automatically based on the type of the Bean
		// ps: 
      
		if (resolvedAutowireMode == AUTOWIRE_BY_TYPE) {
			autowireByType(beanName, mbd, bw, newPvs);
		}
		pvs = newPvs;
	}
	Whether registered InstantiationAwareBeanPostProcessor / / container
	boolean hasInstAwareBpps = hasInstantiationAwareBeanPostProcessors();
	// Whether to check dependencies. Default is false
	booleanneedsDepCheck = (mbd.getDependencyCheck() ! = AbstractBeanDefinition.DEPENDENCY_CHECK_NONE); PropertyDescriptor[] filteredPds =null;
	if (hasInstAwareBpps) {
		if (pvs == null) {
			pvs = mbd.getPropertyValues();
		}
		for (BeanPostProcessor bp : getBeanPostProcessors()) {
			if (bp instanceof InstantiationAwareBeanPostProcessor) {
				InstantiationAwareBeanPostProcessor ibp = (InstantiationAwareBeanPostProcessor) bp;
				// This is where dependency injection is performed on the @autowired tag properties
				PropertyValues pvsToUse = ibp.postProcessProperties(pvs, bw.getWrappedInstance(), beanName);
				if (pvsToUse == null) {
					if (filteredPds == null) {
						filteredPds = filterPropertyDescriptorsForDependencyCheck(bw, mbd.allowCaching);
					}
					// Parsed properties that are not set are processed again
					pvsToUse = ibp.postProcessPropertyValues(pvs, filteredPds, bw.getWrappedInstance(), beanName);
					if (pvsToUse == null) {
						return; } } pvs = pvsToUse; }}}// This attribute is deprecated in 3.0
	if (needsDepCheck) {
		// Filter out all attribute editors that need dependency checking
		if (filteredPds == null) {
			filteredPds = filterPropertyDescriptorsForDependencyCheck(bw, mbd.allowCaching);
		}
		checkDependencies(beanName, mbd, filteredPds, pvs);
	}

	if(pvs ! =null) {
		// Finally, the property is injected into the Bean Wrapper instance. The injection is for properties explicitly configured with autowiredbyName or ByType.
		/ / for comments, because the AutowiredAnnotationBeanPostProcessor have already completed the injection,
		// So it is not executed hereapplyPropertyValues(beanName, mbd, bw, pvs); }}Copy the code

Ok, let’s look at the implementation logic one by one

Support for external custom attribute injection

if(! mbd.isSynthetic() && hasInstantiationAwareBeanPostProcessors()) {for (BeanPostProcessor bp : getBeanPostProcessors()) {
		if (bp instanceof InstantiationAwareBeanPostProcessor) {
			InstantiationAwareBeanPostProcessor ibp = (InstantiationAwareBeanPostProcessor) bp;
			if(! ibp.postProcessAfterInstantiation(bw.getWrappedInstance(), beanName)) {return; }}}}Copy the code

As you can see, before the set properties, make any implementation InstantiationAwareBeanPostProcessor interface class to have the opportunity to modify the state of the bean. Specific by calling postProcessAfterInstantiation method, if the call returns false, said don’t need to continue the dependency injection, returned directly

The main point here is to allow the user to customize the attribute injection. Implement a InstantiationAwareBeanPostProcessor types such as user’s post processor, and through postProcessAfterInstantiation method to the bean’s member variables into the custom information.

Inject properties into PropertyValues

Note here: Regular, according to the dependency injection pattern complete injection Bean configuration resolvedAutowireMode default is 0, is not to walk the following logic autowireByName or autowireByType, In this injection can see doCreateBean applyMergedBeanDefinitionPostProcessors, detailed in the previous article. The autowireByName method is applied only if autowire=”byName” is declared in the configuration file.

	// PVS is a MutablePropertyValues instance that implements the PropertyValues interface,
	// Provides read/write operations on properties, and deep copy can be implemented by calling constructors
	BeanDefinition = BeanDefinition = BeanDefinition = BeanDefinition
	PropertyValues pvs = (mbd.hasPropertyValues() ? mbd.getPropertyValues() : null);
	// The default is 0, which means that all dependency injection needs to be explicitly configured in the XML file
	// If the related dependency assembly mode is set, the properties of the Bean will be traversed to complete the corresponding injection by type or name, no additional configuration is required
	int resolvedAutowireMode = mbd.getResolvedAutowireMode();
	if (resolvedAutowireMode == AUTOWIRE_BY_NAME || resolvedAutowireMode == AUTOWIRE_BY_TYPE) {
		MutablePropertyValues newPvs = new MutablePropertyValues(pvs);
		// Set autowiring based on beanName
		// ps: 
      
		if (resolvedAutowireMode == AUTOWIRE_BY_NAME) {
			autowireByName(beanName, mbd, bw, newPvs);
		}
		// Set autowiring based on BeanType
		// ps: 
      
		if (resolvedAutowireMode == AUTOWIRE_BY_TYPE) {
			autowireByType(beanName, mbd, bw, newPvs);
		}
		pvs = newPvs;
	}
Copy the code

So let’s follow up with the autowireByName method

protected void autowireByName( String beanName, AbstractBeanDefinition mbd, BeanWrapper bw, MutablePropertyValues pvs) {
	// Get the name of the non-simple type attribute to inject
	String[] propertyNames = unsatisfiedNonSimpleProperties(mbd, bw);
	for (String propertyName : propertyNames) {
		// Check whether there is a bean or BeanDefinition associated with propertyName.
		// If so, call the beanFactory.getBean method to get the bean instance
		if (containsBean(propertyName)) {
			// Get the corresponding bean instance from the container
			Object bean = getBean(propertyName);
			// Store the parsed bean in the attribute value list PVS
			pvs.add(propertyName, bean);
			// Register dependencies
			registerDependentBean(propertyName, beanName);
			// logger
		} 
		// logger}}Copy the code

As you can see, this method mainly gets the name of the property of the non-simple type to be injected, gets the corresponding bean instance from the container based on the property name, and then registers the corresponding dependency.

Now let’s look at getting to the injection of a simple type of attribute names unsatisfiedNonSimpleProperties method

protected String[] unsatisfiedNonSimpleProperties(AbstractBeanDefinition mbd, BeanWrapper bw) {
	Set<String> result = new TreeSet<>();
	PropertyValues pvs = mbd.getPropertyValues();
	PropertyDescriptor[] pds = bw.getPropertyDescriptors();
	for (PropertyDescriptor pd : pds) {
		if(pd.getWriteMethod() ! =null&&! isExcludedFromDependencyCheck(pd) && ! pvs.contains(pd.getName()) && ! BeanUtils.isSimpleProperty(pd.getPropertyType())) { result.add(pd.getName()); }}return StringUtils.toStringArray(result);
}
Copy the code

This method mainly gets the name of a non-simple type attribute that is not configured in the configuration file.

So what are simple types? What Spring considers simple type attributes are:

  1. The implementation class of the CharSequence interface, such as String
  2. Enum
  3. Date
  4. URI/URL
  5. An inherited class of Number, such as Integer/Long
  6. byte/short/int… Isobasic type
  7. Locale
  8. All of the above types of arrays, such as String[], Date[], int[], and so on

In addition to requiring properties of non-simple types, the property is not configured in the configuration file, that is, pvs.contains(pd.getName()) = false. This is the judgment condition in the above source code if.

Let’s look at the autowireByType method for autowiring based on BeanType:

protected void autowireByType( String beanName, AbstractBeanDefinition mbd, BeanWrapper bw, MutablePropertyValues pvs) {
	// Get the attribute type converter
	TypeConverter converter = getCustomTypeConverter();
	if (converter == null) {
		converter = bw;
	}
	// Used to hold the name of the parsed property to be injected
	Set<String> autowiredBeanNames = new LinkedHashSet<>(4);
	// Get the name of the attribute to inject (non-simple attribute (8 primitive types, characters, URLS, etc.))
	String[] propertyNames = unsatisfiedNonSimpleProperties(mbd, bw);
	for (String propertyName : propertyNames) {
		try {
			// 获取指定属性名称的属性 Descriptor(Descriptor用来记载属性的getter setter type等情况)
			PropertyDescriptor pd = bw.getPropertyDescriptor(propertyName);
			// If the attribute type is Object, it will be ignored and not parsed
			if(Object.class ! = pd.getPropertyType()) {// Get the setter method for the property
				MethodParameter methodParam = BeanUtils.getWriteMethodParameter(pd);
				// For a post-processor that inherits PriorityOrdered, no immediate initialization (hot loading) is allowed
				booleaneager = ! PriorityOrdered.class.isInstance(bw.getWrappedInstance());// Create a dependency description to be injected to provide uniform access
				DependencyDescriptor desc = new AutowireByTypeDependencyDescriptor(methodParam, eager);
				// Return all Bean instances to be injected by resolving dependencies based on BeanDefinition of the container
				Object autowiredArgument = resolveDependency(desc, beanName, autowiredBeanNames, converter);
				if(autowiredArgument ! =null) {
					// Store the parsed bean in the attribute value list PVS
					pvs.add(propertyName, autowiredArgument);
				}
				for (String autowiredBeanName : autowiredBeanNames) {
					// Register dependencies
					registerDependentBean(autowiredBeanName, beanName);
					if (logger.isTraceEnabled()) {
						logger.trace("Autowiring by type from bean name '" + beanName + "' via property '" +
								propertyName + "' to bean named '" + autowiredBeanName + "'"); }}// Clear records of injected propertiesautowiredBeanNames.clear(); }}catch (BeansException ex) {
			throw newUnsatisfiedDependencyException(mbd.getResourceDescription(), beanName, propertyName, ex); }}}Copy the code

This method is slightly more complex than the autowireByName method in that the name of the bean corresponding to the attribute is uncertain and is parsed accordingly.

This method also starts by getting the name of the non-simple type attribute, creating a description of the dependency to be injected based on the name, providing consistent access, resolving the dependency based on the BeanDefinition of the container, and returning all the Bean instances to be injected. Finally, the resolved bean is stored in the attribute value list PVS and the registerDependentBean method is executed to register the dependency.

Reprocess parsed but unset properties

@autowired: @autowired: @autowired: @autowired: @autowired: @autowired: @autowired

Whether registered InstantiationAwareBeanPostProcessor / / container
boolean hasInstAwareBpps = hasInstantiationAwareBeanPostProcessors();
// Whether to check the dependencies. The default value is false, which determines whether to check the dependencies later.
booleanneedsDepCheck = (mbd.getDependencyCheck() ! = AbstractBeanDefinition.DEPENDENCY_CHECK_NONE); PropertyDescriptor[] filteredPds =null;
if (hasInstAwareBpps) {
	if (pvs == null) {
		pvs = mbd.getPropertyValues();
	}
	for (BeanPostProcessor bp : getBeanPostProcessors()) {
		if (bp instanceof InstantiationAwareBeanPostProcessor) {
			InstantiationAwareBeanPostProcessor ibp = (InstantiationAwareBeanPostProcessor) bp;
			// Do dependency injection for the @autoWired tag attribute
			PropertyValues pvsToUse = ibp.postProcessProperties(pvs, bw.getWrappedInstance(), beanName);
			if (pvsToUse == null) {
				if (filteredPds == null) {
					filteredPds = filterPropertyDescriptorsForDependencyCheck(bw, mbd.allowCaching);
				}
				// Parsed properties that are not set are processed again
				pvsToUse = ibp.postProcessPropertyValues(pvs, filteredPds, bw.getWrappedInstance(), beanName);
				if (pvsToUse == null) {
					return; } } pvs = pvsToUse; }}}Copy the code

We follow up postProcessProperties dependency injection method, the realization of his class for: AutowiredAnnotationBeanPostProcessor

public PropertyValues postProcessProperties(PropertyValues pvs, Object bean, String beanName) {
	// Get the meta information for the @autowired annotation in the specified class
	InjectionMetadata metadata = findAutowiringMetadata(beanName, bean.getClass(), pvs);
	try {
		// Automatically inject the Bean properties
		metadata.inject(bean, beanName, pvs);
	}
	/ / catch...
	return pvs;
}
Copy the code

Inject () ¶ We are familiar with the inject method, which is to iterate over each field and inject it, and finally call the Invoke method for reflection processing. Let’s take a look at the meta information of @autowired related annotation in the specified class:

private InjectionMetadata findAutowiringMetadata(String beanName, Class<? > clazz,@Nullable PropertyValues pvs) {
	String cacheKey = (StringUtils.hasLength(beanName) ? beanName : clazz.getName());
	// Look in the container to see if there is an Autowire for the given class
	InjectionMetadata metadata = this.injectionMetadataCache.get(cacheKey);
	if (InjectionMetadata.needsRefresh(metadata, clazz)) {
		synchronized (this.injectionMetadataCache) {
			metadata = this.injectionMetadataCache.get(cacheKey);
			if (InjectionMetadata.needsRefresh(metadata, clazz)) {
				if(metadata ! =null) {
					metadata.clear(pvs);
				}
                // Parse the given class @autowired to focus on the meta information
				metadata = buildAutowiringMetadata(clazz);
				// Store the obtained information about the given class autowire in the container cache
				this.injectionMetadataCache.put(cacheKey, metadata); }}}return metadata;
}
Copy the code

As you can see, this method mainly parses the information of the given class @Autowired and stores the information of the given class Autowire in the container cache.

Set the PropertyValues in PropertyValues to BeanWrapper

Here we can see that there is a prejudgment condition PVS! = null, so the method (applyPropertyValues) will only be called if an autowireByName or autowireByType property injection is performed, and the property will eventually be injected into the Wrapper instance of the Bean. The source code is as follows:

if(pvs ! =null) {
	applyPropertyValues(beanName, mbd, bw, pvs);
}

protected void applyPropertyValues(String beanName, BeanDefinition mbd, BeanWrapper bw, PropertyValues pvs) {
	// Attribute list zise = 0
	if (pvs.isEmpty()) {
		return;
	}
	if(System.getSecurityManager() ! =null && bw instanceof BeanWrapperImpl) {
		// Set the security context, JDK security mechanism
		((BeanWrapperImpl) bw).setSecurityContext(getAccessControlContext());
	}

	MutablePropertyValues mpvs = null;
	List<PropertyValue> original;

	if (pvs instanceof MutablePropertyValues) {
		mpvs = (MutablePropertyValues) pvs;
		if (mpvs.isConverted()) {
			// If the attribute value has already been converted, assign the value directly
			try {
				bw.setPropertyValues(mpvs);
				return;
			}
			catch (BeansException ex) {
				throw new BeanCreationException(
						mbd.getResourceDescription(), beanName, "Error setting property values", ex); }}// If it is not converted, record the value of the original type before the conversion
		original = mpvs.getPropertyValueList();
	}
	else {
		// If PVS is not of type MutablePropertyValues, use the primitive type directly
		original = Arrays.asList(pvs.getPropertyValues());
	}
	// Get the user's custom type conversion
	TypeConverter converter = getCustomTypeConverter();
	if (converter == null) {
		converter = bw;
	}
	// Create a Bean definition property value parser that resolves the property value of the Bean definition to the actual value of the Bean instance object
	BeanDefinitionValueResolver valueResolver = new BeanDefinitionValueResolver(this, beanName, mbd, converter);

	// Create a copy of the value of the property to be resolved and inject the copy data into the Bean instance
	List<PropertyValue> deepCopy = new ArrayList<>(original.size());
	boolean resolveNecessary = false;
	for (PropertyValue pv : original) {
		// Attribute values that do not need conversion are added directly
		if (pv.isConverted()) {
			deepCopy.add(pv);
		}
		else {
			String propertyName = pv.getName();
			// Retain the value of the property before the transformation
			Object originalValue = pv.getValue();
			}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}
			if (originalValue == AutowiredPropertyMarker.INSTANCE) {
				Method writeMethod = bw.getPropertyDescriptor(propertyName).getWriteMethod();
				if (writeMethod == null) {
					throw new IllegalArgumentException("Autowire marker for property without write method: " + pv);
				}
				originalValue = new DependencyDescriptor(new MethodParameter(writeMethod, 0), true);
			}
			// Convert property values, such as a reference to an object instantiated in the container
			Object resolvedValue = valueResolver.resolveValueIfNecessary(pv, originalValue);
			Object convertedValue = resolvedValue;
			// Whether the attribute value can be converted
			booleanconvertible = bw.isWritableProperty(propertyName) && ! PropertyAccessorUtils.isNestedOrIndexedProperty(propertyName);if (convertible) {
				// Convert property values using a user-defined type converter
				convertedValue = convertForProperty(resolvedValue, propertyName, bw, converter);
			}
			// Store the converted property value, avoiding the transformation every time the property is injected
			if (resolvedValue == originalValue) {
				if (convertible) {
					pv.setConvertedValue(convertedValue);
				}
				deepCopy.add(pv);
			}
			else if (convertible && originalValue instanceofTypedStringValue && ! ((TypedStringValue) originalValue).isDynamic() && ! (convertedValueinstanceof Collection || ObjectUtils.isArray(convertedValue))) {
				pv.setConvertedValue(convertedValue);
				deepCopy.add(pv);
			}
			else {
				resolveNecessary = true;
				deepCopy.add(newPropertyValue(pv, convertedValue)); }}}if(mpvs ! =null && !resolveNecessary) {
		// Tag attributes have been transformed
		mpvs.setConverted();
	}

	try {
		// Use the Java reflection mechanism to inject properties into the bean using the set method.
		bw.setPropertyValues(new MutablePropertyValues(deepCopy));
	}
	catch (BeansException ex) {
		throw new BeanCreationException(
				mbd.getResourceDescription(), beanName, "Error setting property values", ex); }}Copy the code

The collective operation is marked above, which is to generate an object of the type that needs to be injected by performing a transformation operation, and then call the setPropertyValues method to inject the property into the bean using Java’s reflection mechanism according to the set method.

This article is based on the spring framework 5.2.10.RELEASE version for analysis