Use Cases
Prerequisites:Now there is aVehicle
Interface, it has two implementation classesBus
andCar
There is another class nowVehicleService
Need to inject oneVehicle
Type of bean:
public interface Vehicle {}
@Component
public class Car implements Vehicle {}
@Component
public class Bus implements Vehicle {}
use @Autowired
Annotation injection Bean:
@Autowired
Annotations can be combined with@Qualifier
Use 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:
@Inject
Annotations can be combined with@Qualifier
or@Named
Use 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
,@Resource
Annotation, where@Resource
annotationBy default, injection is by name。
JSR 330:Defined@Inject
,@Qualifier
, @Named
Annotation, where@Inject
annotationBy default, injection is performed by type, can be matched@Qualifier
or@Named
Annotation implementation is injected by name.
Spring:Defined@Autowired
,@Qualifier
Annotation, where@Autowired
annotationBy default, injection is performed by type, can be matched@Qualifier
Annotation 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 SpringInstantiationAwareBeanPostProcessor
Interface, it has apostProcessProperties()
Responsible for processing the properties of the bean.
Implementation classes are provided in SpringCommonAnnotationBeanPostProcessor
Responsible for handling@Resource
Annotation; implementation class providedAutowiredAnnotationBeanPostProcessor
Responsible for handling@Autowired
Annotations and@Inject
annotation.
InstantiationAwareBeanPostProcessor
ofpostProcessProperties()
The method isAbstractAutowireCapableBeanFactory
In-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 thatInstantiationAwareBeanPostProcessor
It 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 contextAbstractApplicationContext
ofrefresh()
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 methodPostProcessorRegistrationDelegate
ofregisterBeanPostProcessors()
Method to complete the registration. The code is as follows:
protected void registerBeanPostProcessors(ConfigurableListableBeanFactory beanFactory) {
(beanFactory, this);
}
existPostProcessorRegistrationDelegate
ofregisterBeanPostProcessors()
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 allCommonAnnotationBeanPostProcessor
The 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@Resource
Annotation 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@Resource
The 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@Resource
Annotation modification, if so, wrap it into oneResourceElement
Objects are placed in the list. Finally, construct aInjectionMetadata
Object 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 isInjectionMetadata
ofinject()
Implemented in the method, it will be called in a loop again in its method.InjectedElement
ofinject()
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);
}
}
}
existInjectedElement
ofinject()
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
}
}
existResourceElement
ofgetResourceToInject()
The search logic is implemented in the method:ifBeanFactory
The 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@Resource
The 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 isDefaultListableBeanFactory
ofdoResolveDependency()
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@Autowired
and@Inject
annotation. 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@Autowired
or@Inject
Annotation 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@Autowired
or@Inject
The 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@Autowired
or@Inject
Annotation modification, if so, wrap it into oneAutowiredFieldElement
Objects are placed in the list. Finally, construct aInjectionMetadata
Object 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 isInjectionMetadata
ofinject()
Implemented in the method, it will be called in a loop again in its method.AutowiredFieldElement
ofinject()
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);
}
}
}
existInjectedElement
ofinject()
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 calledDefaultListableBeanFactory
ofdoResolveDependency()
Method, and above@Resource
Annotation 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@Qualifer
Qualified name or through@Primary
to indicate priority injection. existDefaultListableBeanFactor
ofdetermineAutowireCandidate()
The method implements these logic:
First iterate through all beans that match the type found, and then see if there are@Primary
Annotation 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@Qualifier
Name of the annotation definition (for@Named
It also has it on it@Qualifer
Annotation 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@Priority
Annotation modification. If there is one, find the highest priority bean to return. The smaller the value, the higher the priority;
Otherwise, lookresolvableDependencies
Whether 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;
}
@Named
Used in the annotation definition@Qualifer
Annotation modification. The code is as follows:
@Qualifier // @Qualifer annotation is used here
@Documented
@Retention(RUNTIME)
public @interface Named {
String value() default "";
}