Location>code7788 >text

@Autowired, @Resource, @Inject annotation implementation principle in Spring

Popularity:200 ℃/2025-04-24 15:03:20

Use Cases

Prerequisites:Now there is aVehicleInterface, it has two implementation classesBusandCarThere is another class nowVehicleServiceNeed to inject oneVehicleType of bean:

public interface Vehicle {}

@Component
public class Car implements Vehicle {}

@Component 
public class Bus implements Vehicle {}

use @Autowired Annotation injection Bean

@AutowiredAnnotations can be combined with@QualifierUse annotations together to limit beans with specific names injected if there are multiple beans that meet the criteria:

@Component
 public class VehicleService {
     @Autowired
     @Qualifier("car") //Suppose here is the bean with the bean name car
     private Vehicle vehicle;
 }

use @Inject Annotation injection Bean

@InjectAnnotations can be combined with@Qualifieror@NamedUse annotations together to limit beans with specific names injected if there are multiple beans that meet the criteria:

@Component
 public class VehicleService {
     @Inject
     @Qualifier("car") //Suppose here is the bean with the bean name car
     private Vehicle vehicle;

     @Inject
     @Named("bus") //Suppose here is the bean with the bean name bus
     private Vehicle anotherVehicle;
 }

use @Resource Annotation injection bean:

@Component
public class VehicleService {
    @Resource(name = "car")
    private Vehicle vehicle;
}

Although the above three usage methods can all realize the requirements of injecting beans, what are the differences between them in the underlying implementation?

Annotation system

Several sets of annotations are defined in the Java EE and Spring systems:

JSR 250:Defined@PostConstruct@PreDestroy@ResourceAnnotation, where@ResourceannotationBy default, injection is by name

JSR 330:Defined@Inject@Qualifier, @NamedAnnotation, where@InjectannotationBy default, injection is performed by type, can be matched@Qualifieror@NamedAnnotation implementation is injected by name.

Spring:Defined@Autowired@QualifierAnnotation, where@AutowiredannotationBy default, injection is performed by type, can be matched@QualifierAnnotation implementation is injected by name.

The annotation currently defined by JSR 250 belongs to-api, while the annotation defined by JSR 330 belongs to-api

Implementation principle

The location where the InstantiationAwareBeanPostProcessor method call is triggered:

Provided in SpringInstantiationAwareBeanPostProcessorInterface, it has apostProcessProperties()Responsible for processing the properties of the bean.

Implementation classes are provided in SpringCommonAnnotationBeanPostProcessorResponsible for handling@ResourceAnnotation; implementation class providedAutowiredAnnotationBeanPostProcessorResponsible for handling@AutowiredAnnotations and@Injectannotation.

InstantiationAwareBeanPostProcessorofpostProcessProperties()The method isAbstractAutowireCapableBeanFactoryIn-housedoCreateBean()The method that creates a bean triggers the call. The main implementation logic in this method isInstantiate Bean -> Fill in Bean properties -> Initialize Bean.The code is as follows:

protected Object doCreateBean(String beanName, RootBeanDefinition mbd,
	 @Nullable Object[] args) throws BeanCreationException {
	 BeanWrapper instanceWrapper = null;
	 if (()) {
		 instanceWrapper = (beanName);
	 }
	 if (instanceWrapper == null) {
         //Instantiate the Bean object
		 instanceWrapper = createBeanInstance(beanName, mbd, args);
	 }
	 Object bean = ();

	 boolean earlySingletonExposure = (()
		 &&
		 && isSingletonCurrentlyInCreation(beanName));
	 if (earlySingletonExposure) {
		 addSingletonFactory(beanName,
			 () -> getEarlyBeanReference(beanName, mbd, bean));
	 }

	 Object exposedObject = bean;
	 try {
         //Fill in Bean properties
		 populateBean(beanName, mbd, instanceWrapper);
		 //Initialize Bean
		 exposedObject = initializeBean(beanName, exposedObject, mbd);
	 }
 }

Methods in populating Bean propertiespopulateBean()Implemented the rightpostProcessProperties()Method calls,In this method, the fields that need to be injected for annotation modification are assigned, that is, automatic injection.The code is as follows:

protected void populateBean(String beanName, RootBeanDefinition mbd, @Nullable BeanWrapper bw) {
     //Omit some code
     PropertyValues ​​pvs = (() ? () : null);
     if (hasInstantiationAwareBeanPostProcessors()) {
        if (pvs == null) {
           pvs = ();
        }
        // Here we get all the implementation classes of InstantiationAwareBeanPostProcessor interfaces
        for (InstantiationAwareBeanPostProcessor bp : getBeanPostProcessorCache().instantiationAware) {
		   //Calling the postProcessProperties() method
           PropertyValues ​​pvsToUse = (pvs,
	           (), beanName);
           if (pvsToUse == null) {
              return;
           }
           pvs = pvsToUse;
        }
     }
 }

InstantiationAwareBeanPostProcessor registration time:

now thatInstantiationAwareBeanPostProcessorIt is responsible for handling the automatic injection of the properties of the bean, so it must have been initialized before the business bean is created, so that its instance method can be called when the business bean is created. Its initialization is the base class in the Spring contextAbstractApplicationContextofrefresh()Completed in the method. The code is as follows:

public void refresh() throws BeansException, IllegalStateException {
     //Omit other codes
	 //The InstantiationAwareBeanPostProcessor is registered here
	 registerBeanPostProcessors(beanFactory);
	
     //Omit other codes
    
	 //Create all singleton beans here
	 finishBeanFactoryInitialization(beanFactory);
    
	 finishRefresh();
 }

And inregisterBeanPostProcessors()Called again in the methodPostProcessorRegistrationDelegateofregisterBeanPostProcessors()Method to complete the registration. The code is as follows:

protected void registerBeanPostProcessors(ConfigurableListableBeanFactory beanFactory) {
    (beanFactory, this);
}

existPostProcessorRegistrationDelegateofregisterBeanPostProcessors()The method truly implements the registration logic. The code is as follows:

public static void registerBeanPostProcessors(ConfigurableListableBeanFactory beanFactory,
     AbstractApplicationContext applicationContext) {
     //Get all bean names that implement the BeanPostProcessor interface
     //InstantiationAwareBeanPostProcessor interface inherits BeanPostProcessor interface
     String[] postProcessorNames = (, true, false);

     //Transf the Bean name and call the() method to trigger the creation of the BeanPostProcessor Bean
     //Then it is divided into three categories based on whether the PriorityOrdered interface, Ordered interface and others are implemented.
     //Register BeanPostProcessor instances of these three categories respectively
     List<BeanPostProcessor> priorityOrderedPostProcessors = new ArrayList<>();
     List<BeanPostProcessor> internalPostProcessors = new ArrayList<>();
     List<String> orderedPostProcessorNames = new ArrayList<>();
     List<String> nonOrderedPostProcessorNames = new ArrayList<>();
     for (String ppName: postProcessorNames) {
         if ((ppName, )) {
             //Calling the() method here to trigger the creation of the BeanPostProcessor Bean
             BeanPostProcessor pp = (ppName, );
             (pp);
             if (pp instanceof MergedBeanDefinitionPostProcessor) {
                 (pp);
             }
         }
         else if ((ppName, )) {
             (ppName);
         }
         else {
             (ppName);
         }
     }

     //First register the BeanPostProcessor that implements the PriorityOrdered interface
     sortPostProcessors(priorityOrderedPostProcessors, beanFactory);
     registerBeanPostProcessors(beanFactory, priorityOrderedPostProcessors);

     //Then trigger the creation and registration of the BeanPostProcessor Bean that implements the Ordered interface
     List<BeanPostProcessor> orderedPostProcessors = new ArrayList<>(());
     for (String ppName: orderedPostProcessorNames) {
         BeanPostProcessor pp = (ppName, );
         (pp);
         if (pp instanceof MergedBeanDefinitionPostProcessor) {
             (pp);
         }
     }
     sortPostProcessors(orderedPostProcessors, beanFactory);
     registerBeanPostProcessors(beanFactory, orderedPostProcessors);

     // Finally, the creation and registration of other BeanPostProcessor Beans are triggered.
     List<BeanPostProcessor> nonOrderedPostProcessors = new ArrayList<>(());
     for (String ppName: nonOrderedPostProcessorNames) {
         BeanPostProcessor pp = (ppName, );
         (pp);
         if (pp instanceof MergedBeanDefinitionPostProcessor) {
             (pp);
         }
     }
     registerBeanPostProcessors(beanFactory, nonOrderedPostProcessors);

     sortPostProcessors(internalPostProcessors, beanFactory);
     registerBeanPostProcessors(beanFactory, internalPostProcessors);
 }

CommonAnnotationBeanPostProcessor implementation logic (taking the modified field as an example)

First of allCommonAnnotationBeanPostProcessorThe static initialization block initializes the annotation it wants to process. The code is as follows:

static {
     //This is to adapt to different versions of @Resource annotation under different package paths
     jakartaResourceType = loadAnnotationType("");
     if (jakartaResourceType != null) {
         (jakartaResourceType);
     }

     //This is to adapt to different versions of @Resource annotation under different package paths
     javaxResourceType = loadAnnotationType("");
     if (javaxResourceType != null) {
         (javaxResourceType);
     }
 }

In itpostProcessProperties()The main implementation logic in the method isturn up@ResourceAnnotation modified fields -> Assign values ​​to fields through reflection. The code is as follows:

public PropertyValues ​​postProcessProperties(PropertyValues ​​pvs, Object bean, String beanName) {
     // Find the @Resource annotation modified field
     InjectionMetadata metadata = findResourceMetadata(beanName, (), pvs);
     try {
         // Assign a value to the field
         (bean, beanName, pvs);
     }
     catch (Throwable ex) {
         throw new BeanCreationException(beanName, "Injection of resource dependencies failed", ex);
     }
     return pvs;
 }

try to find@ResourceThe fields modified by the annotation are infindResourceMetadata()Implemented in the method, in which the method is called againbuildResourceMetadata()To do the actual search, in this method, iterate through reflection to see if it has@ResourceAnnotation modification, if so, wrap it into oneResourceElementObjects are placed in the list. Finally, construct aInjectionMetadataObject returns. The code is as follows:

private InjectionMetadata findResourceMetadata(String beanName, Class<?> clazz, @Nullable PropertyValues ​​pvs) {
     String cacheKey = ((beanName) ? beanName : ());
     InjectionMetadata metadata = (cacheKey);
     if ((metadata, clazz)) {
         synchronized () {
             metadata = (cacheKey);
             if ((metadata, clazz)) {
                 if (metadata != null) {
                     (pvs);
                 }
                 //Call the buildResourceMetadata() method here
                 metadata = buildResourceMetadata(clazz);
                 (cacheKey, metadata);
             }
         }
     }
     return metadata;
 }

 private InjectionMetadata buildResourceMetadata(Class<?> clazz) {
     List<> elements = new ArrayList<>();
     Class<?> targetClass = clazz;

     //Omit some code
    
     do {
         final List<> currElements = new ArrayList<>();
         // Here we will traverse each field to see if the field has @Resource annotation modification, add it to the list
         (targetClass, field -> {
            //Omit some code
            
            if (jakartaResourceType != null && (jakartaResourceType)) {
                 if ((())) {
                     throw new IllegalStateException("@Resource annotation is not supported on static fields");
                 }
                 if (!(().getName())) {
                     (new ResourceElement(field, field, null));
                 }
             }
             else if (javaxResourceType != null && (javaxResourceType)) {
                 if ((())) {
                     throw new IllegalStateException("@Resource annotation is not supported on static fields");
                 }
                 if (!(().getName())) {
                     (new LegacyResourceElement(field, field, null));
                 }
             }
         });
         (0, currElements);
         targetClass = ();
     }
     while (targetClass != null && targetClass != );

     return (elements, clazz);
 }

The actual operation to trigger the assignment isInjectionMetadataofinject()Implemented in the method, it will be called in a loop again in its method.InjectedElementofinject()method. The code is as follows:

public void inject(Object target, @Nullable String beanName, @Nullable PropertyValues pvs) throws Throwable {
    Collection<InjectedElement> checkedElements = ;
    Collection<InjectedElement> elementsToIterate =
            (checkedElements != null ? checkedElements : );
    if (!()) {
        for (InjectedElement element : elementsToIterate) {
            (target, beanName, pvs);
        }
    }
}

existInjectedElementofinject()The method is used to reflect the found bean to the field. The code is as follows:

protected void inject(Object target, @Nullable String requestingBeanName, @Nullable PropertyValues ​​pvs)
	 throws Throwable {
     if (! shouldInject(pvs)) {
         return;
     }
     if () {
         Field field = (Field);
         (field);
         //The value is set by reflection here. The value set is the Bean obtained according to the Bean name
         (target, getResourceToInject(target, requestingBeanName));
     } else {
         //Omit other codes
     }
 }

existResourceElementofgetResourceToInject()The search logic is implemented in the method:ifBeanFactoryThe bean corresponding to the name of this bean is directly searched according to the name, otherwise it will match according to the type. This is what is commonly said@ResourceThe default annotation is to match according to the name. If the name cannot match, then match according to the type.. The code is as follows:

protected Object getResource(LookupElement element, @Nullable String requestingBeanName)
     throws NoSuchBeanDefinitionException {
     //Omit the code

     // Regular resource autowiring
     if ( == null) {
         throw new NoSuchBeanDefinitionException(,
                 "No resource factory configured - specify the 'resourceFactory' property");
     }
     return autowireResource(, element, requestingBeanName);
 }

 protected Object autowireResource(BeanFactory factory, LookupElement element, @Nullable String requestingBeanName)
	 throws NoSuchBeanDefinitionException {
     Object resource;
     Set<String> autowiredBeanNames;
     String name = ;

     if (factory instance of AutowireCapableBeanFactory autowireCapableBeanFactory) {
         //If the bean cannot be found according to the bean name and the first branch is allowed to match according to the type
         if ( && && !(name)) {
             autowiredBeanNames = new LinkedHashSet<>();
             resource = (
                     (), requestingBeanName, autowiredBeanNames, null);
             if (resource == null) {
                 throw new NoSuchBeanDefinitionException((), "No resolvable resource object");
             }
         } else { //If you find a bean based on the name, you will directly obtain the bean based on the name
             resource = (name, ());
             autowiredBeanNames = (name);
         }
     } else {
         //Omit the code
     }

     //Omit the code
     return resource;
 }

The logic of type matching isDefaultListableBeanFactoryofdoResolveDependency()Implemented in the method,In this method, all beans of the current type will be found according to the type, and then a map is constructed. The key is the name of the bean and the value is the corresponding bean object. If the number of beans found is greater than 1, the return that best meets the criteria will be selected (the basis for selection will be discussed later). If it is equal to 1, the bean will be directly returned.. The code is as follows:

public Object doResolveDependency(DependencyDescriptor descriptor, @Nullable String beanName,
	 @Nullable Set<String> autowiredBeanNames, @Nullable TypeConverter typeConverter) throws BeansException {
	 InjectionPoint previousInjectionPoint = (descriptor);
	 try {
		 //Omit the code
		
		 // Here all beans are found according to the type, and then the name of the bean is used as the key and the bean is used as the Value
		 Map<String, Object> matchingBeans = findAutowireCandidates(beanName, type, descriptor);
		 if (()) {
			 // Step 4c (fallback): custom Collection / Map declarations for collecting multiple beans
			 multipleBeans = resolveMultipleBeansFallback(descriptor, beanName, autowiredBeanNames, typeConverter);
			 if (multipleBeans != null) {
				 return multipleBeans;
			 }
			 // Raise exception if nothing found for required injection point
			 if (isRequired(descriptor)) {
				 raiseNoMatchingBeanFound(type, (), descriptor);
			 }
			 return null;
		 }

		 String autowiredBeanName;
		 Object instanceCandidate;

		 //If you find multiple beans according to the type, you need to select a suitable bean to return
		 if (() > 1) {
			 autowiredBeanName = determineAutowireCandidate(matchingBeans, descriptor);
			 if (autowiredBeanName == null) {
				 if (isRequired(descriptor) || !indicatesArrayCollectionOrMap(type)) {
					 // Raise exception if no clear match found for required injection point
					 return ((), matchingBeans);
				 }
				 else {
					 // In case of an optional Collection/Map, silently ignore a non-unique case:
					 // possible 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 = (autowiredBeanName);
		 } else {
			 //If there is only one bean, return this bean directly
			 <String, Object> entry = ().iterator().next();
			 autowiredBeanName = ();
			 instanceCandidate = ();
		 }

		 // Step 6: validate single result
		 if (autowiredBeanNames != null) {
			 (autowiredBeanName);
		 }
		 if (instanceCandidate instanceof Class) {
			 instanceCandidate = (autowiredBeanName, type, this);
		 }
		 return resolveInstance(instanceCandidate, descriptor, type, autowiredBeanName);
	 }
	 Finally {
		 (previousInjectionPoint);
	 }
 }

AutowiredAnnotationBeanPostProcessor implementation logic (taking the modified field as an example)

First, the annotations that need to be processed in the constructor include@Autowiredand@Injectannotation. The code is as follows:

public AutowiredAnnotationBeanPostProcessor() {
     //Add @Autowired annotation to be processed
     ();
     ();

     ClassLoader classLoader = ();
     try {
         //This is to adapt to different versions of @Inject annotation under different package paths
         ((Class<? extends Annotation>)
                 ("", classLoader));
     } catch (ClassNotFoundException ex) {
         // API not available - simply skip.
     }

     try {
         //This is to adapt to different versions of @Inject annotation under different package paths
         ((Class<? extends Annotation>)
                 ("", classLoader));
     } catch (ClassNotFoundException ex) {
         // API not available - simply skip.
     }
 }

In itpostProcessProperties()The main implementation logic in the method isturn up@Autowiredor@InjectAnnotation modified fields -> Assign values ​​to fields through reflection. The code is as follows:

public PropertyValues postProcessProperties(PropertyValues pvs, Object bean, String beanName) {
    InjectionMetadata metadata = findAutowiringMetadata(beanName, (), pvs);
    try {
        (bean, beanName, pvs);
    }
    catch (BeanCreationException ex) {
        throw ex;
    }
    catch (Throwable ex) {
        throw new BeanCreationException(beanName, "Injection of autowired dependencies failed", ex);
    }
    return pvs;
}

try to find@Autowiredor@InjectThe fields modified by the annotation are infindAutowiringMetadata()Implemented in the method, in which the method is called againbuildAutowiringMetadata()To do the actual search, in this method, iterate through reflection to see if it has@Autowiredor@InjectAnnotation modification, if so, wrap it into oneAutowiredFieldElementObjects are placed in the list. Finally, construct aInjectionMetadataObject returns. The code is as follows:

private InjectionMetadata findAutowiringMetadata(String beanName, Class<?> clazz, @Nullable PropertyValues ​​pvs) {
     // Fall back to class name as cache key, for backwards compatibility with custom calls.
     String cacheKey = ((beanName) ? beanName : ());
     // Quick check on the concurrent map first, with minimal locking.
     InjectionMetadata metadata = (cacheKey);
     if ((metadata, clazz)) {
         synchronized () {
             metadata = (cacheKey);
             if ((metadata, clazz)) {
                 if (metadata != null) {
                     (pvs);
                 }
                 metadata = buildAutowiringMetadata(clazz);
                 (cacheKey, metadata);
             }
         }
     }
     return metadata;
 }

 private InjectionMetadata buildAutowiringMetadata(Class<?> clazz) {
     if (!(clazz, )) {
         return ;
     }

     final List<> elements = new ArrayList<>();
     Class<?> targetClass = clazz;

     do {
         final List<> fieldElements = new ArrayList<>();
         (targetClass, field -> {
             //I found here whether there are @Autowired or @Inject annotation modifications
             MergedAnnotation<?> ann = findAutowiredAnnotation(field);
             if (ann != null) {
                 if ((())) {
                     return;
                 }
                 boolean required = determineRequiredStatus(ann);
                 (new AutowiredFieldElement(field, required));
             }
         });
     }
 }

The actual operation to trigger the assignment isInjectionMetadataofinject()Implemented in the method, it will be called in a loop again in its method.AutowiredFieldElementofinject()method. The code is as follows:

public void inject(Object target, @Nullable String beanName, @Nullable PropertyValues pvs) throws Throwable {
    Collection<InjectedElement> checkedElements = ;
    Collection<InjectedElement> elementsToIterate =
            (checkedElements != null ? checkedElements : );
    if (!()) {
        for (InjectedElement element : elementsToIterate) {
            (target, beanName, pvs);
        }
    }
}

existInjectedElementofinject()The method is used to reflect the found bean to the field. The code is as follows:

@Override
 protected void inject(Object bean, @Nullable String beanName, @Nullable PropertyValues ​​pvs) throws Throwable {
     Field field = (Field);
     Object value;
     if () {
         //Omit the code
     } else {
         //Find the corresponding bean
         value = resolveFieldValue(field, bean, beanName);
     }
     if (value != null) {
         (field);
         //Assign value through reflection
         (bean, value);
     }
 }

 @Nullable
 private Object resolveFieldValue(Field field, Object bean, @Nullable String beanName) {
     DependencyDescriptor desc = new DependencyDescriptor(field, );
     (());
     Set<String> autowiredBeanNames = new LinkedHashSet<>(2);
     TypeConverter typeConverter = ();
     Object value;
     try {
         //Calling the resolveDependency() method of beanFactory
         value = (desc, beanName, autowiredBeanNames, typeConverter);
     } catch (BeansException ex) {
         throw new UnsatisfiedDependencyException(null, beanName, new InjectionPoint(field), ex);
     }
     return value;
 }

Then it will be calledDefaultListableBeanFactoryofdoResolveDependency()Method, and above@ResourceAnnotation The call that the bean needs to match according to the type is a method, but it will have one more branch.In this branch, determine whether the bean corresponding to the bean name exists. If it exists, it will be returned directly. If it does not exist, it will be matched according to the type. In fact, it will be matched according to the name first. If the name cannot match, the logic of type matching will be followed before going.. The code is as follows:

public Object doResolveDependency(DependencyDescriptor descriptor, @Nullable String beanName,
	 @Nullable Set<String> autowiredBeanNames, @Nullable TypeConverter typeConverter) throws BeansException {
	 InjectionPoint previousInjectionPoint = (descriptor);
	 try {
		 //Omit the code

         //If it is @Autowired annotation or @Inject annotation, you will first go to the following branch
         //In this branch, you will also first determine whether the bean corresponding to the bean name exists. If it exists
         //Then directly get the return, and if it does not exist, it will match according to the type
         if (()) {
             String dependencyName = ();
             if (dependencyName == null || !containsBean(dependencyName)) {
                 String suggestedName = getAutowireCandidateResolver().getSuggestedName(descriptor);
                 dependencyName = (suggestedName != null && containsBean(suggestedName) ? suggestedName : null);
             }
             if (dependencyName != null) {
                 dependencyName = canonicalName(dependentName); // dependency name can be alias of target name
                 if (isTypeMatch(dependencyName, type) && isAutowireCandidate(dependencyName, descriptor) &&
                         !isFallback(dependencyName) && !hasPrimaryConflict(dependencyName, type) &&
                         !isSelfReference(beanName, dependencyName)) {
                     if (autowiredBeanNames != null) {
                         (dependencyName);
                     }
                     Object dependencyBean = getBean(dependentName);
                     return resolveInstance(dependentBean, descriptor, type, dependencyName);
                 }
             }
         }
        
		 // Here all beans are found according to the type, and then the name of the bean is used as the key and the bean is used as the Value
		 Map<String, Object> matchingBeans = findAutowireCandidates(beanName, type, descriptor);
		 if (()) {
			 // Step 4c (fallback): custom Collection / Map declarations for collecting multiple beans
			 multipleBeans = resolveMultipleBeansFallback(descriptor, beanName, autowiredBeanNames, typeConverter);
			 if (multipleBeans != null) {
				 return multipleBeans;
			 }
			 // Raise exception if nothing found for required injection point
			 if (isRequired(descriptor)) {
				 raiseNoMatchingBeanFound(type, (), descriptor);
			 }
			 return null;
		 }

		 String autowiredBeanName;
		 Object instanceCandidate;

		 //If you find multiple beans according to the type, you need to select a suitable bean to return
		 if (() > 1) {
			 autowiredBeanName = determineAutowireCandidate(matchingBeans, descriptor);
			 if (autowiredBeanName == null) {
				 if (isRequired(descriptor) || !indicatesArrayCollectionOrMap(type)) {
					 // Raise exception if no clear match found for required injection point
					 return ((), matchingBeans);
				 }
				 else {
					 // In case of an optional Collection/Map, silently ignore a non-unique case:
					 // possible 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 = (autowiredBeanName);
		 } else {
			 //If there is only one bean, return this bean directly
			 <String, Object> entry = ().iterator().next();
			 autowiredBeanName = ();
			 instanceCandidate = ();
		 }

		 // Step 6: validate single result
		 if (autowiredBeanNames != null) {
			 (autowiredBeanName);
		 }
		 if (instanceCandidate instanceof Class) {
			 instanceCandidate = (autowiredBeanName, type, this);
		 }
		 return resolveInstance(instanceCandidate, descriptor, type, autowiredBeanName);
	 }
	 Finally {
		 (previousInjectionPoint);
	 }
 }

The principle of returning a bean when there are multiple types matching beans

When multiple beans are found according to type, one bean needs to be returned according to some rules. Common ones can be passed@QualiferQualified name or through@Primaryto indicate priority injection. existDefaultListableBeanFactorofdetermineAutowireCandidate()The method implements these logic:

First iterate through all beans that match the type found, and then see if there are@PrimaryAnnotation modification, if any, the bean is returned first;

Otherwise, try again to see if there is a matching bean based on the field name, and return if so;

Otherwise try to get@QualifierName of the annotation definition (for@NamedIt also has it on it@QualiferAnnotation modification), then see if there is a bean with a name matching, and if so, return;

Otherwise, traverse the bean to see if there is@PriorityAnnotation modification. If there is one, find the highest priority bean to return. The smaller the value, the higher the priority;

Otherwise, lookresolvableDependenciesWhether there is a corresponding instance to register, and if so, it will return. Its usage scenario is generally that the user's own new object can be registered here, and then it can be injected into a Spring-managed bean. The code is as follows:

protected String determineAutowireCandidate(Map<String, Object> candidates, DependencyDescriptor descriptor) {
     Class<?> requiredType = ();
     //First process @Primary annotation, if a bean has @Primary annotation modification, it will be returned first
     String primaryCandidate = determinePrimaryCandidate(candidates, requiredType);
     if (primaryCandidate != null) {
         return primaryCandidate;
     }
     // Otherwise, match again according to the name of the field to see if there is a bean with the same name as the field in the bean found. If so, return it first.
     String dependencyName = ();
     if (dependencyName != null) {
         for (String beanName : ()) {
             if (matchesBeanName(beanName, dependencyName)) {
                 return beanName;
             }
         }
     }
     // Otherwise, try to get the name defined by the @Qualifier annotation, see if there is a bean with the same name as the bean in the bean you are looking for. If so, return it first
     String suggestedName = getAutowireCandidateResolver().getSuggestedName(descriptor);
     if (suggestedName != null) {
         for (String beanName : ()) {
             if (matchesBeanName(beanName, suggestedName)) {
                 return beanName;
             }
         }
     }
     // Otherwise, see if the bean found is modified with @Priority annotation. If so, take the highest priority and return the lowest value, which is the lowest value.
     String priorityCandidate = determineHighestPriorityCandidate(candidates, requiredType);
     if (priorityCandidate != null) {
         return priorityCandidate;
     }
     // Otherwise, if there is a match in the custom registered object that is not Spring management lifecycle, you can put it in resolvableDependencies
     //Some objects, these objects are not created by Spring but are created by the user themselves and need to be injected into a Spring bean
     for (<String, Object> entry : ()) {
         String candidateName = ();
         Object beanInstance = ();
         if (beanInstance != null && (beanInstance)) {
             return candidateName;
         }
     }
     return null;
 }

@NamedUsed in the annotation definition@QualiferAnnotation modification. The code is as follows:

@Qualifier // @Qualifer annotation is used here
 @Documented
 @Retention(RUNTIME)
 public @interface Named {
     String value() default "";
 }