Dependency injection related source code parsing

Xml and annotations are implemented in much the same way, and can be divided into the following categories based on the different approaches

  1. XML setter injection
  2. Annotation property injection
  3. Annotation/XML constructor parameter injection
  4. XML factory injection / @bean setter injection

XML setter injection

This is actually injected during the populateBean attribute assignment phase. The tags we declare in XML are read by XmlBeanDefinitionReader and mapped to PropertyValues in BeanDefinition, the real object that gets the attributes via dependency lookup, and finally injected into the Bean by reflection

  1. Related XML environment configuration

      
<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xsi:schemaLocation="http://www.springframework.org/schema/beans https://www.springframework.org/schema/beans/spring-beans.xsd">
    <bean id="user" class="blog.spring.introduction.domain.User">
        <property name="age" value="12"/>
        <property name="name" value="lazylittle"/>
    </bean>
</beans>

Copy the code
  1. The POJO
@Data
public class User {

    private String name;

    private Integer age;
}
Copy the code
  1. Bootstrap class
public class DependencyInjectionSourceDemo {

    public static void main(String[] args) {
        DefaultListableBeanFactory beanFactory = new DefaultListableBeanFactory();
        XmlBeanDefinitionReader reader = new XmlBeanDefinitionReader(beanFactory);
        reader.loadBeanDefinitions("META-INF/display-source-context.xml"); System.out.println(beanFactory.getBean(User.class)); }}Copy the code
  1. The container does not automatically initialize singleton beans when operating in a BeanFactory environment. So we use dependency lookupgetBean(User.class)Start Bean creation and property injection for our source code analysis. Let’s ignore the Bean creation and go straight to the property assignment phase:AbstractAutowireCapableBeanFactory#populateBean(String beanName, RootBeanDefinition mbd, @Nullable BeanWrapper bw)
  2. debug populateBeanAs can be seen in the figureUserThere are already two beanDefinitions after loading the Xml meta-informationPropertyValue.
	//AbstractAutowireCapableBeanFactory.class
	protected void populateBean(String beanName, RootBeanDefinition mbd, @Nullable BeanWrapper bw) {
		//1. Throw an exception if there is no value in the current BeanWrapper but there is a value in the BeanDefinition.
    if (bw == null) {
			if (mbd.hasPropertyValues()) {
				throw new BeanCreationException(
						mbd.getResourceDescription(), beanName, "Cannot apply property values to null instance");
			}
			else {
				return; }}/ / 2. If there is a InstantiationAwareBeanPostProcessor, here are all the callback
		/ / InstantiationAwareBeanPostProcessor# postProcessAfterInstantiation (), if you return false skip attribute assignment stage
		if(! mbd.isSynthetic() && hasInstantiationAwareBeanPostProcessors()) {for (InstantiationAwareBeanPostProcessor bp : getBeanPostProcessorCache().instantiationAware) {
				if(! bp.postProcessAfterInstantiation(bw.getWrappedInstance(), beanName)) {return;
				}
			}
		}

		PropertyValues pvs = (mbd.hasPropertyValues() ? mbd.getPropertyValues() : null);
		//3. If the mode is Autowiring, go to the corresponding injection method. Here we do not use Autowiring, so we will skip it
		int resolvedAutowireMode = mbd.getResolvedAutowireMode();
		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 (resolvedAutowireMode == AUTOWIRE_BY_NAME) {
				autowireByName(beanName, mbd, bw, newPvs);
			}
			// Add property values based on autowire by type if applicable.
			if (resolvedAutowireMode == AUTOWIRE_BY_TYPE) {
				autowireByType(beanName, mbd, bw, newPvs);
			}
			pvs = newPvs;
		}
		
		boolean hasInstAwareBpps = hasInstantiationAwareBeanPostProcessors();
		booleanneedsDepCheck = (mbd.getDependencyCheck() ! = AbstractBeanDefinition.DEPENDENCY_CHECK_NONE);/ / 4. Here is also the InstantiationAwareBeanPostProcessor lifecycle callback, used to customize the current PropertyValues before the assignment
    // This will also be skipped
		PropertyDescriptor[] filteredPds = null;
		if (hasInstAwareBpps) {
			if (pvs == null) {
				pvs = mbd.getPropertyValues();
			}
			for (InstantiationAwareBeanPostProcessor bp : getBeanPostProcessorCache().instantiationAware) {
				PropertyValues pvsToUse = bp.postProcessProperties(pvs, bw.getWrappedInstance(), beanName);
				if (pvsToUse == null) {
					if (filteredPds == null) {
						filteredPds = filterPropertyDescriptorsForDependencyCheck(bw, mbd.allowCaching);
					}
					pvsToUse = bp.postProcessPropertyValues(pvs, filteredPds, bw.getWrappedInstance(), beanName);
					if (pvsToUse == null) {
						return; } } pvs = pvsToUse; }}// 5. Dependency check, this column is not set, skip
    / / mainly filter ignoredDependencyTypes ignoredDependencyInterfaces related classes
		if (needsDepCheck) {
			if (filteredPds == null) {
				filteredPds = filterPropertyDescriptorsForDependencyCheck(bw, mbd.allowCaching);
			}
			checkDependencies(beanName, mbd, filteredPds, pvs);
		}
		//6. The core application attribute method
		if(pvs ! =null) { applyPropertyValues(beanName, mbd, bw, pvs); }}Copy the code
  1. Go to the core method for setting propertiesapplyPropertyValues()
	protected void applyPropertyValues(String beanName, BeanDefinition mbd, BeanWrapper bw, PropertyValues pvs) {
		// omit irrelevant code...
    //1. Create a value parser
		BeanDefinitionValueResolver valueResolver = new BeanDefinitionValueResolver(this, beanName, mbd, converter);
		// omit irrelevant code..
    //2
				Object resolvedValue = valueResolver.resolveValueIfNecessary(pv, originalValue);
				Object convertedValue = resolvedValue;
    //3. Related to type conversion, XML is a String type and is converted to the corresponding type in the Bean by TypeConverter
				booleanconvertible = bw.isWritableProperty(propertyName) && ! PropertyAccessorUtils.isNestedOrIndexedProperty(propertyName);if (convertible) {
					convertedValue = convertForProperty(resolvedValue, propertyName, bw, converter);
		// omit extraneous code
		//4. Use reflection to set the property and complete the property injection (including the related Api of PropertyAccessor to be parsed later in the data binding)
		try {
			bw.setPropertyValues(new MutablePropertyValues(deepCopy));
		}
		catch (BeansException ex) {
			throw new BeanCreationException(
					mbd.getResourceDescription(), beanName, "Error setting property values", ex); }}Copy the code

Annotation method property injection

There are actually two pieces here, but the logic is the same

  • @Autowired.@InjectThrough:AutowiredAnnotationBeanPostProcessorThis is the post-processor to do the processing
  • @ResourceThrough:CommonAnnotationBeanPostProcessorprocessed

The core step

Scan and build meta-information of concern

The callback time point is after the Bean instance is created and before the ObjectFactory (used to resolve loop dependencies) is exposed, Is actually MergedBeanDefinitionPostProcessor# postProcessMergedBeanDefinition (RootBeanDefinition MBD, Class
beanType, String BeanName) callback, position in AbstractAutowirCapableBeanFactory# applyMergedBeanDefinitionPostProcessors () will callback AutowiredAnnotationBeanPo at this time StProcessor# postProcessMergedBeanDefinition (), here we come to the source code:

  1. Enter theAutowiredAnnotationBeanPostProcessor
	@Override
	public void postProcessMergedBeanDefinition(RootBeanDefinition beanDefinition, Class
        beanType, String beanName) {
    //1. Query @autowired related meta information
		InjectionMetadata metadata = findAutowiringMetadata(beanName, beanType, null);
		// 2. Check the configuration
		metadata.checkConfigMembers(beanDefinition);
	}
Copy the code
  1. findAuttowiringMetadata()What meta information does the method load?
	//1. Find Autowired meta information
 private InjectionMetadata findAutowiringMetadata(String beanName, Class<? > clazz,@Nullable PropertyValues pvs) {
		// Check if there is any in the cache
		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);
					}
          // The core method finds and builds AutowiringMetadata
					metadata = buildAutowiringMetadata(clazz);
					this.injectionMetadataCache.put(cacheKey, metadata); }}}return metadata;
	}
	//2. Find and build AutowiringMetadata
	private InjectionMetadata buildAutowiringMetadata(finalClass<? > clazz) {
    //2.1 Recursively retrieve meta information from the parent class
		do {
			final List<InjectionMetadata.InjectedElement> currElements = new ArrayList<>();
			//2.2 Get all attributes of the current class
			ReflectionUtils.doWithLocalFields(targetClass, field -> {
        //2.3 Get @autowired annotation informationMergedAnnotation<? > ann = findAutowiredAnnotation(field);if(ann ! =null) {
          //2.4 Return if the field is static
					if (Modifier.isStatic(field.getModifiers())) {
						if (logger.isInfoEnabled()) {
							logger.info("Autowired annotation is not supported on static fields: " + field);
						}
						return;
					}
          //2.5 Check if it is required @autoiwred (required = true)
					boolean required = determineRequiredStatus(ann);
          //2.6 Construct AutowiredFieldElement and add it to the candidate meta-information list
					currElements.add(newAutowiredFieldElement(field, required)); }});//3. Handle all methods, similar to properties
			ReflectionUtils.doWithLocalMethods(targetClass, method -> {
				Method bridgedMethod = BridgeMethodResolver.findBridgedMethod(method);
				if(! BridgeMethodResolver.isVisibilityBridgeMethodPair(method, bridgedMethod)) {return; } MergedAnnotation<? > ann = findAutowiredAnnotation(bridgedMethod);if(ann ! =null && method.equals(ClassUtils.getMostSpecificMethod(method, clazz))) {
					if (Modifier.isStatic(method.getModifiers())) {
						if (logger.isInfoEnabled()) {
							logger.info("Autowired annotation is not supported on static methods: " + method);
						}
						return;
					}
					/ /... Omit related logs
					boolean required = determineRequiredStatus(ann);
					PropertyDescriptor pd = BeanUtils.findPropertyForMethod(bridgedMethod, clazz);
          // Set method meta information
					currElements.add(newAutowiredMethodElement(method, required, pd)); }}); elements.addAll(0, currElements);
			targetClass = targetClass.getSuperclass();
		}
		while(targetClass ! =null&& targetClass ! = Object.class);//4. Encapsulate it as InjectionMetadata
		return InjectionMetadata.forElements(elements, clazz);
	}

Copy the code
A dependency lookup is performed on the property to be injected and then reflection injection is performed

The first step to construct good InjectionMetdata, and then to attribute assignment before populateBean life cycle will callback all InstantiationAwareBeanPostProcessor# postProcessProperties () method, At this time will enter into the AutowiredAnnotationBeanPostProcessor corresponding callback

		// AbstractAutowireCapableBeanFactory#popultaeBea()
			/ / 1. Get all the InstantiationAwareBeanPostProcessor callback postProcessProperties ()
			for (InstantiationAwareBeanPostProcessor bp : getBeanPostProcessorCache().instantiationAware) {
				PropertyValues pvsToUse = bp.postProcessProperties(pvs, bw.getWrappedInstance(), beanName);
				if (pvsToUse == null) {
					if (filteredPds == null) {
						filteredPds = filterPropertyDescriptorsForDependencyCheck(bw, mbd.allowCaching);
					}
					pvsToUse = bp.postProcessPropertyValues(pvs, filteredPds, bw.getWrappedInstance(), beanName);
					if (pvsToUse == null) {
						return; } } pvs = pvsToUse; }}//AutowiredAnnotationBeanPostProcessor
	@Override
	public PropertyValues postProcessProperties(PropertyValues pvs, Object bean, String beanName) {
    / / 1. Before MergedBeanDefinitionPostProcess built in () callback InjectionMetadata, at this time will return directly from the cache
		InjectionMetadata metadata = findAutowiringMetadata(beanName, bean.getClass(), pvs);
		try {
     //2. Perform injection
			metadata.inject(bean, beanName, pvs);
		}
		return pvs;
	}
	//InjectionMetadata
	public void inject(Object target, @Nullable String beanName, @Nullable PropertyValues pvs) throws Throwable {
		Collection<InjectedElement> checkedElements = this.checkedElements; Collection<InjectedElement> elementsToIterate = (checkedElements ! =null ? checkedElements : this.injectedElements);
		if(! elementsToIterate.isEmpty()) {InjectedElement constructed from @autowired field and Method
			for (InjectedElement element : elementsToIterate) {
        //2. Execute the injection methods in sequenceelement.inject(target, beanName, pvs); }}}Copy the code

Select the corresponding AutowiredElement implementation based on the field/method

AutowiredFieldElement# inject () implementation

		protected void inject(Object bean, @Nullable String beanName, @Nullable PropertyValues pvs) throws Throwable {
			Field field = (Field) this.member;
			Object value;
			if (this.cached) {
				value = resolvedCachedArgument(beanName, this.cachedFieldValue);
			}
			else {
        //1. Encapsulate into DependencyDescriptor. This object is very important and is a core object in dependency injection scenarios
        // This contains the field to be injected, or the method parameter meta information
				DependencyDescriptor desc = new DependencyDescriptor(field, this.required);
				desc.setContainingClass(bean.getClass());
				Set<String> autowiredBeanNames = new LinkedHashSet<>(1); Assert.state(beanFactory ! =null."No BeanFactory available"); TypeConverter typeConvert,, er = the beanFactory getTypeConverter ();try {
          //2. This method is the core method for injection, which is used to obtain the candidate Bean object based on our DependencyDescriptor
					value = beanFactory.resolveDependency(desc, beanName, autowiredBeanNames, typeConverter);
				}
				catch (BeansException ex) {
					throw new UnsatisfiedDependencyException(null, beanName, new InjectionPoint(field), ex);
				}
				synchronized (this) {
					if (!this.cached) {
						Object cachedFieldValue = null;
						if(value ! =null || this.required) {
							cachedFieldValue = desc;
							//3. Register dependencies and cache Settings
							registerDependentBeans(beanName, autowiredBeanNames);
							if (autowiredBeanNames.size() == 1) {
								String autowiredBeanName = autowiredBeanNames.iterator().next();
								if (beanFactory.containsBean(autowiredBeanName) &&
										beanFactory.isTypeMatch(autowiredBeanName, field.getType())) {
									cachedFieldValue = newShortcutDependencyDescriptor( desc, autowiredBeanName, field.getType()); }}}this.cachedFieldValue = cachedFieldValue;
						this.cached = true; }}}if(value ! =null) {
				//4. Reflection set propertiesReflectionUtils.makeAccessible(field); field.set(bean, value); }}}Copy the code

AutowiredMethodElement#inject()

		protected void inject(Object bean, @Nullable String beanName, @Nullable PropertyValues pvs) throws Throwable {
      //1. Cache related processing
			if (checkPropertySkipping(pvs)) {
				return;
			}
			Method method = (Method) this.member;
			Object[] arguments;
			if (this.cached) {
				// Shortcut for avoiding synchronization...
				arguments = resolveCachedArguments(beanName);
			}
			else {
				int argumentCount = method.getParameterCount();
				arguments = new Object[argumentCount];
				DependencyDescriptor[] descriptors = new DependencyDescriptor[argumentCount];
				Set<String> autowiredBeans = newLinkedHashSet<>(argumentCount); Assert.state(beanFactory ! =null."No BeanFactory available");
				TypeConverter typeConverter = beanFactory.getTypeConverter();
				for (int i = 0; i < arguments.length; i++) {
					MethodParameter methodParam = new MethodParameter(method, i);
					DependencyDescriptor currDesc = new DependencyDescriptor(methodParam, this.required);
					currDesc.setContainingClass(bean.getClass());
					descriptors[i] = currDesc;
					try {
            //2. Encapsulate DependencyDescriptor
						Object arg = beanFactory.resolveDependency(currDesc, beanName, autowiredBeans, typeConverter);
						if (arg == null&&!this.required) {
							arguments = null;
							break;
						}
						arguments[i] = arg;
					}
					catch (BeansException ex) {
						throw new UnsatisfiedDependencyException(null, beanName, newInjectionPoint(methodParam), ex); }}// omit injection dependencies and associated cache handling...
			if(arguments ! =null) {
				try {
					//3. Reflection injection
					ReflectionUtils.makeAccessible(method);
					method.invoke(bean, arguments);
				}
				catch (InvocationTargetException ex) {
					throwex.getTargetException(); }}}Copy the code
Core lookup depends on the processAutowireCapableBeanFaactory#resolvableDependency()
  1. The method declaration is as follows
/** * descriptor: dependency descriptor to be parsed, e.g., inject B into A, so here's A descriptor for B, including field/method/consturct * requestingBeanName: B name * autowiredBeanNames: resolvableDependency Find all dependent Bean collection * typeConverter: type conversion related **/
@Nullable
	Object resolveDependency(DependencyDescriptor descriptor, @Nullable String requestingBeanName,
			@Nullable Set<String> autowiredBeanNames, @Nullable TypeConverter typeConverter) throws BeansException;
Copy the code
  1. DependencyDescriptorThe core dependency description object, which holds meta information about the dependency properties to be injected
// Insert B into A
public class DependencyDescriptor extends InjectionPoint implements Serializable {
	private finalClass<? > declaringClass;//A's native Class object, if enhanced by CGLIB, is not A proxy object
	@Nullable
	private String methodName;  // B If it is method injection, this will be the method name
	@Nullable
	privateClass<? >[] parameterTypes;// Method parameter type
	private int parameterIndex; // Method parameter index
	@Nullable
	private String fieldName; // The attribute name of B
	private final boolean required; // Is required
	private final boolean eager; // If hungry, true = not lazy loading
  // The number of nesting layers, which specifies the number of layers to look for dependency types, for example, declaringClass is Optional
      
       >
      
	private int nestingLevel = 1; 
	@Nullable
	privateClass<? > containingClass;// proxy object of A
	@Nullable
	private transient volatile ResolvableType resolvableType; // Generic information
	@Nullable
	private transient volatile TypeDescriptor typeDescriptor; // Type description
}
Copy the code
  1. Start our DefaultLisableBeanFactory# resolveDependency () parsing!!

    Several different types of parsing dependency types (related to circular dependencies and lazy loading)

    • Optional: Non-lazy loading, does not resolve constructor loop dependencies, but can inject beans that do not exist, not outNoSuchBeanDefinitionException
    • ObjectFactory, ObjectProvider, JSR 330 Provider: lazy loading, can solve the constructor cycle dependency
    • Lazy: Lazy load, which generates proxy objects to resolve constructor loop dependencies
	@Override
	@Nullable
	public Object resolveDependency(DependencyDescriptor descriptor, @Nullable String requestingBeanName,
			@Nullable Set<String> autowiredBeanNames, @Nullable TypeConverter typeConverter) throws BeansException {
		//1. Initialize the name detector to DependencyDescriptor. The name of the parameter used to probe the property/method. Those of you who know how to use SpringMVC@RequestParam should be familiar with this component
		descriptor.initParameterNameDiscovery(getParameterNameDiscoverer());
    //2. If the dependency type is Optional, return Optional wrapped objects (not lazy loading).
		if (Optional.class == descriptor.getDependencyType()) {
			return createOptionalDependency(descriptor, requestingBeanName);
		}
		/ / 3. The ObjectFactory/ObjectProvider type processing, return DependencyObjectProvider object, (lazy loading)
    GetObject ()/getIfAvaliable() can be used to obtain dependent objects
		else if (ObjectFactory.class == descriptor.getDependencyType() ||
				ObjectProvider.class == descriptor.getDependencyType()) {
			return new DependencyObjectProvider(descriptor, requestingBeanName);
		}
    //4. Jsr330 Provider type processing, similar to ObojectFactory, using get() method to obtain dependent objects (lazy loading)
		else if (javaxInjectProviderClass == descriptor.getDependencyType()) {
			return new Jsr330Factory().createDependencyProvider(descriptor, requestingBeanName);
		}
		else {
      //5. @lazy-loaded annotation processing will return the proxy object (lazy-loaded).
			Object result = getAutowireCandidateResolver().getLazyResolutionProxyIfNecessary(
					descriptor, requestingBeanName);
			if (result == null) {
        //6. Handle general POJOs and collection arrays, etc
				result = doResolveDependency(descriptor, requestingBeanName, autowiredBeanNames, typeConverter);
			}
			returnresult; }}Copy the code
  1. So let’s do this firstdoResolveDependencyMethod, which is more complex, does dependency lookup based on different dependency types.
	public Object doResolveDependency(DependencyDescriptor descriptor, @Nullable String beanName,
			@Nullable Set<String> autowiredBeanNames, @Nullable TypeConverter typeConverter) throws BeansException {
		Set descriptor cache (ThreadLocal)
		InjectionPoint previousInjectionPoint = ConstructorResolver.setCurrentInjectionPoint(descriptor);
		try {
			/ / 1.1 if the type descriptor is a snapshot, then directly through the beanFactory. GetBen () to obtain rely on Bean object, because the snapshot type ShortcutDependencyDescriptor cache the parsed beanName, After the success of the concrete resolution in AutowiredFieldElement/AutowiredMethodElement will cache the snapshot
			Object shortcut = descriptor.resolveShortcut(this);
			if(shortcut ! =null) {
				returnshortcut; } Class<? > type = descriptor.getDependencyType();//2. Handle @value annotations (more on externalizing configurations)
			Object value = getAutowireCandidateResolver().getSuggestedValue(descriptor);
			if(value ! =null) {
				if (value instanceof String) {
					//2.1 Handle placeholdersString strVal = resolveEmbeddedValue((String) value); BeanDefinition bd = (beanName ! =null && containsBean(beanName) ?
							getMergedBeanDefinition(beanName) : null); value = evaluateBeanDefinitionString(strVal, bd); } TypeConverter converter = (typeConverter ! =null ? typeConverter : getTypeConverter());
				try {
					//2.2 Type conversion if necessary,
					return converter.convertIfNecessary(value, type, descriptor.getTypeDescriptor());
				}
				catch (UnsupportedOperationException ex) {
					// A custom TypeConverter which does not support TypeDescriptor resolution...
					return(descriptor.getField() ! =null? converter.convertIfNecessary(value, type, descriptor.getField()) : converter.convertIfNecessary(value, type, descriptor.getMethodParameter())); }}Stream/Array/Collection /Map
			Object multipleBeans = resolveMultipleBeans(descriptor, beanName, autowiredBeanNames, typeConverter);
			if(multipleBeans ! =null) {
				return multipleBeans;
			}
			//4. Find common dependencies
			Map<String, Object> matchingBeans = findAutowireCandidates(beanName, type, descriptor);
			if (matchingBeans.isEmpty()) {
				//4.1 Not found again required = true throws an exception
				if (isRequired(descriptor)) {
					raiseNoMatchingBeanFound(type, descriptor.getResolvableType(), descriptor);
				}
				return null;
			}

			String autowiredBeanName;
			Object instanceCandidate;

			/ / 5. When the candidate into the Bean is greater than 1, then the @ Primary - > @ Priority (javax.mail. The annotation. Priority) - >
			/ / ResolvableDependency (through ConfigurableListableBeanFactory# registerResolvableDependency) - > by name (alias)
			if (matchingBeans.size() > 1) {
				autowiredBeanName = determineAutowireCandidate(matchingBeans, descriptor);
				if (autowiredBeanName == null) {
					/ / this time according to the type matching has multiple, but can't judge the priority bean is thrown NoUniqueBeanDefinitionException
					if(isRequired(descriptor) || ! indicatesMultipleBeans(type)) {return descriptor.resolveNotUnique(descriptor.getResolvableType(), matchingBeans);
					}
					else {
						return null;
					}
				}
				instanceCandidate = matchingBeans.get(autowiredBeanName);
			}
			else {
				// We have exactly one match.
				Map.Entry<String, Object> entry = matchingBeans.entrySet().iterator().next();
				autowiredBeanName = entry.getKey();
				instanceCandidate = entry.getValue();
			}

			if(autowiredBeanNames ! =null) {
				autowiredBeanNames.add(autowiredBeanName);
			}
			//6. Rely on the lookup to find candidate beans
			if (instanceCandidate instanceof Class) {
				instanceCandidate = descriptor.resolveCandidate(autowiredBeanName, type, this);
			}
			Object result = instanceCandidate;
			// Handle an exception that cannot be found
			if (result instanceof NullBean) {
				if (isRequired(descriptor)) {
					raiseNoMatchingBeanFound(type, descriptor.getResolvableType(), descriptor);
				}
				result = null;
			}
			if(! ClassUtils.isAssignableValue(type, result)) {throw new BeanNotOfRequiredTypeException(autowiredBeanName, type, instanceCandidate.getClass());
			}
			return result;
		}
		finally{ ConstructorResolver.setCurrentInjectionPoint(previousInjectionPoint); }}Copy the code

The steps above are roughly as follows:

  • From the snapshot (ShortcutDependencyDescriptor), if any
  • To deal with@Valueannotations
  • resolveMultipleBeans()Parsing complex objects (Stream.Array.Collection.Map) Find, if any
  • findAutowireCandidates()Parse simple POJO types
protected Map<String, Object> findAutowireCandidates(
			@NullableString beanName, Class<? > requiredType, DependencyDescriptor descriptor) {
		//1. Get the beanName array recursively according to type
		String[] candidateNames = BeanFactoryUtils.beanNamesForTypeIncludingAncestors(
				this, requiredType, true, descriptor.isEager());
    //2. Create result set container
		Map<String, Object> result = CollectionUtils.newLinkedHashMap(candidateNames.length);
		//3. Try to get the candidate Bean from ResolvableDependencies
		for(Map.Entry<Class<? >, Object> classObjectEntry :this.resolvableDependencies.entrySet()) { Class<? > autowiringType = classObjectEntry.getKey();if (autowiringType.isAssignableFrom(requiredType)) {
				Object autowiringValue = classObjectEntry.getValue();
				autowiringValue = AutowireUtils.resolveAutowiringValue(autowiringValue, requiredType);
				if (requiredType.isInstance(autowiringValue)) {
					result.put(ObjectUtils.identityToString(autowiringValue), autowiringValue);
					break; }}}//4. Get non-own beans, and filter through generics and Qualifier
		for (String candidate : candidateNames) {
			if(! isSelfReference(beanName, candidate) && isAutowireCandidate(candidate, descriptor)) {//4.1 Add to result setaddCandidateEntry(result, candidate, descriptor, requiredType); }}//5. If not, fallback matches beans whose generics do not match
		if (result.isEmpty()) {
			boolean multiple = indicatesMultipleBeans(requiredType);
			// Consider fallback matches if the first pass failed to find anything...
			DependencyDescriptor fallbackDescriptor = descriptor.forFallbackMatch();
			for (String candidate : candidateNames) {
						(!multiple || getAutowireCandidateResolver().hasQualifier(descriptor))) {
					addCandidateEntry(result, candidate, descriptor, requiredType);
				}
			}
			if(result.isEmpty() && ! multiple) {//6. Parse your own injection scene
				for (String candidate : candidateNames) {
					if(isSelfReference(beanName, candidate) && (! (descriptorinstanceofMultiElementDescriptor) || ! beanName.equals(candidate)) && isAutowireCandidate(candidate, fallbackDescriptor)) { addCandidateEntry(result, candidate, descriptor, requiredType); }}}}return result;
	}
Copy the code
  • determineAutowireCandidate()If more than one matching Bean is obtained by parsing (passfindAutowiredCandidates()Method, handle generic type filtering, Qualifier filtering), then try to get the best Bean from @primary -> @priority -> ResovlableDependency -> concrete name)
	protected String determineAutowireCandidate(Map<String, Object> candidates, DependencyDescriptor descriptor) { Class<? > requiredType = descriptor.getDependencyType();// select a candidate whose primary is declared
		String primaryCandidate = determinePrimaryCandidate(candidates, requiredType);
		if(primaryCandidate ! =null) {
			// if there is a direct return
			return primaryCandidate;
		}
    //2. Obtain the @priority value with a large value
		String priorityCandidate = determineHighestPriorityCandidate(candidates, requiredType);
		if(priorityCandidate ! =null) {
			return priorityCandidate;
		}	
    < span style = "box-sizing: border-box; color: RGB (74, 74, 74); line-height: 22px; font-size: 14px! Important; white-space: inherit! Important;
		for (Map.Entry<String, Object> entry : candidates.entrySet()) {
			String candidateName = entry.getKey();
			Object beanInstance = entry.getValue();
			if((beanInstance ! =null && this.resolvableDependencies.containsValue(beanInstance)) ||
					matchesBeanName(candidateName, descriptor.getDependencyName())) {
				returncandidateName; }}return null;
	}
Copy the code
  • If not found, and to required = true is thrown NoSuchBeanDefinitionException, if more than one optimal Bean thrown NoUniqueBeanDefinitionException
  1. Optional type parsing related processing
	privateOptional<? > createOptionalDependency( DependencyDescriptor descriptor,@Nullable String beanName, final Object... args) {
		// Wrap a nested dependency descriptor. I'm actually going to check the dependency type level +1, like Optional
      
    // Ordinary DependencyDescriptor queries only Optional types, while level +1 checks the Holder type
		DependencyDescriptor descriptorToUse = new NestedDependencyDescriptor(descriptor) {
			@Override
			public boolean isRequired(a) {
				return false;
			}
			@Override
			public Object resolveCandidate(String beanName, Class
        requiredType, BeanFactory beanFactory) {
				return(! ObjectUtils.isEmpty(args) ? beanFactory.getBean(beanName, args) :super.resolveCandidate(beanName, requiredType, beanFactory)); }};//2. Look for the optimal dependency and find that this is not lazy loading, but simply wrapping the result set with Optional
		Object result = doResolveDependency(descriptorToUse, beanName, null.null);
    //3. If null is returned, an empty Optional object is returned
		return (result instanceofOptional ? (Optional<? >) result : Optional.ofNullable(result)); }Copy the code
  1. ObjectFactory, ObjectProvider(which SpringBoot uses heavily for lazy construction), and Provider lazy loading types
		else if (ObjectFactory.class == descriptor.getDependencyType() ||
				ObjectProvider.class == descriptor.getDependencyType()) {
      // Returns a DependencyObjectProvider object directly
			return new DependencyObjectProvider(descriptor, requestingBeanName);
		}
// This class is an implementation class of ObjectProvider
private class DependencyObjectProvider implements BeanObjectProvider<Object> {
		private final DependencyDescriptor descriptor;
		private final boolean optional;
		@Nullable
		private final String beanName;
		public DependencyObjectProvider(DependencyDescriptor descriptor, @Nullable String beanName) {
      //1. Construct a nested dependency description object, where the hierarchy +1 is changed to type T in resolving ObjectProvider
      
			this.descriptor = new NestedDependencyDescriptor(descriptor);
			this.optional = (this.descriptor.getDependencyType() == Optional.class);
			this.beanName = beanName;
		}
  	//2. Lazy loading, when we call getObject() with the ObjectProvider object of dependency injection
		@Override
		public Object getObject(a) throws BeansException {
			if (this.optional) {
				return createOptionalDependency(this.descriptor, this.beanName);
			}
			else {
        // Formalize dependency resolution
				Object result = doResolveDependency(this.descriptor, this.beanName, null.null);
				if (result == null) {
					throw new NoSuchBeanDefinitionException(this.descriptor.getResolvableType());
				}
				returnresult; }}Copy the code

Provider: implemented according to the JSR330 standard, similar to ObjectProvider

		else if (javaxInjectProviderClass == descriptor.getDependencyType()) {
      Jsr330Provider implements the Provider and ObjectProvider interfaces. Jsr330Provider implements the Provider and ObjectProvider interfaces
      //2. Call its get() method to adapt to the same method as ObjectProvider
			return new Jsr330Factory().createDependencyProvider(descriptor, requestingBeanName);
		}

	private class Jsr330Factory implements Serializable {
		public Object createDependencyProvider(DependencyDescriptor descriptor, @Nullable String beanName) {
			return new Jsr330Provider(descriptor, beanName);
		}
		private class Jsr330Provider extends DependencyObjectProvider implements Provider<Object> {
			public Jsr330Provider(DependencyDescriptor descriptor, @Nullable String beanName) {
				super(descriptor, beanName);
			}
			@Override
			@Nullable
			public Object get(a) throws BeansException {
        //3. Apply getValue() to the implementation of DependencyObjectProvider
				returngetValue(); }}}Copy the code

Lazy Dynamic proxy Lazy loading mode

		else {
      / / DefaultListableBeanFactory# resolveDependency processing @ Lazy annotation
			Object result = getAutowireCandidateResolver().getLazyResolutionProxyIfNecessary(
					descriptor, requestingBeanName);
			return result;
		}
 //ContextAnnotationAutowireCandidateResolver#getLazyResolutionProxyIfNecessary
	public Object getLazyResolutionProxyIfNecessary(DependencyDescriptor descriptor, @Nullable String beanName) {
    //1. Check if @lazy annotations annotate properties or methods, if so, construct proxy objects and return them
		return (isLazy(descriptor) ? buildLazyResolutionProxy(descriptor, beanName) : null);
	}

	protected Object buildLazyResolutionProxy(final DependencyDescriptor descriptor, final @Nullable String beanName) {
		//1.1 Build proxy objects
		TargetSource ts = new TargetSource() {
			@Override
			publicClass<? > getTargetClass() {return descriptor.getDependencyType();
			}
			@Override
			public boolean isStatic(a) {
				return false;
			}
			@Override
			public Object getTarget(a) {
        //1.2 The callback is only made when the proxy object is officially used.Set<String> autowiredBeanNames = (beanName ! =null ? new LinkedHashSet<>(1) : null);
        //1.3 Parsing dependent beans
				Object target = dlbf.doResolveDependency(descriptor, beanName, autowiredBeanNames, null);
				if (target == null) { Class<? > type = getTargetClass();if (Map.class == type) {
						return Collections.emptyMap();
					}
					else if (List.class == type) {
						return Collections.emptyList();
					}
					else if (Set.class == type || Collection.class == type) {
						return Collections.emptySet();
					}
					throw new NoSuchBeanDefinitionException(descriptor.getResolvableType(),
							"Optional dependency not present for lazy injection point");
				}
				if(autowiredBeanNames ! =null) {
					for (String autowiredBeanName : autowiredBeanNames) {
						if(dlbf.containsBean(autowiredBeanName)) { dlbf.registerDependentBean(autowiredBeanName, beanName); }}}return target;
			}
			@Override
			public void releaseTarget(Object target) {}};//2. Use the Spring proxy factory to build the proxy object return
		ProxyFactory pf = newProxyFactory(); pf.setTargetSource(ts); Class<? > dependencyType = descriptor.getDependencyType();if (dependencyType.isInterface()) {
			pf.addInterface(dependencyType);
		}
		return pf.getProxy(dlbf.getBeanClassLoader());
	}
Copy the code

That’s all the property injection flow. It is very complicated, you can know the main process without paying too much attention to details:

  • AbstractAutowireCapableBeanFactory#applyMergedBeanDefinitionPostProcessorsLifecycle lookup @autowired meta information
  • Attribute assignment (populateBean) before beingAutowiredAnnotationBeanPostProcessor#postProcessProperties()Intercept and AutowiredFieldElement/AutowiredMethodElement injection
    • throughAutowireCapableBeanFactory#resolveDependencyParse the Bean object that gets injected depending on the property
      • Special Lazy loading processing for Optional/ObjectProvider/ @lazy etc
      • Find all beans by type and filter for generic types, qualifiers, and so on
      • Primary => priority => ResolvableDependencies => BeanName if the number of autowiredcandidates is >1, run primary => priority => ResolvableDependencies => BeanName
    • Use reflection for injection

XML constructor parameter injection/constructor injection

Both injection methods instantiate the Bean using the returned parameter constructor.

  1. The core logical location isAbstractAutowirCapableBeanFactory#createBeanInstance
	protected BeanWrapper createBeanInstance(String beanName, RootBeanDefinition mbd, @Nullable Object[] args) {
    // omit code irrelevant to the current analysis...
    / / 1. All the callback SmartInstantiationAwareBeanPostProcessor# determineCandidateConstructors () method to try to return to the constructor, Here we will explore AutowiredAnnotationBeanPostProcessor# determineCandidateConstructors ()Constructor<? >[] ctors = determineConstructorsFromBeanPostProcessors(beanClass, beanName);//2. Return true if the constructor returned by the callback is not empty, or if the BeanDefinition is 
       configured in XML
		if(ctors ! =null|| mbd.getResolvedAutowireMode() == AUTOWIRE_CONSTRUCTOR || mbd.hasConstructorArgumentValues() || ! ObjectUtils.isEmpty(args)) {//3. Perform automatic constructor injection
			return autowireConstructor(beanName, mbd, ctors, args);
		}
		//4. Use the default constructor to instantiate the Bean if no constructor is returned
		return instantiateBean(beanName, mbd);
	}
Copy the code
  1. parsingAutowiredAnnotationBeanPostProcessor#determineCandidateConstructors()How is the candidate constructor returned
	publicConstructor<? >[] determineCandidateConstructors(Class<? > beanClass,final String beanName)
			throws BeanCreationException {
		// omit lookup related...
		//1. Preferentially fetch from the candidate constructor cache
		// Quick check on the concurrent map first, with minimal locking.Constructor<? >[] candidateConstructors =this.candidateConstructorsCache.get(beanClass);
		if (candidateConstructors == null) {
			// Fully synchronized resolution now...
			synchronized (this.candidateConstructorsCache) {
				candidateConstructors = this.candidateConstructorsCache.get(beanClass);
				if (candidateConstructors == null) { Constructor<? >[] rawCandidates;try {
						//2. If null is present in the cache, all constructors of the BeanClass may be presentrawCandidates = beanClass.getDeclaredConstructors(); } List<Constructor<? >> candidates =newArrayList<>(rawCandidates.length); Constructor<? > requiredConstructor =null; Constructor<? > defaultConstructor =null;
					//3. The kotlin implementation is ignoredConstructor<? > primaryConstructor = BeanUtils.findPrimaryConstructor(beanClass);int nonSyntheticConstructors = 0;
					//4. Filter through all constructors
					for(Constructor<? > candidate : rawCandidates) {//4.1 Non-synthetic constructor
						if(! candidate.isSynthetic()) { nonSyntheticConstructors++; }else if(primaryConstructor ! =null) {
							continue;
						}
						//4.2 Get the @autowired meta-information on the constructorMergedAnnotation<? > ann = findAutowiredAnnotation(candidate);// If no attempt is made and the current BeanClass is a CGLIB proxy object, try to obtain the meta information of the proxied object
						if (ann == null) { Class<? > userClass = ClassUtils.getUserClass(beanClass);if(userClass ! = beanClass) {try{ Constructor<? > superCtor = userClass.getDeclaredConstructor(candidate.getParameterTypes()); ann = findAutowiredAnnotation(superCtor); }catch (NoSuchMethodException ex) {
									// Simply proceed, no equivalent superclass constructor found...}}}// There is Autowired meta information
						if(ann ! =null) {
							@autowired (require = true) {BeanCreationException = BeanCreationException = BeanCreationException = BeanCreationException
							if(requiredConstructor ! =null) {
								throw new BeanCreationException(beanName,
										"Invalid autowire-marked constructor: " + candidate +
										". Found constructor with 'required' Autowired annotation already: " +
										requiredConstructor);
							}
							//4.4 Get the require attribute value
							boolean required = determineRequiredStatus(ann);
							if (required) {
								If @autowired (require=false) {// if @autowired (require=false) {if @autowired (require=false);
								if(! candidates.isEmpty()) {throw new BeanCreationException(beanName,
											"Invalid autowire-marked constructors: " + candidates +
											". Found constructor with 'required' Autowired annotation: " +
											candidate);
								}
								requiredConstructor = candidate;
							}
							candidates.add(candidate);
						}
						// Sets the default construction parameters
						else if (candidate.getParameterCount() == 0) { defaultConstructor = candidate; }}if(! candidates.isEmpty()) {//5 If there is no constructor @autowired (required=true)
						if (requiredConstructor == null) {
							// If the default constructor is not null, it is added to the candidate constructor as a fallback
							if(defaultConstructor ! =null) {
								candidates.add(defaultConstructor);
							}
							else if (candidates.size() == 1 && logger.isInfoEnabled()) {
								logger.info("Inconsistent constructor declaration on bean with name '" + beanName +
										"': single autowire-marked constructor flagged as optional - " +
										"this constructor is effectively required since there is no " +
										"default constructor to fall back to: " + candidates.get(0)); }}//5.1 Return candidate beans as arrays (at this point there may be only one @autowired (required=true) or one or more @Autowired(required=false) constructors)
						candidateConstructors = candidates.toArray(newConstructor<? > [0]);
					}
					//6. If there is no constructor for the @autoWired tag and the current BeanClass has only one non-default constructor, return
					else if (rawCandidates.length == 1 && rawCandidates[0].getParameterCount() > 0) {
						candidateConstructors = newConstructor<? >[] {rawCandidates[0]};
					}
					// Kotlin related skip
					else if (nonSyntheticConstructors == 2&& primaryConstructor ! =null&& defaultConstructor ! =null && !primaryConstructor.equals(defaultConstructor)) {
						candidateConstructors = newConstructor<? >[] {primaryConstructor, defaultConstructor}; }else if (nonSyntheticConstructors == 1&& primaryConstructor ! =null) {
						candidateConstructors = newConstructor<? >[] {primaryConstructor}; }else {
						//7. Return empty constructor
						candidateConstructors = newConstructor<? > [0];
					}
					//8. Set the parsed constructor to the cache
					this.candidateConstructorsCache.put(beanClass, candidateConstructors); }}}return (candidateConstructors.length > 0 ? candidateConstructors : null);
	}
Copy the code

The core logic and flow are as follows

  • Check whether a parsed constructor for the current BeanClass exists in the cache, and return if it does
  • To obtainBeanClassFor all constructors, traverse the constructors that meet the requirements as follows:
    • There is only one@Autowired(required=true)The constructor and others are not marked@AutowiredThe constructor
    • There is one or more@Autowired(required=false)The constructor
    • There is only one parameter constructor
  • Set to cache and return
  1. Enter theautowireConstructor()Do constructor injection
// Perform automatic constructor injection
protected BeanWrapper autowireConstructor(
			String beanName, RootBeanDefinition mbd, @NullableConstructor<? >[] ctors,@Nullable Object[] explicitArgs) {
		return new ConstructorResolver(this).autowireConstructor(beanName, mbd, ctors, explicitArgs);
	}
Copy the code

AutowireConstructor () ¶

public BeanWrapper autowireConstructor(String beanName, RootBeanDefinition mbd,
			@NullableConstructor<? >[] chosenCtors,@Nullable Object[] explicitArgs) {
		//1. Initialize BeanWrapper to set type conversion correlation
		BeanWrapperImpl bw = new BeanWrapperImpl();
		this.beanFactory.initBeanWrapper(bw); Constructor<? > constructorToUse =null;
		ArgumentsHolder argsHolderToUse = null;
		Object[] argsToUse = null;
		//2. Cache processing
		if(explicitArgs ! =null) {
			argsToUse = explicitArgs;
		}
		else {
			Object[] argsToResolve = null;
			synchronized(mbd.constructorArgumentLock) { constructorToUse = (Constructor<? >) mbd.resolvedConstructorOrFactoryMethod;if(constructorToUse ! =null && mbd.constructorArgumentsResolved) {
					// Found a cached constructor...
					argsToUse = mbd.resolvedConstructorArguments;
					if (argsToUse == null) { argsToResolve = mbd.preparedConstructorArguments; }}}if(argsToResolve ! =null) {
				argsToUse = resolvePreparedArguments(beanName, mbd, bw, constructorToUse, argsToResolve, true); }}//3. Constructor selection, if none, get all constructors of BeanClass
		if (constructorToUse == null || argsToUse == null) {
			// Take specified constructors, if any.Constructor<? >[] candidates = chosenCtors;if (candidates == null) { Class<? > beanClass = mbd.getBeanClass();try {
					candidates = (mbd.isNonPublicAccessAllowed() ?
							beanClass.getDeclaredConstructors() : beanClass.getConstructors());
				}
				catch (Throwable ex) {
					throw new BeanCreationException(mbd.getResourceDescription(), beanName,
							"Resolution of declared constructors on bean Class [" + beanClass.getName() +
							"] from ClassLoader [" + beanClass.getClassLoader() + "] failed", ex); }}//3.1 If there is only one constructor and BeanDefinition has no constructor parameters configured
			if (candidates.length == 1 && explicitArgs == null&&! mbd.hasConstructorArgumentValues()) { Constructor<? > uniqueCandidate = candidates[0];
				//3.2 If the default constructor is used, the cache parameters are set directly and then reflected to instantiate and set into BeanWrapper
				if (uniqueCandidate.getParameterCount() == 0) {
					synchronized (mbd.constructorArgumentLock) {
						mbd.resolvedConstructorOrFactoryMethod = uniqueCandidate;
						mbd.constructorArgumentsResolved = true;
						mbd.resolvedConstructorArguments = EMPTY_ARGS;
					}
					bw.setBeanInstance(instantiate(beanName, mbd, uniqueCandidate, EMPTY_ARGS));
					returnbw; }}//3.3 Autowiring is true if the constructor passed in is not null
			// Need to resolve the constructor.
			booleanautowiring = (chosenCtors ! =null ||
					mbd.getResolvedAutowireMode() == AutowireCapableBeanFactory.AUTOWIRE_CONSTRUCTOR);
			ConstructorArgumentValues resolvedValues = null;

			int minNrOfArgs;
			if(explicitArgs ! =null) {
				minNrOfArgs = explicitArgs.length;
			}
			else {
				//3.4 If there are constructor arguments, evaluate and return the minimum constructor argument
				ConstructorArgumentValues cargs = mbd.getConstructorArgumentValues();
				resolvedValues = new ConstructorArgumentValues();
				// The dependency lookup is done and the construct parameters are parsed
				minNrOfArgs = resolveConstructorArguments(beanName, mbd, bw, cargs, resolvedValues);
			}
			//3.5 Sort all candidate constructors public first, then the one with more arguments first
			AutowireUtils.sortConstructors(candidates);
			int minTypeDiffWeight = Integer.MAX_VALUE; // Default minimum type difference weightSet<Constructor<? >> ambiguousConstructors =null; Construct A(String A,Integer b) Construct B(Integer A, String b
			Deque<UnsatisfiedDependencyException> causes = null; // Exception record
			//4. Iterate over all candidate constructors
			for(Constructor<? > candidate : candidates) {int parameterCount = candidate.getParameterCount(); // Number of constructor arguments
				//4.1 If there are already candidate constructors, then the number of iterated constructors and parameters is compared. If there are already candidate constructors, then the number of iterated constructors and parameters can be directly returned.
				if(constructorToUse ! =null&& argsToUse ! =null && argsToUse.length > parameterCount) {
					// Already found greedy constructor that can be satisfied ->
					// do not look any further, there are only less greedy constructors left.
					break;
				}
				
       
				if (parameterCount < minNrOfArgs) {
					continue; } ArgumentsHolder argsHolder; Class<? >[] paramTypes = candidate.getParameterTypes();if(resolvedValues ! =null) {
					try {
						String[] paramNames = ConstructorPropertiesChecker.evaluate(candidate, parameterCount);
						if (paramNames == null) {
							ParameterNameDiscoverer pnd = this.beanFactory.getParameterNameDiscoverer();
							if(pnd ! =null) { paramNames = pnd.getParameterNames(candidate); }}//4.3 Construct attributes for dependency lookup
						argsHolder = createArgumentArray(beanName, mbd, resolvedValues, bw, paramTypes, paramNames,
								getUserDeclaredConstructor(candidate), autowiring, candidates.length == 1);
					}
					catch (UnsatisfiedDependencyException ex) {
						if (logger.isTraceEnabled()) {
							logger.trace("Ignoring constructor [" + candidate + "] of bean '" + beanName + "'." + ex);
						}
						// Swallow and try next constructor.
						if (causes == null) {
							causes = new ArrayDeque<>(1);
						}
						causes.add(ex);
						continue; }}else {
					// Explicit arguments given -> arguments length must match exactly.
					if(parameterCount ! = explicitArgs.length) {continue;
					}
					argsHolder = new ArgumentsHolder(explicitArgs);
				}
				//5. Return a differential value based on the parameter type
				int typeDiffWeight = (mbd.isLenientConstructorResolution() ?
						argsHolder.getTypeDifferenceWeight(paramTypes) : argsHolder.getAssignabilityWeight(paramTypes));
				// Choose this constructor if it represents the closest match.
				//5.1 If less than the minimum weight, set the constructor property
				if (typeDiffWeight < minTypeDiffWeight) {
					constructorToUse = candidate;
					argsHolderToUse = argsHolder;
					argsToUse = argsHolder.arguments;
					minTypeDiffWeight = typeDiffWeight;
					ambiguousConstructors = null;
				}
				// If any parameters are the same, ambiguousConstructors should be ambiguousConstructors
				else if(constructorToUse ! =null && typeDiffWeight == minTypeDiffWeight) {
					if (ambiguousConstructors == null) {
						ambiguousConstructors = newLinkedHashSet<>(); ambiguousConstructors.add(constructorToUse); } ambiguousConstructors.add(candidate); }}if (constructorToUse == null) {
				if(causes ! =null) {
					UnsatisfiedDependencyException ex = causes.removeLast();
					for (Exception cause : causes) {
						this.beanFactory.onSuppressedException(cause);
					}
					throw ex;
				}
				throw new BeanCreationException(mbd.getResourceDescription(), beanName,
						"Could not resolve matching constructor " +
						"(hint: specify index/type/name arguments for simple parameters to avoid type ambiguities)");
			}
			// Having a constructor of the same type but in a different position and in a non-loose-checking mode throws an exception
			else if(ambiguousConstructors ! =null && !mbd.isLenientConstructorResolution()) {
				throw new BeanCreationException(mbd.getResourceDescription(), beanName,
						"Ambiguous constructor matches found in bean '" + beanName + "'" +
						"(hint: specify index/type/name arguments for simple parameters to avoid type ambiguities): " +
						ambiguousConstructors);
			}

			if (explicitArgs == null&& argsHolderToUse ! =null) { argsHolderToUse.storeCache(mbd, constructorToUse); }}// Finally use the candidate constructor reflection to instantiate the object and set it into BeanWrapperAssert.state(argsToUse ! =null."Unresolved constructor arguments");
		bw.setBeanInstance(instantiate(beanName, mbd, constructorToUse, argsToUse));
		return bw;
	}
Copy the code

Conclusion:

  • If the constructor arguments have already been parsed, the cache is hit and the matching constructor is returned directly
  • Start parsing all candidate constructors
    • If there is only one default constructor, it returns directly
    • If there are constructor arguments(<construct-args>), parses the constructor parameter attribute value and passesBeanDefinitionValueResolver#resolveValueIfNecessary()Depends on the lookup constructor parameter value
    • Sort candidate constructors (public first, number of arguments first)
    • Iterate through the ordered constructor to find the number of argumentsParameterCount> =<construct-args> Number of parameters.And the constructor with the most property parameters is returned. There is an interesting looser check mechanism, namely againstconstruct A(String a,Integer b)construct B(Integer a,String b)If these two properties are in the same position, they will be added toSet<Constructor<? >> ambiguousConstructorsIs returned in the order defined by the constructors in the Bean
    • Finally usingInstantiationStrategy#instantiate()Method for reflection injection

Factory method instantiation / @bean instantiation

And the constructor injection pattern are all the same, is to change the constructor to specific factory method, detailed you can refer to ConstructorResolver# instantiateUsingFactoryMethod () method