preface
If you like my article, please give me a favorable comment. Yours must be the biggest driving force for me to insist on writing. Come on, brothers, give me some driving force
In this chapter, we will discuss the attribute injection in the process of creating beans. During the startup of Spring IOC container, the defined beans will be encapsulated as BeanDefinition and registered in a ConcurrentHashMap. After the Bean registration is completed, the simple and lazy init = false beans will be instantiated. The code for creating the Bean is in AbstractAutowireCapableBeanFactory#doCreateBean. When the Bean is created successfully, the AbstractAutowireCapableBeanFactory#populateBean method will be called for attribute injection. This article mainly analyzes how this method realizes Bean attribute injection.
Here is the flow chart of attribute injection. You can see the code according to this chart later
Attribute injection: AbstractAutowireCapableBeanFactory#populateBean
The main function of AbstractAutowireCapableBeanFactory#populateBean method is attribute filling. The source code is as follows
//Populates the bean instance in a given BeanWrapper with the property values in the bean definition. @SuppressWarnings("deprecation") // for postProcessPropertyValues protected void populateBean(String beanName, RootBeanDefinition mbd, @Nullable BeanWrapper bw) { if (bw == null) { //Judge whether there is property attribute if (mbd.hasPropertyValues()) { throw new BeanCreationException( mbd.getResourceDescription(), beanName, "Cannot apply property values to null instance"); } else { //No attributes can be populated // 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. //Let instantiaawarebeanpostprocessors also change the state of the Bean before property injection if (!mbd.isSynthetic() && hasInstantiationAwareBeanPostProcessors()) { for (BeanPostProcessor bp : getBeanPostProcessors()) { if (bp instanceof InstantiationAwareBeanPostProcessor) { InstantiationAwareBeanPostProcessor ibp = (InstantiationAwareBeanPostProcessor) bp; if (!ibp.postProcessAfterInstantiation(bw.getWrappedInstance(), beanName)) { return; } } } } //Get all PropertyValues from RootBeanDefinition PropertyValues pvs = (mbd.hasPropertyValues() ? mbd.getPropertyValues() : null); int resolvedAutowireMode = mbd.getResolvedAutowireMode(); //Get type injection by name if (resolvedAutowireMode == AUTOWIRE_BY_NAME || resolvedAutowireMode == AUTOWIRE_BY_TYPE) { MutablePropertyValues newPvs = new MutablePropertyValues(pvs); // Add property values based on autowire by name if applicable. //If applicable, add auto assemble based attribute values by name. if (resolvedAutowireMode == AUTOWIRE_BY_NAME) { autowireByName(beanName, mbd, bw, newPvs); } // Add property values based on autowire by type if applicable. //If applicable, add auto assemble based attribute values based on the type if (resolvedAutowireMode == AUTOWIRE_BY_TYPE) { autowireByType(beanName, mbd, bw, newPvs); } pvs = newPvs; } //Has the post processor been registered and initialized boolean hasInstAwareBpps = hasInstantiationAwareBeanPostProcessors(); //Whether to check the dependency. The default is false boolean needsDepCheck = (mbd.getDependencyCheck() != AbstractBeanDefinition.DEPENDENCY_CHECK_NONE); PropertyDescriptor[] filteredPds = null; if (hasInstAwareBpps) { if (pvs == null) { pvs = mbd.getPropertyValues(); } //Get post processor for (BeanPostProcessor bp : getBeanPostProcessors()) { //If Bean instantiates the post processor if (bp instanceof InstantiationAwareBeanPostProcessor) { InstantiationAwareBeanPostProcessor ibp = (InstantiationAwareBeanPostProcessor) bp; // PropertyValues pvsToUse = ibp.postProcessProperties(pvs, bw.getWrappedInstance(), beanName); if (pvsToUse == null) { if (filteredPds == null) { filteredPds = filterPropertyDescriptorsForDependencyCheck(bw, mbd.allowCaching); } //Post process the attributes that need dependency check pvsToUse = ibp.postProcessPropertyValues(pvs, filteredPds, bw.getWrappedInstance(), beanName); if (pvsToUse == null) { return; } } pvs = pvsToUse; } } } if (needsDepCheck) { if (filteredPds == null) { filteredPds = filterPropertyDescriptorsForDependencyCheck(bw, mbd.allowCaching); } checkDependencies(beanName, mbd, filteredPds, pvs); } if (pvs != null) { //Dependency injection entry: apply attributes to beans applyPropertyValues(beanName, mbd, bw, pvs); } }
Important code in method
- autowireByName: inject according to attribute name
- autowireByType: inject beans according to type
- InstantiationAwareBeanPostProcessor.postProcessPropertyValues: this method processes the given property value before the factory applies it to the given bean, such as the verification of the property in the RequiredAnnotationBeanPostProcessor class.
- applyPropertyValues: fill in of properties
AbstractAutowireCapableBeanFactory#autowireByName
autowireByName is injected according to the name, and the source code is as follows
protected void autowireByName( String beanName, AbstractBeanDefinition mbd, BeanWrapper bw, MutablePropertyValues pvs) { //Find the dependent properties in BeanWrapper String[] propertyNames = unsatisfiedNonSimpleProperties(mbd, bw); for (String propertyName : propertyNames) { if (containsBean(propertyName)) { //Recursively instantiated Bean Object bean = getBean(propertyName); pvs.add(propertyName, bean); //Register the dependent Bean and add it to the dependentBeanMap registerDependentBean(propertyName, beanName); if (logger.isTraceEnabled()) { logger.trace("Added autowiring by name from bean name '" + beanName + "' via property '" + propertyName + "' to bean named '" + propertyName + "'"); } } else { if (logger.isTraceEnabled()) { logger.trace("Not autowiring property '" + propertyName + "' of bean '" + beanName + "' by name: no matching bean found"); } } } }
This method is very simple, that is, first find the dependent Bean, recursively initialize it, and then add it to pvs
//An abstract method that defines the behavior of "auto assemble by type" (bean properties by type) protected void autowireByType( String beanName, AbstractBeanDefinition mbd, BeanWrapper bw, MutablePropertyValues pvs) { //Type converter TypeConverter converter = getCustomTypeConverter(); if (converter == null) { converter = bw; } Set<String> autowiredBeanNames = new LinkedHashSet<>(4); //Find the attribute to be injected String[] propertyNames = unsatisfiedNonSimpleProperties(mbd, bw); for (String propertyName : propertyNames) { try { //Attribute description PropertyDescriptor pd = bw.getPropertyDescriptor(propertyName); // Don't try autowiring by type for type Object: never makes sense, // even if it technically is a unsatisfied, non-simple property. if (Object.class != pd.getPropertyType()) { //Get the set method of the object MethodParameter methodParam = BeanUtils.getWriteMethodParameter(pd); // Do not allow eager init for type matching in case of a prioritized post-processor. boolean eager = !(bw.getWrappedInstance() instanceof PriorityOrdered); //Dependency description DependencyDescriptor desc = new AutowireByTypeDependencyDescriptor(methodParam, eager); //[important] get the value of the dependent attribute and store it in the autowiredBeanNames collection //It provides a pair of sets, such as: @ Autowired private list < a > as; Support, according to the type, go to all beans and inject them Object autowiredArgument = resolveDependency(desc, beanName, autowiredBeanNames, converter); if (autowiredArgument != null) { //Add to pvs pvs.add(propertyName, autowiredArgument); } for (String autowiredBeanName : autowiredBeanNames) { //Inject dependent beans registerDependentBean(autowiredBeanName, beanName); if (logger.isTraceEnabled()) { logger.trace("Autowiring by type from bean name '" + beanName + "' via property '" + propertyName + "' to bean named '" + autowiredBeanName + "'"); } } //Clean up dependencies autowiredBeanNames.clear(); } } catch (BeansException ex) { throw new UnsatisfiedDependencyException(mbd.getResourceDescription(), beanName, propertyName, ex); } } }
Seeing this, we probably know that in fact, in the populateBean method, we will first obtain the Bean's properties (PropertyValues) from the RootBeanDefinition. At the same time, we will automatically inject the mode according to the autowireMode of the RootBeanDefinition to find the dependency of the master Bean according to the name or type.
Both type injection and name injection are to find the dependent attributes of the Bean from the BeanWrapper, and then find the matching Bean according to the attribute type to realize dependency injection. It also provides a pair of sets, such as: @ Autowired private list < a > as; Support for collection injection.
After the property is searched, it will be encapsulated into PropertyValues, and then passed to applyPropertyValues to be applied to the Bean.
AbstractAutowireCapableBeanFactory#applyPropertyValues
We can think that the previous code is looking for the dependent properties for the current Bean and encapsulating them in PropertyValues. In applyPropertyValues, the properties are applied to the current Bean.
//Handle references between objects, using deep copy protected void applyPropertyValues(String beanName, BeanDefinition mbd, BeanWrapper bw, PropertyValues pvs) { if (pvs.isEmpty()) { return; } if (System.getSecurityManager() != null && bw instanceof BeanWrapperImpl) { ((BeanWrapperImpl) bw).setSecurityContext(getAccessControlContext()); } MutablePropertyValues mpvs = null; List<PropertyValue> original; if (pvs instanceof MutablePropertyValues) { mpvs = (MutablePropertyValues) pvs; //Judge whether the value in mpvs has been converted to the corresponding type. After that, you can directly set the value to BeanWrapper if (mpvs.isConverted()) { // Shortcut: use the pre-converted values as-is. try { //Set properties for instanced objects bw.setPropertyValues(mpvs); return; } catch (BeansException ex) { throw new BeanCreationException( mbd.getResourceDescription(), beanName, "Error setting property values", ex); } } //Gets the original type of the property value original = mpvs.getPropertyValueList(); } else { //If the type is not MutablePropertyValues, the native property acquisition method is used original = Arrays.asList(pvs.getPropertyValues()); } //Get user-defined type converter TypeConverter converter = getCustomTypeConverter(); if (converter == null) { converter = bw; } //Parser: the Helper class used for bean factory implementation, which parses the value contained in the bean definition object into the actual value applied to the target bean instance. BeanDefinitionValueResolver valueResolver = new BeanDefinitionValueResolver(this, beanName, mbd, converter); // Create a deep copy, resolving any references for values. //Store the converted attributes, create a new copy of the attribute resolution value of the Bean, and inject the copied data into the object List<PropertyValue> deepCopy = new ArrayList<>(original.size()); boolean resolveNecessary = false; //Type conversion, which converts the attribute to the corresponding type for (PropertyValue pv : original) { if (pv.isConverted()) { //The attribute value does not need to be converted deepCopy.add(pv); } else { //Attribute name String propertyName = pv.getName(); //The original attribute value, whose type is a reference type such as runtimebeanreference < otherbean > Object originalValue = pv.getValue(); //Convert the attribute value and convert the reference to the instantiated object reference OtherBean in the IOC container Object resolvedValue = valueResolver.resolveValueIfNecessary(pv, originalValue); Object convertedValue = resolvedValue; boolean convertible = bw.isWritableProperty(propertyName) && !PropertyAccessorUtils.isNestedOrIndexedProperty(propertyName); if (convertible) { //Convert using user-defined converters convertedValue = convertForProperty(resolvedValue, propertyName, bw, converter); } // Possibly store converted value in merged bean definition, // in order to avoid re-conversion for every created bean instance. if (resolvedValue == originalValue) { if (convertible) { //Set the converted value to PV, and set the dependent Bean to PropertyValue pv.setConvertedValue(convertedValue); } deepCopy.add(pv); } else if (convertible && originalValue instanceof TypedStringValue && !((TypedStringValue) originalValue).isDynamic() && !(convertedValue instanceof Collection || ObjectUtils.isArray(convertedValue))) { pv.setConvertedValue(convertedValue); deepCopy.add(pv); } else { resolveNecessary = true; //The converted dependent attributes are finally placed in an ArrayList deepCopy.add(new PropertyValue(pv, convertedValue)); } } } if (mpvs != null && !resolveNecessary) { mpvs.setConverted(); } // Set our (possibly massaged) deep copy. try { //Set the parsed property to BeanWrapper bw.setPropertyValues(new MutablePropertyValues(deepCopy)); } catch (BeansException ex) { throw new BeanCreationException( mbd.getResourceDescription(), beanName, "Error setting property values", ex); } }
Attribute conversion is mainly carried out here and then applied to beans. For example, in BeanDefinition, attributes may be described by string type, and attributes need to be converted into real original attribute types.
- First, judge whether the attribute needs to be converted. If not, it is directly applied to the Bean. For example: < property name = "otherbean" ref = "otherbean" / > this property value is actually a string "otherbean", which needs to be resolved into a reference to the otherbean instance in the container.
- If the attribute value needs type conversion, for example, if the attribute value is another Bean in the container, the referenced object needs to be resolved according to the attribute value, and then injected into the attribute of the object and applied to the Bean.
Resolve the attribute value through the resolveValueIfNecessary() method in the BeanDefinitionValueResolver class, and inject the attribute value through BW Setpropertyvalues() method completed
Resolution: BeanDefinitionValueResolver#resolveValueIfNecessary
Given a PropertyValue, type resolution is performed according to the property value, and references to other bean s in the factory are resolved if necessary
@Nullable public Object resolveValueIfNecessary(Object argName, @Nullable Object value) { // We must check each value to see whether it requires a runtime reference // to another bean to be resolved. //Resolution of property values that are reference types if (value instanceof RuntimeBeanReference) { //For example, < property name = "XX" ref = "xxbean" is the reference type, which will go here RuntimeBeanReference ref = (RuntimeBeanReference) value; //Resolve reference type properties return resolveReference(argName, ref); } ///The property value is the resolution of the name of another Bean in the reference container else if (value instanceof RuntimeBeanNameReference) { String refName = ((RuntimeBeanNameReference) value).getBeanName(); refName = String.valueOf(doEvaluate(refName)); //Determine whether this Bean exists in the container if (!this.beanFactory.containsBean(refName)) { throw new BeanDefinitionStoreException( "Invalid bean name '" + refName + "' in bean reference for " + argName); } return refName; } else if (value instanceof BeanDefinitionHolder) { // Resolve BeanDefinitionHolder: contains BeanDefinition with name and aliases. //Resolve BeanDefinitionHolder: contains BeanDefinition with name and alias BeanDefinitionHolder bdHolder = (BeanDefinitionHolder) value; //Resolve internal Bean return resolveInnerBean(argName, bdHolder.getBeanName(), bdHolder.getBeanDefinition()); } else if (value instanceof BeanDefinition) { // Resolve plain BeanDefinition, without contained name: use dummy name. //Resolve pure BeanDefinition without name BeanDefinition bd = (BeanDefinition) value; String innerBeanName = "(inner bean)" + BeanFactoryUtils.GENERATED_BEAN_NAME_SEPARATOR + ObjectUtils.getIdentityHexString(bd); return resolveInnerBean(argName, innerBeanName, bd); } //Parsing array types else if (value instanceof ManagedArray) { // May need to resolve contained runtime references. ManagedArray array = (ManagedArray) value; Class<?> elementType = array.resolvedElementType; if (elementType == null) { String elementTypeName = array.getElementTypeName(); if (StringUtils.hasText(elementTypeName)) { try { elementType = ClassUtils.forName(elementTypeName, this.beanFactory.getBeanClassLoader()); array.resolvedElementType = elementType; } catch (Throwable ex) { // Improve the message by showing the context. throw new BeanCreationException( this.beanDefinition.getResourceDescription(), this.beanName, "Error resolving array type for " + argName, ex); } } else { elementType = Object.class; } } return resolveManagedArray(argName, (List<?>) value, elementType); } //Resolve collection type else if (value instanceof ManagedList) { // May need to resolve contained runtime references. return resolveManagedList(argName, (List<?>) value); } //Resolve Set type else if (value instanceof ManagedSet) { // May need to resolve contained runtime references. return resolveManagedSet(argName, (Set<?>) value); } //Resolve Map type else if (value instanceof ManagedMap) { // May need to resolve contained runtime references. return resolveManagedMap(argName, (Map<?, ?>) value); } //Parsing Properties else if (value instanceof ManagedProperties) { Properties original = (Properties) value; Properties copy = new Properties(); original.forEach((propKey, propValue) -> { if (propKey instanceof TypedStringValue) { propKey = evaluate((TypedStringValue) propKey); } if (propValue instanceof TypedStringValue) { propValue = evaluate((TypedStringValue) propValue); } if (propKey == null || propValue == null) { throw new BeanCreationException( this.beanDefinition.getResourceDescription(), this.beanName, "Error converting Properties key/value pair for " + argName + ": resolved to null"); } copy.put(propKey, propValue); }); return copy; } //Resolve attribute values of string type else if (value instanceof TypedStringValue) { // Convert value to target type here. TypedStringValue typedStringValue = (TypedStringValue) value; Object valueObject = evaluate(typedStringValue); try { //Target type Class<?> resolvedTargetType = resolveTargetType(typedStringValue); if (resolvedTargetType != null) { //Resolve the target type return this.typeConverter.convertIfNecessary(valueObject, resolvedTargetType); } else { //If the type is not obtained, the Object type is returned return valueObject; } } catch (Throwable ex) { // Improve the message by showing the context. throw new BeanCreationException( this.beanDefinition.getResourceDescription(), this.beanName, "Error converting typed String value for " + argName, ex); } } else if (value instanceof NullBean) { return null; } else { return evaluate(value); } }
In this method, it is resolved according to the type of attribute value, such as String, array, list, set and map. More complex is that the attribute value depends on a Bean, so you need to find the instance of the Bean in the container according to the name of the dependent Bean, as shown below:
/** * Resolve a reference to another bean in the factory. */ //Resolution of associated objects @Nullable private Object resolveReference(Object argName, RuntimeBeanReference ref) { try { Object bean; //Name of the reference object String refName = ref.getBeanName(); refName = String.valueOf(doEvaluate(refName)); //If the object is in the parent container, get it from the parent container if (ref.isToParent()) { if (this.beanFactory.getParentBeanFactory() == null) { throw new BeanCreationException( this.beanDefinition.getResourceDescription(), this.beanName, "Can't resolve reference to bean '" + refName + "' in parent factory: no parent factory available"); } //If the object is in the parent container, get it from the parent container bean = this.beanFactory.getParentBeanFactory().getBean(refName); } else { //[important] obtain the Bean from the current container according to the name of the dependent Bean bean = this.beanFactory.getBean(refName); //Suggest the dependency relationship between the instance of the dependent Bean and the current object, and use the dependentBeanMap to maintain the relationship this.beanFactory.registerDependentBean(refName, this.beanName); } if (bean instanceof NullBean) { bean = null; } return bean; } catch (BeansException ex) { throw new BeanCreationException( this.beanDefinition.getResourceDescription(), this.beanName, "Cannot resolve reference to bean '" + ref.getBeanName() + "' while setting " + argName, ex); } } * For each element in the managed array, resolve reference if necessary. */ //Parse array private Object resolveManagedArray(Object argName, List<?> ml, Class<?> elementType) { Object resolved = Array.newInstance(elementType, ml.size()); for (int i = 0; i < ml.size(); i++) { Array.set(resolved, i, resolveValueIfNecessary(new KeyedArgName(argName, i), ml.get(i))); } return resolved; } /** * For each element in the managed list, resolve reference if necessary. */ //Parse List private List<?> resolveManagedList(Object argName, List<?> ml) { List<Object> resolved = new ArrayList<>(ml.size()); for (int i = 0; i < ml.size(); i++) { resolved.add(resolveValueIfNecessary(new KeyedArgName(argName, i), ml.get(i))); } return resolved; } /** * For each element in the managed set, resolve reference if necessary. */ //Parse set private Set<?> resolveManagedSet(Object argName, Set<?> ms) { Set<Object> resolved = new LinkedHashSet<>(ms.size()); int i = 0; for (Object m : ms) { resolved.add(resolveValueIfNecessary(new KeyedArgName(argName, i), m)); i++; } return resolved; } /** * For each element in the managed map, resolve reference if necessary. */ //Parse Map private Map<?, ?> resolveManagedMap(Object argName, Map<?, ?> mm) { Map<Object, Object> resolved = new LinkedHashMap<>(mm.size()); mm.forEach((key, value) -> { Object resolvedKey = resolveValueIfNecessary(argName, key); Object resolvedValue = resolveValueIfNecessary(new KeyedArgName(argName, key), value); resolved.put(resolvedKey, resolvedValue); }); return resolved; }
After the property value is parsed, it is encapsulated into a MutablePropertyValues through BeanWrapperImpl The setpropertyvalues () method completes the value injection, and the injection method in BeanWrapperImpl is completed by AbstractPropertyAccessor#setPropertyValue(java.lang.String, java.lang.Object).
AbstractPropertyAccessor#setPropertyValue
@Override public void setPropertyValues(PropertyValues pvs, boolean ignoreUnknown, boolean ignoreInvalid) throws BeansException { List<PropertyAccessException> propertyAccessExceptions = null; //Get all the attribute lists List<PropertyValue> propertyValues = (pvs instanceof MutablePropertyValues ? ((MutablePropertyValues) pvs).getPropertyValueList() : Arrays.asList(pvs.getPropertyValues())); for (PropertyValue pv : propertyValues) { try { // This method may throw any BeansException, which won't be caught // here, if there is a critical failure such as no matching field. // We can attempt to deal only with less serious exceptions. //Set attribute value setPropertyValue(pv); } ...ellipsis... @Override public void setPropertyValue(String propertyName, @Nullable Object value) throws BeansException { //Property accessor AbstractNestablePropertyAccessor nestedPa; try { nestedPa = getPropertyAccessorForPropertyPath(propertyName); } catch (NotReadablePropertyException ex) { throw new NotWritablePropertyException(getRootClass(), this.nestedPath + propertyName, "Nested property in path '" + propertyName + "' does not exist", ex); } //Property assistant PropertyTokenHolder tokens = getPropertyNameTokens(getFinalPath(nestedPa, propertyName)); //Setting values for properties through property accessors nestedPa.setPropertyValue(tokens, new PropertyValue(propertyName, value)); }
It can be seen here that the property injection is completed by the AbstractNestablePropertyAccessor property accessor
protected void setPropertyValue(PropertyTokenHolder tokens, PropertyValue pv) throws BeansException { if (tokens.keys != null) { processKeyedProperty(tokens, pv); } else { //Come here processLocalProperty(tokens, pv); } } private void processLocalProperty(PropertyTokenHolder tokens, PropertyValue pv) { //Attribute processor PropertyHandler ph = getLocalPropertyHandler(tokens.actualName); if (ph == null || !ph.isWritable()) { if (pv.isOptional()) { if (logger.isDebugEnabled()) { logger.debug("Ignoring optional value for property '" + tokens.actualName + "' - property not found on bean class [" + getRootClass().getName() + "]"); } return; } else { throw createNotWritablePropertyException(tokens.canonicalName); } } Object oldValue = null; try { //Native value Object originalValue = pv.getValue(); Object valueToApply = originalValue; ...ellipsis... //This is the key point. Set the property value to the object through PropertyHandler ph.setValue(valueToApply); } catch (TypeMismatchException ex) { throw ex; }
The property value here is set through PropertyHandler
@Override public void setValue(@Nullable Object value) throws Exception { //Get the set method of the attribute Method writeMethod = (this.pd instanceof GenericTypeAwarePropertyDescriptor ? ((GenericTypeAwarePropertyDescriptor) this.pd).getWriteMethodForActualAccess() : this.pd.getWriteMethod()); if (System.getSecurityManager() != null) { AccessController.doPrivileged((PrivilegedAction<Object>) () -> { ReflectionUtils.makeAccessible(writeMethod); return null; }); try { AccessController.doPrivileged((PrivilegedExceptionAction<Object>) () -> writeMethod.invoke(getWrappedInstance(), value), acc); } catch (PrivilegedActionException ex) { throw ex.getException(); } } else { //Set access rights ReflectionUtils.makeAccessible(writeMethod); //Call the set method to set the attribute value writeMethod.invoke(getWrappedInstance(), value); } }
Here is the set method to get the attribute, and then call the set method to inject the value into it.
Constructor injection parameters
When analyzing the creation of Bean before, we said that in AbstractAutowireCapableBeanFactory#createBeanInstance, the constructor of the Bean will be obtained through reflection. If it is a parametric construction, we will use the autowireConstructor method to create an instance through parametric construction
protected BeanWrapper createBeanInstance(String beanName, RootBeanDefinition mbd, @Nullable Object[] args) { // Make sure bean class is actually resolved at this point. Class<?> beanClass = resolveBeanClass(mbd, beanName); ...ellipsis... // Need to determine the constructor... Constructor<?>[] ctors = determineConstructorsFromBeanPostProcessors(beanClass, beanName); if (ctors != null || mbd.getResolvedAutowireMode() == RootBeanDefinition.AUTOWIRE_CONSTRUCTOR || mbd.hasConstructorArgumentValues() || !ObjectUtils.isEmpty(args)) { //[important] constructor injection parameters return autowireConstructor(beanName, mbd, ctors, args); } // No special handling: simply use no-arg constructor. return instantiateBean(beanName, mbd); }
In the autowireConstructor method, the constructor parameters will be resolved through the ConstructorResolver
protected BeanWrapper autowireConstructor( String beanName, RootBeanDefinition mbd, @Nullable Constructor<?>[] ctors, @Nullable Object[] explicitArgs) { //Constructor, parser, injection return new ConstructorResolver(this).autowireConstructor(beanName, mbd, ctors, explicitArgs); } public BeanWrapper autowireConstructor(final String beanName, final RootBeanDefinition mbd, @Nullable Constructor<?>[] chosenCtors, @Nullable final Object[] explicitArgs) { ...ellipsis... else { //Get constructor parameters ConstructorArgumentValues cargs = mbd.getConstructorArgumentValues(); //Get constructor parameter value resolvedValues = new ConstructorArgumentValues(); //Analytical parameter value [important] minNrOfArgs = resolveConstructorArguments(beanName, mbd, bw, cargs, resolvedValues); } ...ellipsis... try { //Instantiation strategy final InstantiationStrategy strategy = beanFactory.getInstantiationStrategy(); Object beanInstance; if (System.getSecurityManager() != null) { final Constructor<?> ctorToUse = constructorToUse; final Object[] argumentsToUse = argsToUse; beanInstance = AccessController.doPrivileged((PrivilegedAction<Object>) () -> strategy.instantiate(mbd, beanName, beanFactory, ctorToUse, argumentsToUse), beanFactory.getAccessControlContext()); } else { //Instantiate an object and create an instance using reflection according to the parameterized constructor beanInstance = strategy.instantiate(mbd, beanName, this.beanFactory, constructorToUse, argsToUse); } bw.setBeanInstance(beanInstance); return bw; }
The resolveConstructorArguments method uses BeanDefinitionValueResolver to resolve the attribute value. If there is a parameter value, it will go through reflection, and the instance will be created and returned according to the parameter constructor.
private int resolveConstructorArguments(String beanName, RootBeanDefinition mbd, BeanWrapper bw, ConstructorArgumentValues cargs, ConstructorArgumentValues resolvedValues) { TypeConverter customConverter = this.beanFactory.getCustomTypeConverter(); TypeConverter converter = (customConverter != null ? customConverter : bw); //Parser for attribute values BeanDefinitionValueResolver valueResolver = new BeanDefinitionValueResolver(this.beanFactory, beanName, mbd, converter); ...ellipsis... for (ConstructorArgumentValues.ValueHolder valueHolder : cargs.getGenericArgumentValues()) { if (valueHolder.isConverted()) { resolvedValues.addGenericArgumentValue(valueHolder); } else { //Parsing the constructor parameter value is the same as the attribute value parsing of set injection previously analyzed Object resolvedValue = valueResolver.resolveValueIfNecessary("constructor argument", valueHolder.getValue()); ConstructorArgumentValues.ValueHolder resolvedValueHolder = new ConstructorArgumentValues.ValueHolder( resolvedValue, valueHolder.getType(), valueHolder.getName()); resolvedValueHolder.setSource(valueHolder); resolvedValues.addGenericArgumentValue(resolvedValueHolder); } } return minNrOfArgs; }
Because the resolveValueIfNecessary method has been analyzed before, I won't talk about it here.
summary
Here, the process of attribute injection is analyzed and summarized in this figure
If you like it, give me a high praise. Your must be the biggest driving force for me to insist on writing. Come on, brothers, give me some driving force