AutowiredAnnotationBeanPostProcessor is Spring’s rear processor, handle the @autowired and @ Value annotation.

I. Trigger mode

  • The Spring container after each Bean instantiation, call AutowiredAnnotationBeanPostProcessorpostProcessMergedBeanDefinitionMethod to find if the Bean has an @autoWired annotation.
  • Spring calls each Bean instantiation timepopulateBeanIs called when a property injection is performedpostProcessPropertyValuesMethod to find if the Bean has an @autoWired annotation.

Constructors

public AutowiredAnnotationBeanPostProcessor(a) {
	// The post-processor will handle the @autowire annotation
	this.autowiredAnnotationTypes.add(Autowired.class);
	// The post-processor will handle the @value annotation
	this.autowiredAnnotationTypes.add(Value.class);
	try {
		// The post-processor will handle the javax.inject.Inject JSR-330 annotation
		this.autowiredAnnotationTypes.add((Class<? extends Annotation>)
				ClassUtils.forName("javax.inject.Inject", AutowiredAnnotationBeanPostProcessor.class.getClassLoader()));
		logger.info("JSR-330 'javax.inject.Inject' annotation found and supported for autowiring");
	}
	catch (ClassNotFoundException ex) {
		// JSR-330 API not available - simply skip.}}Copy the code

Three, injection method

        // Handle attributes in the class, attribute injection
	@Override
	public PropertyValues postProcessPropertyValues( PropertyValues pvs, PropertyDescriptor[] pds, Object bean, String beanName) throws BeanCreationException {

	// Get meta information about the annotations associated with autowire in the specified class
<1>	InjectionMetadata metadata = findAutowiringMetadata(beanName, bean.getClass(), pvs);
	try {
		// Automatically inject the Bean's properties
<2>		metadata.inject(bean, beanName, pvs);
	}
	catch (BeanCreationException ex) {
		throw ex;
	}
	catch (Throwable ex) {
		throw new BeanCreationException(beanName, "Injection of autowired dependencies failed", ex);
	}
	return pvs;
	}
Copy the code

This method is attributes inject populateBean invokes the PVS = ibp. PostProcessPropertyValues (PVS, filteredPds, bw. GetWrappedInstance (), beanName); One of the concrete implementations of.

< 1 > the code from the bean, obtaining the corresponding annotation information is AutowiredAnnotationBeanPostProcessor here add @ the Value, the @autowired annotation fields, The related information is then encapsulated in InjectionMetadata. The code is as follows:

// Get the autowire meta-information for the given class
	private InjectionMetadata findAutowiringMetadata(String beanName, Class
        clazz, @Nullable PropertyValues pvs) {
	// Fall back to class name as cache key, for backwards compatibility with custom callers.
	String cacheKey = (StringUtils.hasLength(beanName) ? beanName : clazz.getName());
	// Quick check on the concurrent map first, with minimal locking.
	// First look up 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) {
					// Parsing the given class autowire focuses on solution meta information
					metadata.clear(pvs);
				}
				// Parsing the given class autowire focuses on solution meta information
				metadata = buildAutowiringMetadata(clazz);
				// Store the resulting solution meta-information for the given class Autowire in the container cache
				this.injectionMetadataCache.put(cacheKey, metadata); }}}return metadata;
	}
Copy the code

BuildAutowiringMetadata:

// Parsing the given class autowire focuses on solution meta information
	private InjectionMetadata buildAutowiringMetadata(finalClass<? > clazz) {
	// Create a collection of annotations meta information
	LinkedList<InjectionMetadata.InjectedElement> elements = newLinkedList<>(); Class<? > targetClass = clazz;// Recursively iterates through the current class and all its base classes, parsing all annotation meta-information
	do {
		// Create a collection that stores meta information about the currently being processed class annotations
		final LinkedList<InjectionMetadata.InjectedElement> currElements = new LinkedList<>();

		// Use JDK reflection to get all declaration fields of a given class, and get the annotation information on the fields
		ReflectionUtils.doWithLocalFields(targetClass, field -> {
			// Get the annotation on the given field
			AnnotationAttributes ann = findAutowiredAnnotation(field);
			if(ann ! =null) {
				// If a given field is static, the next field is iterated directly
				if (Modifier.isStatic(field.getModifiers())) {
					if (logger.isWarnEnabled()) {
						logger.warn("Autowired annotation is not supported on static fields: " + field);
					}
					return;
				}
				// Determine whether the annotation's required attribute value is valid
				boolean required = determineRequiredStatus(ann);
				// Encapsulate the current field meta information and add it to the returned collection
				currElements.add(newAutowiredFieldElement(field, required)); }});// Use JDK reflection to get all declared methods in a given class
		ReflectionUtils.doWithLocalMethods(targetClass, method -> {
			Method bridgedMethod = BridgeMethodResolver.findBridgedMethod(method);
			if(! BridgeMethodResolver.isVisibilityBridgeMethodPair(method, bridgedMethod)) {return;
			}
			// Get all annotations on the given method
			AnnotationAttributes ann = findAutowiredAnnotation(bridgedMethod);
			if(ann ! =null && method.equals(ClassUtils.getMostSpecificMethod(method, clazz))) {
				// If the method is static, the next method is iterated directly
				if (Modifier.isStatic(method.getModifiers())) {
					if (logger.isWarnEnabled()) {
						logger.warn("Autowired annotation is not supported on static methods: " + method);
					}
					return;
				}
				// If the method argument list is empty
				if (method.getParameterCount() == 0) {
					if (logger.isWarnEnabled()) {
						logger.warn("Autowired annotation should only be used on methods with parameters: "+ method); }}// Determine whether the annotation's required attribute value is valid
				boolean required = determineRequiredStatus(ann);
				// Gets a property descriptor for the current method, that is, whether the method is a readable getter or writeable setter
				PropertyDescriptor pd = BeanUtils.findPropertyForMethod(bridgedMethod, clazz);
				// Add method meta-information encapsulation to the returned meta-information set
				currElements.add(newAutowiredMethodElement(method, required, pd)); }});// Store the annotation meta-information of the current class in the annotation meta-information collection
		elements.addAll(0, currElements);
		// Get the parent of the given class
		targetClass = targetClass.getSuperclass();
	}
	// If a given class has a base class, and the base class is not Object, then the meta information of its base class is recursively obtained
	while(targetClass ! =null&& targetClass ! = Object.class);return new InjectionMetadata(clazz, elements);
	}
Copy the code

The code is clearly commented, and at this point you get meta information about the annotations associated with autowire in the specified class. Ps: You can see that the @autowired annotation does not support static decorations

Then we look at postProcessPropertyValues method < 2 > specific injection logic:

//InjectionMetadata.java

public void inject(Object target, @Nullable String beanName, @Nullable PropertyValues pvs) throws Throwable {
	Collection<InjectedElement> checkedElements = this.checkedElements;
	// Set of fields to be injectedCollection<InjectedElement> elementsToIterate = (checkedElements ! =null ? checkedElements : this.injectedElements);
	if(! elementsToIterate.isEmpty()) {boolean debug = logger.isDebugEnabled();
		// Iterate over each field injection
		for (InjectedElement element : elementsToIterate) {
			if (debug) {
				logger.debug("Processing injected element of bean '" + beanName + "'."+ element); } element.inject(target, beanName, pvs); }}}Copy the code

Here is not the actual injection method, we continue to trace element.inject(target, beanName, PVS);

//InjectionMetadata.java

protected void inject(Object target, @Nullable String requestingBeanName, @Nullable PropertyValues pvs)
		throws Throwable {

	if (this.isField) {
		Field field = (Field) this.member;
		ReflectionUtils.makeAccessible(field);
		field.set(target, getResourceToInject(target, requestingBeanName));
	}
	else {
		if (checkPropertySkipping(pvs)) {
			return;
		}
		try {
			Method method = (Method) this.member;
			ReflectionUtils.makeAccessible(method);
			method.invoke(target, getResourceToInject(target, requestingBeanName));
		}
		catch (InvocationTargetException ex) {
			throwex.getTargetException(); }}}Copy the code

This is the original method of element.inject(), which also has two methods that subclasses implement themselves, as shown:

AutowiredAnnotationBeanPostProcessor

3.1. Field injection

Let’s look at field injection first:

//AutowiredAnnotationBeanPostProcessor.java

	@Override
	protected void inject(Object bean, @Nullable String beanName, @Nullable PropertyValues pvs) throws Throwable {
		// Get the field to be injected
		Field field = (Field) this.member;
		Object value;
		// If the value of the field is cached
		if (this.cached) {
			// Get the field value from the cache
			value = resolvedCachedArgument(beanName, this.cachedFieldValue);
		}
		// No cache
		else {
			// Create a field dependency descriptor
			DependencyDescriptor desc = new DependencyDescriptor(field, this.required);
			desc.setContainingClass(bean.getClass());
			Set<String> autowiredBeanNames = new LinkedHashSet<>(1); Assert.state(beanFactory ! =null."No BeanFactory available");
			// Get the type converter in the container
			TypeConverter typeConverter = beanFactory.getTypeConverter();
			try {
				/ / core! Gets the injected value
				value = beanFactory.resolveDependency(desc, beanName, autowiredBeanNames, typeConverter);
			}
			catch (BeansException ex) {
				throw new UnsatisfiedDependencyException(null, beanName, new InjectionPoint(field), ex);
			}
			// Thread synchronization to ensure data consistency in the container
			synchronized (this) {
				// If the field value is not cached
				if (!this.cached) {
					// The field value is not null and the required attribute is true
					if(value ! =null || this.required) {
						this.cachedFieldValue = desc;
						// Register the dependent Bean for the specified Bean
						registerDependentBeans(beanName, autowiredBeanNames);
						if (autowiredBeanNames.size() == 1) {
							String autowiredBeanName = autowiredBeanNames.iterator().next();
							// If the container has a Bean object with the specified name
							if (beanFactory.containsBean(autowiredBeanName)) {
								// The dependent object type matches the field type and is injected by type by default
								if (beanFactory.isTypeMatch(autowiredBeanName, field.getType())) {
									// Create a reference to the dependent object and cache it
									this.cachedFieldValue = newShortcutDependencyDescriptor( desc, autowiredBeanName, field.getType()); }}}}// If the dependency is null and the required attribute is false
					else {
						// Set the cache of field values to NULL
						this.cachedFieldValue = null;
					}
					// The container already caches the value of the current field
					this.cached = true; }}}// If the field value is not null
		if(value ! =null) {
			// Explicitly use JDK reflection to set automatic access control permissions to allow access
			ReflectionUtils.makeAccessible(field);
			// Assign a value to the fieldfield.set(bean, value); }}Copy the code

This code is easy to understand, getting the Value to be injected from the @Value/ @autoWired annotation and then using reflection set to the field. Extracted from the key is how the annotation to the value of the injection, we come to the core code value = the beanFactory. ResolveDependency (desc, beanName autowiredBeanNames, typeConverter);

//DefaultListableBeanFactory.java

public Object resolveDependency(DependencyDescriptor descriptor, @Nullable String requestingBeanName, @Nullable Set
       
         autowiredBeanNames, @Nullable TypeConverter typeConverter)
        throws BeansException {

	descriptor.initParameterNameDiscovery(getParameterNameDiscoverer());
	if (Optional.class == descriptor.getDependencyType()) {
		return createOptionalDependency(descriptor, requestingBeanName);
	}
	else if (ObjectFactory.class == descriptor.getDependencyType() ||
			ObjectProvider.class == descriptor.getDependencyType()) {
		return new DependencyObjectProvider(descriptor, requestingBeanName);
	}
	else if (javaxInjectProviderClass == descriptor.getDependencyType()) {
		return new Jsr330ProviderFactory().createDependencyProvider(descriptor, requestingBeanName);
	}
	else {
		Object result = getAutowireCandidateResolver().getLazyResolutionProxyIfNecessary(
				descriptor, requestingBeanName);
		if (result == null) {
			// The code that actually gets the value
			result = doResolveDependency(descriptor, requestingBeanName, autowiredBeanNames, typeConverter);
		}
		returnresult; }}Copy the code

To track:

//DefaultListableBeanFactory.java

public Object doResolveDependency(DependencyDescriptor descriptor, @Nullable String beanName, @Nullable Set
       
         autowiredBeanNames, @Nullable TypeConverter typeConverter)
        throws BeansException {
        / / injection points
	InjectionPoint previousInjectionPoint = ConstructorResolver.setCurrentInjectionPoint(descriptor);
	try {
		// Give a shortcut implementation for a given factory, e.g. consider some pre-parsed information
		// The parsing algorithm will first attempt to parse the shortcut through this method before entering the normal type-matching algorithm for all beans.
		// Subclasses can override this method
		Object shortcut = descriptor.resolveShortcut(this);
		if(shortcut ! =null) {
			return shortcut;
		}

		// Get the type of the field attributeClass<? > type = descriptor.getDependencyType();// Get the Value in @value
		Object value = getAutowireCandidateResolver().getSuggestedValue(descriptor);
		if(value ! =null) {
			if (value instanceofString) { String strVal = resolveEmbeddedValue((String) value); BeanDefinition bd = (beanName ! =null && containsBean(beanName) ? getMergedBeanDefinition(beanName) : null); value = evaluateBeanDefinitionString(strVal, bd); } TypeConverter converter = (typeConverter ! =null ? typeConverter : getTypeConverter());
			return(descriptor.getField() ! =null ?
					converter.convertIfNecessary(value, type, descriptor.getField()) :
					converter.convertIfNecessary(value, type, descriptor.getMethodParameter()));
		}

		// If the attribute that identifies the @autoWired annotation is a compound type, such as Array,Collection,Map,
		// Get the value in @autowired from this method
<1>		Object multipleBeans = resolveMultipleBeans(descriptor, beanName, autowiredBeanNames, typeConverter);
		if(multipleBeans ! =null) {
			return multipleBeans;
		}

		// If the attribute that identifies the @autoWired annotation is non-compound,
		// Get the value in @autowired from this method
<2>		Map<String, Object> matchingBeans = findAutowireCandidates(beanName, type, descriptor);
		// If there is no Bean that matches this type
		if (matchingBeans.isEmpty()) {
			// Check if @autowire require is true
			if (isRequired(descriptor)) {
				// Throw an exception
				raiseNoMatchingBeanFound(type, descriptor.getResolvableType(), descriptor);
			}
			return null;
		}

		String autowiredBeanName;
		Object instanceCandidate;

		// If there are multiple beans of this type
		if (matchingBeans.size() > 1) {
			// Pick the best solution
<3>			autowiredBeanName = determineAutowireCandidate(matchingBeans, descriptor);
			if (autowiredBeanName == null) {
				if(isRequired(descriptor) || ! indicatesMultipleBeans(type)) {// Throw an exception
					return descriptor.resolveNotUnique(type, matchingBeans);
				}
				else {
					// In case of an optional Collection/Map, silently ignore a non-unique case:
					// possibly it was meant to be an empty collection of multiple regular beans
					(before 4.3 in particular when we didn't even look for collection beans)
					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);
		}
		if (instanceCandidate instanceof Class) {
			instanceCandidate = descriptor.resolveCandidate(autowiredBeanName, type, this);
		}
		Object result = instanceCandidate;
		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

This code looks long, but it’s really easy to understand. The general process is to get a matching Bean from the IOC container based on the field type and, if there are more than one, pick the best one.

Now let’s look at the logic.

3.1.1, <1> : @autoWired injects an array of collections, such as map.list

Let’s take a look at @AutoWired’s logic for injecting an array of collections:

//DefaultListableBeanFactory.java

private Object resolveMultipleBeans(DependencyDescriptor descriptor, @Nullable String beanName, @Nullable Set
       
         autowiredBeanNames, @Nullable TypeConverter typeConverter)
        { Class<? > type = descriptor.getDependencyType();// If @autoWired identifies an attribute of array type
	if (type.isArray()) {
		// Get the content type of the arrayClass<? > componentType = type.getComponentType(); ResolvableType resolvableType = descriptor.getResolvableType(); Class<? > resolvedArrayType = resolvableType.resolve();if(resolvedArrayType ! =null&& resolvedArrayType ! = type) { type = resolvedArrayType; componentType = resolvableType.getComponentType().resolve(); }if (componentType == null) {
			return null;
		}
		// This method is used to select matching beans from the IOC container by type
		Map<String, Object> matchingBeans = findAutowireCandidates(beanName, componentType,
				new MultiElementDescriptor(descriptor));
		if (matchingBeans.isEmpty()) {
			return null;
		}
		if(autowiredBeanNames ! =null) { autowiredBeanNames.addAll(matchingBeans.keySet()); } TypeConverter converter = (typeConverter ! =null ? typeConverter : getTypeConverter());
		// Convert the resulting Bean candidates to property types, e.g. from set to Array,List, etc
		Object result = converter.convertIfNecessary(matchingBeans.values(), type);
		if(getDependencyComparator() ! =null && result instanceof Object[]) {
			Arrays.sort((Object[]) result, adaptDependencyComparator(matchingBeans));
		}
		return result;
	}
	else if (Collection.class.isAssignableFrom(type) && type.isInterface()) {
		// Get the generics for CollectionClass<? > elementType = descriptor.getResolvableType().asCollection().resolveGeneric();if (elementType == null) {
			return null;
		}
		Map<String, Object> matchingBeans = findAutowireCandidates(beanName, elementType,
				new MultiElementDescriptor(descriptor));
		if (matchingBeans.isEmpty()) {
			return null;
		}
		if(autowiredBeanNames ! =null) { autowiredBeanNames.addAll(matchingBeans.keySet()); } TypeConverter converter = (typeConverter ! =null ? typeConverter : getTypeConverter());
		Object result = converter.convertIfNecessary(matchingBeans.values(), type);
		if(getDependencyComparator() ! =null && result instanceofList) { Collections.sort((List<? >) result, adaptDependencyComparator(matchingBeans)); }return result;
	}
	else if(Map.class == type) { ResolvableType mapType = descriptor.getResolvableType().asMap(); Class<? > keyType = mapType.resolveGeneric(0);
		if(String.class ! = keyType) {return null; } Class<? > valueType = mapType.resolveGeneric(1);
		if (valueType == null) {
			return null;
		}
		Map<String, Object> matchingBeans = findAutowireCandidates(beanName, valueType,
				new MultiElementDescriptor(descriptor));
		if (matchingBeans.isEmpty()) {
			return null;
		}
		if(autowiredBeanNames ! =null) {
			autowiredBeanNames.addAll(matchingBeans.keySet());
		}
		return matchingBeans;
	}
	else {
		return null; }}Copy the code

3.1.2, <2> : @AutoWired injects non-collection arrays, i.e. ordinary classes such as Service

//DefaultListableBeanFactory.java

protected Map<String, Object> findAutowireCandidates( @Nullable String beanName, Class
        requiredType, DependencyDescriptor descriptor) {

	// Get all the BeanName matching types from the IOC container and store them in the candidate array
	String[] candidateNames = BeanFactoryUtils.beanNamesForTypeIncludingAncestors(
			this, requiredType, true, descriptor.isEager());
	Map<String, Object> result = new LinkedHashMap<>(candidateNames.length);
	// The Spring container registers many Bean dependencies.
	// When a consumer wants to inject a Bean of the specified type, it will first look for matches from registered dependencies
	for(Class<? > autowiringType :this.resolvableDependencies.keySet()) {
		if (autowiringType.isAssignableFrom(requiredType)) {
			Object autowiringValue = this.resolvableDependencies.get(autowiringType);
			autowiringValue = AutowireUtils.resolveAutowiringValue(autowiringValue, requiredType);
			// If the registered dependent Bean type is an instance of the specified type or its parent class, interface, then it is used as a candidate. The registered dependent Bean type is not repeated
			if (requiredType.isInstance(autowiringValue)) {
				result.put(ObjectUtils.identityToString(autowiringValue), autowiringValue);
				break; }}}// Iterate over the candidate array
	for (String candidate : candidateNames) {
		// The candidate Bean is not self-referential (i.e. the class to be injected cannot be the class itself, triggering infinite recursive injection)
		if (!isSelfReference(beanName, candidate) && isAutowireCandidate(candidate, descriptor)) {
			addCandidateEntry(result, candidate, descriptor, requiredType);
		}
	}
	if(result.isEmpty() && ! indicatesMultipleBeans(requiredType)) {// Consider fallback matches if the first pass failed to find anything...
		DependencyDescriptor fallbackDescriptor = descriptor.forFallbackMatch();
		for (String candidate : candidateNames) {
			if (!isSelfReference(beanName, candidate) && isAutowireCandidate(candidate, fallbackDescriptor)) {
				addCandidateEntry(result, candidate, descriptor, requiredType);
			}
		}
		if (result.isEmpty()) {
			// Consider self references as a final pass...
			// but in the case of a dependency collection, not the very same bean itself.
			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

With this code comment clearly written, let’s move on to the addCandidateEntry method, which puts the Bean instance into the collection of candidates

//DefaultListableBeanFactory.java

private void addCandidateEntry(Map
       
         candidates, String candidateName, DependencyDescriptor descriptor, Class
         requiredType)
       ,> {

	// When @autoWired is a container type attribute, the dependency descriptor type is MultiElementDescriptor,
	// Therefore all candidates are qualified, so they are instantiated on the spot. If the property is of a non-container type, it may be one of several candidates,
	// It is not appropriate to instantiate all of them. The qualified one will be instantiated eventually. If there is no qualified one, it will not be instantiated.
	// Early instantiation affects many aspects of beans, such as AOP, EarlyReference, etc. */
	if (descriptor instanceof MultiElementDescriptor || containsSingleton(candidateName)) {
		Object beanInstance = descriptor.resolveCandidate(candidateName, requiredType, this);
		candidates.put(candidateName, (beanInstance instanceof NullBean ? null : beanInstance));
	}
	else{ candidates.put(candidateName, getType(candidateName)); }}Copy the code

The doGetBean() method is called to instantiate the Bean

<3> : The optimal solution is selected from multiple candidates

If according to the type of Bean have more than one from the IOC container, you will need to call determineAutowireCandidate (matchingBeans, descriptor) method, to pick out the optimal solution. Code:

//DefaultListableBeanFactory.java

protected String determineAutowireCandidate(Map<String, Object> candidates, DependencyDescriptor descriptor) { Class<? > requiredType = descriptor.getDependencyType();// Select the best solution according to the @primary annotation
	String primaryCandidate = determinePrimaryCandidate(candidates, requiredType);
	if(primaryCandidate ! =null) {
		return primaryCandidate;
	}
	// Select the best solution according to @order, @priorityOrder, and the serial number of the interface that implements Order
	String priorityCandidate = determineHighestPriorityCandidate(candidates, requiredType);
	if(priorityCandidate ! =null) {
		return priorityCandidate;
	}
	// Fallback
	for (Map.Entry<String, Object> entry : candidates.entrySet()) {
		String candidateName = entry.getKey();
		Object beanInstance = entry.getValue();
		// If the optimal solution cannot be selected through the above two steps, the most basic strategy is used
		// First, if the type has already been registered by Spring, use the registered object directly.
		// The collection of candidates is a LinkedHashMap, an ordered Map collection, where the container registers dependencies at the start of the LinkedHashMap
		// If this type of dependency is not registered, the attribute name will be matched, and
		// If the attribute name is the same as the Bean name or alias of a candidate, then that Bean is directly used as the optimal solution
		if((beanInstance ! =null && this.resolvableDependencies.containsValue(beanInstance)) ||
				matchesBeanName(candidateName, descriptor.getDependencyName())) {
			returncandidateName; }}return null;
	}
Copy the code

This part of the logic is relatively simple, summed up in 3 steps:

  • Choose the best solution according to the @primary annotation
  • Select the optimal solution according to @order, @priorityOrder, and the serial number of the interface that implements Order
  • According to Spring default rules

Let’s go through these steps one by one, starting with the first: select the best solution according to the @primary annotation

//DefaultListableBeanFactory.java

protected String determinePrimaryCandidate(Map
       
         candidates, Class
         requiredType)
       ,> {
	String primaryBeanName = null;
	for (Map.Entry<String, Object> entry : candidates.entrySet()) {
		String candidateBeanName = entry.getKey();
		Object beanInstance = entry.getValue();
		// The candidate can be a Bean in the parent container that identifies @primary, or it can be a Bean in the current container. The SpringMVC container has the Spring container as its parent
		if (isPrimary(candidateBeanName, beanInstance)) {
			if(primaryBeanName ! =null) {
				boolean candidateLocal = containsBeanDefinition(candidateBeanName);
				boolean primaryLocal = containsBeanDefinition(primaryBeanName);
				// Ensure that at most one Bean of the same type in the same container identifies @primary
				if (candidateLocal && primaryLocal) {
					throw new NoUniqueBeanDefinitionException(requiredType, candidates.size(),
							"more than one 'primary' bean found among candidates: " + candidates.keySet());
				}
				// If the previous @primary Bean belongs to the parent container, the previous @primary Bean is overwritten with the candidate of the current container
				else if(candidateLocal) { primaryBeanName = candidateBeanName; }}else{ primaryBeanName = candidateBeanName; }}}return primaryBeanName;
	}
Copy the code

And then the second one: according to @order, @priorityOrder

//DefaultListableBeanFactory.java

protected String determineHighestPriorityCandidate(Map
       
         candidates, Class
         requiredType)
       ,> {
	String highestPriorityBeanName = null;
	Integer highestPriority = null;
	for (Map.Entry<String, Object> entry : candidates.entrySet()) {
		String candidateBeanName = entry.getKey();
		Object beanInstance = entry.getValue();
		Integer candidatePriority = getPriority(beanInstance);
		if(candidatePriority ! =null) {
			// The sequence number with the highest priority cannot exist at the same time
			if(highestPriorityBeanName ! =null) {
				if (candidatePriority.equals(highestPriority)) {
					throw new NoUniqueBeanDefinitionException(requiredType, candidates.size(),
							"Multiple beans found with the same priority ('" + highestPriority +
							"') among candidates: " + candidates.keySet());
				}
				// Use the Bean with the lowest priority number as the optimal solution
				else if(candidatePriority < highestPriority) { highestPriorityBeanName = candidateBeanName; highestPriority = candidatePriority; }}else{ highestPriorityBeanName = candidateBeanName; highestPriority = candidatePriority; }}}return highestPriorityBeanName;
	}
Copy the code

Summary: At this point, the source code for @Autowired field injection is analyzed.

Let’s look at method injection:

3.2. Method injection

//DefaultListableBeanFactory.java

protected void inject(Object bean, @Nullable String beanName, @Nullable PropertyValues pvs) throws Throwable {
	// If the property is explicitly set to skip, no injection takes place
	if (checkPropertySkipping(pvs)) {
		return;
	}
	// Get the injected element object
	Method method = (Method) this.member;
	Object[] arguments;
	// If the container caches the current method
	if (this.cached) {
		// Shortcut for avoiding synchronization...
		// Gets the method parameter in the cache to specify the Bean name
		arguments = resolveCachedArguments(beanName);
	}
	// If there is no cache
	else {
		// Get the argument list for the methodClass<? >[] paramTypes = method.getParameterTypes();// Create an array of method parameters
		arguments = new Object[paramTypes.length];
		DependencyDescriptor[] descriptors = new DependencyDescriptor[paramTypes.length];
		Set<String> autowiredBeans = newLinkedHashSet<>(paramTypes.length); Assert.state(beanFactory ! =null."No BeanFactory available");
		// Get the type converter for the container
		TypeConverter typeConverter = beanFactory.getTypeConverter();
		for (int i = 0; i < arguments.length; i++) {
			// Create a method parameter object
			MethodParameter methodParam = new MethodParameter(method, i);
			DependencyDescriptor currDesc = new DependencyDescriptor(methodParam, this.required);
			currDesc.setContainingClass(bean.getClass());
			// Parses the input parameters of the method to create dependency descriptors for the method parameters
			descriptors[i] = currDesc;
			try {
				Object arg = beanFactory.resolveDependency(currDesc, beanName, autowiredBeans, typeConverter);
				if (arg == null&&!this.required) {
					arguments = null;
					break;
				}
				// Resolve the dependencies according to the Bean definition in the container, and obtain the method parameter dependency object
				arguments[i] = arg;
			}
			catch (BeansException ex) {
				throw new UnsatisfiedDependencyException(null, beanName, newInjectionPoint(methodParam), ex); }}// Thread synchronization to ensure data consistency in the container
		synchronized (this) {
			// If the current method is not cached by the container
			if (!this.cached) {
				// If the method argument list is not empty
				if(arguments ! =null) {
					// Assign to the object that caches method parameters in the container
					Object[] cachedMethodArguments = new Object[paramTypes.length];
					for (int i = 0; i < arguments.length; i++) {
						cachedMethodArguments[i] = descriptors[i];
					}
					// Register the dependent Bean for the specified Bean
					registerDependentBeans(beanName, autowiredBeans);
					// If the size of the set of dependent objects is equal to the number of method parameters
					if (autowiredBeans.size() == paramTypes.length) {
						Iterator<String> it = autowiredBeans.iterator();
						// Set dependent objects for method parameters
						for (int i = 0; i < paramTypes.length; i++) {
							String autowiredBeanName = it.next();
							// If there is a Bean object with the specified name in the container
							if (beanFactory.containsBean(autowiredBeanName)) {
								// If the parameter type matches the dependent object type
								if (beanFactory.isTypeMatch(autowiredBeanName, paramTypes[i])) {
									// Create a reference to the dependent object and copy it to the corresponding parameter of the method
									cachedMethodArguments[i] = newShortcutDependencyDescriptor( descriptors[i], autowiredBeanName, paramTypes[i]); }}}}this.cachedMethodArguments = cachedMethodArguments;
				}
				// If the method parameter list is null, set the container's cache for that method parameter to NULL
				else {
					this.cachedMethodArguments = null;
				}
				// Set the container to already cache the method
				this.cached = true; }}}// If the method parameter dependent object is not null
	if(arguments ! =null) {
		try {
			Using the JDK's reflection mechanism, explicitly set the method's access control permission to allow access
			ReflectionUtils.makeAccessible(method);
			// Call the specified method of the Bean
			method.invoke(bean, arguments);
		}
		catch (InvocationTargetException ex){
			throwex.getTargetException(); }}}Copy the code

conclusion

The principle of the @AutoWired annotation is explained in one word: it is to find all matching beans by type from the IOC container, and then select the most matching beans according to @primary, @ORDER, @priorityOrder or Spring default rules, and inject them into the field using reflection.