Spring @ Autowired implementation details you don't know

Don't talk at night 2022-02-13 07:25:50 阅读数:732

spring autowired implementation details don

Preface

Believe that a lot of Java Developers have encountered an interview question :Resource and Autowired What's the difference ? I believe the answer to this question is basically clear , But the two are Spring How is China realized ? This requires analysis Spring The source code can be known . Friendship tips : This article is mainly about Autowired Implementation principle of , No analysis Spring Initialization process , Unfamiliar readers can read a previous article of the author first 《 This time I understand Spring Of Bean The instantiation principle 》.

Text

stay Spring Bean There will be many calls during the whole creation process of BeanPostProcessor Implementation class of interface :
 Insert picture description here
The picture above is compiled by me Spring Bean The creation process and all aspects of the whole process BeanPostProcessor And callback calls , Call... The same group of lines on the right represents the same color , Mainly see AutowiredAnnotationBeanPostProcessor and CommonAnnotationBeanPostProcessor, The former is to support @Autowired and @Value annotation , The latter is to support @PostConstruct、@PreDestroy、@Resource annotation . First understand these two Processor The role of , Let's start from scratch .
As you can see from the diagram , stay createBeanInstance Method is called SmartInstantiationAwareBeanPostProcessor Type of determineCandidateConstructors, What does this method do ? Look at the code :

 protected BeanWrapper createBeanInstance(String beanName, RootBeanDefinition mbd, @Nullable Object[] args) {

......
// Candidate constructors for autowiring?
// Find the currently instantiating bean There is @Autowired Annotation constructor 
Constructor<?>[] ctors = determineConstructorsFromBeanPostProcessors(beanClass, beanName);
if (ctors != null || mbd.getResolvedAutowireMode() == AUTOWIRE_CONSTRUCTOR ||
mbd.hasConstructorArgumentValues() || !ObjectUtils.isEmpty(args)) {

// If ctors Not empty , It means that there is... On the constructor @Autowired annotation 
return autowireConstructor(beanName, mbd, ctors, args);
}
......
// No special handling: simply use no-arg constructor.
return instantiateBean(beanName, mbd);
}
protected Constructor<?>[] determineConstructorsFromBeanPostProcessors(@Nullable Class<?> beanClass, String beanName)
throws BeansException {

if (beanClass != null && hasInstantiationAwareBeanPostProcessors()) {

for (BeanPostProcessor bp : getBeanPostProcessors()) {

if (bp instanceof SmartInstantiationAwareBeanPostProcessor) {

SmartInstantiationAwareBeanPostProcessor ibp = (SmartInstantiationAwareBeanPostProcessor) bp;
Constructor<?>[] ctors = ibp.determineCandidateConstructors(beanClass, beanName);
if (ctors != null) {

return ctors;
}
}
}
}
return null;
}

createBeanInstance The method is to instantiate Bean, And call AutowiredAnnotationBeanPostProcessor.determineCandidateConstructors The purpose of is to find the first with @Autowired How to construct annotations ( There are three modes of automatic injection : attribute 、 Construction method 、 Common method ), That is, inject... Through the construction method , If it is not found, the parameterless construction is instantiated through reflection . We usually use attribute injection , So you don't usually enter determineCandidateConstructors Method , So I won't elaborate here , Interested readers can see for themselves .
Then go back to doCreateBean In the method , You can see the call applyMergedBeanDefinitionPostProcessors Method :

 protected void applyMergedBeanDefinitionPostProcessors(RootBeanDefinition mbd, Class<?> beanType, String beanName) {

for (BeanPostProcessor bp : getBeanPostProcessors()) {

if (bp instanceof MergedBeanDefinitionPostProcessor) {

/** * CommonAnnotationBeanPostProcessor Support @PostConstruct,@PreDestroy,@Resource annotation * AutowiredAnnotationBeanPostProcessor Support @Autowired,@Value annotation */
MergedBeanDefinitionPostProcessor bdp = (MergedBeanDefinitionPostProcessor) bp;
bdp.postProcessMergedBeanDefinition(mbd, beanType, beanName);
}
}
}

This method essentially calls MergedBeanDefinitionPostProcessor Type of postProcessMergedBeanDefinition Method , In this way to collect @Autowired、@Resource Etc , Here is the main analysis AutowiredAnnotationBeanPostProcessor The implementation of the :

 public void postProcessMergedBeanDefinition(RootBeanDefinition beanDefinition, Class<?> beanType, String beanName) {

InjectionMetadata metadata = findAutowiringMetadata(beanName, beanType, null);
metadata.checkConfigMembers(beanDefinition);
}
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.
InjectionMetadata metadata = this.injectionMetadataCache.get(cacheKey);
if (InjectionMetadata.needsRefresh(metadata, clazz)) {

synchronized (this.injectionMetadataCache) {

metadata = this.injectionMetadataCache.get(cacheKey);
if (InjectionMetadata.needsRefresh(metadata, clazz)) {

if (metadata != null) {

metadata.clear(pvs);
}
// Mainly look at this method 
metadata = buildAutowiringMetadata(clazz);
this.injectionMetadataCache.put(cacheKey, metadata);
}
}
}
return metadata;
}
private InjectionMetadata buildAutowiringMetadata(final Class<?> clazz) {

List<InjectionMetadata.InjectedElement> elements = new ArrayList<>();
Class<?> targetClass = clazz;
do {

final List<InjectionMetadata.InjectedElement> currElements = new ArrayList<>();
// Find the belt @Autowired Attributes of the annotation and encapsulated as AnnotationAttributes
ReflectionUtils.doWithLocalFields(targetClass, field -> {

AnnotationAttributes ann = findAutowiredAnnotation(field);
if (ann != null) {

if (Modifier.isStatic(field.getModifiers())) {

if (logger.isInfoEnabled()) {

logger.info("Autowired annotation is not supported on static fields: " + field);
}
return;
}
boolean required = determineRequiredStatus(ann);
currElements.add(new AutowiredFieldElement(field, required));
}
});
// Find the belt @Autowired Annotate the method and encapsulate it as AnnotationAttributes
ReflectionUtils.doWithLocalMethods(targetClass, method -> {

Method bridgedMethod = BridgeMethodResolver.findBridgedMethod(method);
if (!BridgeMethodResolver.isVisibilityBridgeMethodPair(method, bridgedMethod)) {

return;
}
AnnotationAttributes ann = findAutowiredAnnotation(bridgedMethod);
if (ann != null && method.equals(ClassUtils.getMostSpecificMethod(method, clazz))) {

if (Modifier.isStatic(method.getModifiers())) {

if (logger.isInfoEnabled()) {

logger.info("Autowired annotation is not supported on static methods: " + method);
}
return;
}
if (method.getParameterCount() == 0) {

if (logger.isInfoEnabled()) {

logger.info("Autowired annotation should only be used on methods with parameters: " +
method);
}
}
boolean required = determineRequiredStatus(ann);
PropertyDescriptor pd = BeanUtils.findPropertyForMethod(bridgedMethod, clazz);
currElements.add(new AutowiredMethodElement(method, required, pd));
}
});
elements.addAll(0, currElements);
targetClass = targetClass.getSuperclass();
}
while (targetClass != null && targetClass != Object.class);
return new InjectionMetadata(clazz, elements);
}

The logic of collection is mainly in findAutowiringMetadata In the method , After calling layers, you can see that findAutowiredAnnotation This is the way to find the one with @Autowired and @Value Properties and methods of annotations :

 private final Set<Class<? extends Annotation>> autowiredAnnotationTypes = new LinkedHashSet<>(4);
public AutowiredAnnotationBeanPostProcessor() {

this.autowiredAnnotationTypes.add(Autowired.class);
this.autowiredAnnotationTypes.add(Value.class);
try {

this.autowiredAnnotationTypes.add((Class<? extends Annotation>)
ClassUtils.forName("javax.inject.Inject", AutowiredAnnotationBeanPostProcessor.class.getClassLoader()));
logger.trace("JSR-330 'javax.inject.Inject' annotation found and supported for autowiring");
}
catch (ClassNotFoundException ex) {

// JSR-330 API not available - simply skip.
}
}
private AnnotationAttributes findAutowiredAnnotation(AccessibleObject ao) {

if (ao.getAnnotations().length > 0) {
 // autowiring annotations have to be local
for (Class<? extends Annotation> type : this.autowiredAnnotationTypes) {

AnnotationAttributes attributes = AnnotatedElementUtils.getMergedAnnotationAttributes(ao, type);
if (attributes != null) {

return attributes;
}
}
}
return null;
}

Finally, it is encapsulated as AutowiredFieldElement and AutowiredMethodElement Object's list And along with Class Package them together into InjectionMetadata return , This completes the collection of relevant annotations .
Where to use it after the collection ? Yes Bean Readers familiar with the life cycle know , And then it's going to be Dependency injection , Naturally related calls are populateBean In this way :

 protected void populateBean(String beanName, RootBeanDefinition mbd, @Nullable BeanWrapper bw) {

......
PropertyValues pvs = (mbd.hasPropertyValues() ? mbd.getPropertyValues() : null);
if (mbd.getResolvedAutowireMode() == AUTOWIRE_BY_NAME || mbd.getResolvedAutowireMode() == AUTOWIRE_BY_TYPE) {

MutablePropertyValues newPvs = new MutablePropertyValues(pvs);
// Add property values based on autowire by name if applicable.
if (mbd.getResolvedAutowireMode() == AUTOWIRE_BY_NAME) {

autowireByName(beanName, mbd, bw, newPvs);
}
// Add property values based on autowire by type if applicable.
if (mbd.getResolvedAutowireMode() == AUTOWIRE_BY_TYPE) {

autowireByType(beanName, mbd, bw, newPvs);
}
pvs = newPvs;
}
boolean hasInstAwareBpps = hasInstantiationAwareBeanPostProcessors();
boolean needsDepCheck = (mbd.getDependencyCheck() != AbstractBeanDefinition.DEPENDENCY_CHECK_NONE);
PropertyDescriptor[] filteredPds = null;
// Focus on this if Code block , How important 5
if (hasInstAwareBpps) {

if (pvs == null) {

pvs = mbd.getPropertyValues();
}
for (BeanPostProcessor bp : getBeanPostProcessors()) {

if (bp instanceof InstantiationAwareBeanPostProcessor) {

InstantiationAwareBeanPostProcessor ibp = (InstantiationAwareBeanPostProcessor) bp;
// Dependency injection process ,@Autowired Support for 
PropertyValues pvsToUse = ibp.postProcessProperties(pvs, bw.getWrappedInstance(), beanName);
if (pvsToUse == null) {

if (filteredPds == null) {

filteredPds = filterPropertyDescriptorsForDependencyCheck(bw, mbd.allowCaching);
}
// The old version used this to complete the dependency injection process ,@Autowired Support for 
pvsToUse = ibp.postProcessPropertyValues(pvs, filteredPds, bw.getWrappedInstance(), beanName);
if (pvsToUse == null) {

return;
}
}
pvs = pvsToUse;
}
}
}
if (needsDepCheck) {

if (filteredPds == null) {

filteredPds = filterPropertyDescriptorsForDependencyCheck(bw, mbd.allowCaching);
}
checkDependencies(beanName, mbd, filteredPds, pvs);
}
// xml in <property> Dependency injection of tags 
if (pvs != null) {

applyPropertyValues(beanName, mbd, bw, pvs);
}
}
mbd.getResolvedAutowireMode() == AUTOWIRE_BY_NAME || mbd.getResolvedAutowireMode() == AUTOWIRE_BY_TYPE

Many readers, including many articles on the Internet, see this judgment , We all think that the logic of automatic injection is here , But it's not , This is automatic injection. That's right , But it is aimed at the past xml To configure , as follows :

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation=" http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-2.5.xsd" default-autowire="byName">
<bean id="a" class="com.A" autowire="byName"/>
<bean id="b" class="com.B" autowire="byType"/>
</beans>

In the header file default-autowire Property is to enable global automatic injection , and bean On the label autowire Is specific to the current bean Of , Will override the global configuration . In this way, after we configure ,bean Tags do not need to be configured prototype Child tags , It can also automatically inject the corresponding object . These properties contain the following values :

  • no: The default value is . Indicates no automatic injection . Corresponding BeanDefinition in autowireMode The value of is 0.
  • byName: Automatic injection by name . Corresponding BeanDefinition in autowireMode The value of is 1.
  • byType: Automatic injection according to type , If two or more are found in the container that match this type Bean Will throw an exception . Corresponding BeanDefinition in autowireMode The value of is 2.
  • constructor: Equate to byType, Only when specified autowire=”constructor” When, it means that it will be automatically injected according to the type through the construction method . Corresponding BeanDefinition in autowireMode The value of is 3.

This is it. xml Automatic injection in configuration , And we use @Autowired When the annotation ,BeanDefinition in autowireMode The value of is 0, That means no automatic injection . Insert a digression , Many people are arguing on the Internet @Autowired Is it automatic injection or manual injection , Personally, I think it's all automatic injection , It cannot be said that it cannot be called automatic injection without entering this logic , It's just that it's implemented in another way , At least we didn't let ourselves new And set properties .
What's the other way ? That's what the following code does :

if (hasInstAwareBpps) {

if (pvs == null) {

pvs = mbd.getPropertyValues();
}
for (BeanPostProcessor bp : getBeanPostProcessors()) {

if (bp instanceof InstantiationAwareBeanPostProcessor) {

InstantiationAwareBeanPostProcessor ibp = (InstantiationAwareBeanPostProcessor) bp;
// Dependency injection process ,@Autowired Support for 
PropertyValues pvsToUse = ibp.postProcessProperties(pvs, bw.getWrappedInstance(), beanName);
if (pvsToUse == null) {

if (filteredPds == null) {

filteredPds = filterPropertyDescriptorsForDependencyCheck(bw, mbd.allowCaching);
}
// The old version used this to complete the dependency injection process ,@Autowired Support for 
pvsToUse = ibp.postProcessPropertyValues(pvs, filteredPds, bw.getWrappedInstance(), beanName);
if (pvsToUse == null) {

return;
}
}
pvs = pvsToUse;
}
}
}

As you can see, here is another call InstantiationAwareBeanPostProcessor Type of postProcessProperties and postProcessPropertyValues Method , The latter is the implementation in the old version , Has been abandoned , So just look postProcessProperties, Or into AutowiredAnnotationBeanPostProcessor Class :

 public PropertyValues postProcessProperties(PropertyValues pvs, Object bean, String beanName) {

InjectionMetadata metadata = findAutowiringMetadata(beanName, bean.getClass(), pvs);
try {

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;
}

findAutowiringMetadata This method is not strange , Just analyzed , Is to collect the corresponding annotations and encapsulate them as InjectionMetadata Put the object into the cache , Here is the value from the cache , Injection is through inject Realized :

public void inject(Object target, @Nullable String beanName, @Nullable PropertyValues pvs) throws Throwable {

Collection<InjectedElement> checkedElements = this.checkedElements;
Collection<InjectedElement> elementsToIterate =
(checkedElements != null ? checkedElements : this.injectedElements);
if (!elementsToIterate.isEmpty()) {

for (InjectedElement element : elementsToIterate) {

if (logger.isTraceEnabled()) {

logger.trace("Processing injected element of bean '" + beanName + "': " + element);
}
if(element.isField) {

Field field = (Field)element.member;
System.out.println("==IOC/DI===beanName==" + beanName + "==field[" + field.getName() +"]-> getBean(" + field.getName() + ")");
}
element.inject(target, beanName, pvs);
}
}
}

Finally, call element.inject Implement Injection ,element We just saw , Namely AutowiredFieldElement and AutowiredMethodElement, Implement attribute injection and method injection respectively , Here, let's look at the most commonly used attribute Injection :

protected void inject(Object bean, @Nullable String beanName, @Nullable PropertyValues pvs) throws Throwable {

Field field = (Field) this.member;
Object value;
if (this.cached) {

value = resolvedCachedArgument(beanName, this.cachedFieldValue);
}
else {

DependencyDescriptor desc = new DependencyDescriptor(field, this.required);
desc.setContainingClass(bean.getClass());
Set<String> autowiredBeanNames = new LinkedHashSet<>(1);
Assert.state(beanFactory != null, "No BeanFactory available");
TypeConverter typeConverter = beanFactory.getTypeConverter();
try {

// Find dependent objects 
value = beanFactory.resolveDependency(desc, beanName, autowiredBeanNames, typeConverter);
}
catch (BeansException ex) {

throw new UnsatisfiedDependencyException(null, beanName, new InjectionPoint(field), ex);
}
synchronized (this) {

if (!this.cached) {

if (value != null || this.required) {

this.cachedFieldValue = desc;
registerDependentBeans(beanName, autowiredBeanNames);
if (autowiredBeanNames.size() == 1) {

String autowiredBeanName = autowiredBeanNames.iterator().next();
if (beanFactory.containsBean(autowiredBeanName) &&
beanFactory.isTypeMatch(autowiredBeanName, field.getType())) {

this.cachedFieldValue = new ShortcutDependencyDescriptor(
desc, autowiredBeanName, field.getType());
}
}
}
else {

this.cachedFieldValue = null;
}
this.cached = true;
}
}
}
if (value != null) {

ReflectionUtils.makeAccessible(field);
field.set(bean, value);
}
}

The overall logic of this code is relatively clear , First of all, according to the field Create an abstraction of dependent objects DependencyDescriptor object , And then through beanFactory.resolveDependency Analyze and get the corresponding instance , Finally, it can be injected by reflection . So we mainly look at resolveDependency What has been done in the method :

public Object resolveDependency(DependencyDescriptor descriptor, @Nullable String requestingBeanName,
@Nullable Set<String> 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 Jsr330Factory().createDependencyProvider(descriptor, requestingBeanName);
}
else {

Object result = getAutowireCandidateResolver().getLazyResolutionProxyIfNecessary(
descriptor, requestingBeanName);
if (result == null) {

result = doResolveDependency(descriptor, requestingBeanName, autowiredBeanNames, typeConverter);
}
return result;
}
}

In general , Are walking else Branch and call doResolveDependency Method :

public Object doResolveDependency(DependencyDescriptor descriptor, @Nullable String beanName,
@Nullable Set<String> autowiredBeanNames, @Nullable TypeConverter typeConverter) throws BeansException {

InjectionPoint previousInjectionPoint = ConstructorResolver.setCurrentInjectionPoint(descriptor);
try {

Object shortcut = descriptor.resolveShortcut(this);
if (shortcut != null) {

return shortcut;
}
Class<?> type = descriptor.getDependencyType();
Object value = getAutowireCandidateResolver().getSuggestedValue(descriptor);
if (value != null) {

if (value instanceof String) {

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()));
}
// There are multiple implementation classes that need to be injected , Specifically refers to the injection of an array 、 Set or Map
Object multipleBeans = resolveMultipleBeans(descriptor, beanName, autowiredBeanNames, typeConverter);
if (multipleBeans != null) {

return multipleBeans;
}
// Find all implementation classes of dependent objects 
Map<String, Object> matchingBeans = findAutowireCandidates(beanName, type, descriptor);
if (matchingBeans.isEmpty()) {

if (isRequired(descriptor)) {

raiseNoMatchingBeanFound(type, descriptor.getResolvableType(), descriptor);
}
return null;
}
String autowiredBeanName;
Object instanceCandidate;
// The dependent object has multiple instances 
if (matchingBeans.size() > 1) {

// according to @Primary、@Priority And names in turn 
autowiredBeanName = determineAutowireCandidate(matchingBeans, descriptor);
if (autowiredBeanName == null) {

if (isRequired(descriptor) || !indicatesMultipleBeans(type)) {

return descriptor.resolveNotUnique(descriptor.getResolvableType(), 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 you get class object , adopt getBean Instantiation return 
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);
}
}

First of all, through getAutowireCandidateResolver().getSuggestedValue(descriptor) Get @Value The value of the annotation , And then through TypeConverter convert , The default convertible type is JDK and Spring Some built-in types , Naturally, it does not include our custom classes , So if you don't extend it, you can do it in @Autowired When injecting our custom class objects, we use @Value Comments will report errors .
Then there's the call resolveMultipleBeans Method implementation Map、List、 Injection of attributes such as arrays , In essence, call findAutowireCandidates Method to find all the objects of the implementation class and load them into the corresponding collection array , So just look findAutowireCandidates

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

String[] candidateNames = BeanFactoryUtils.beanNamesForTypeIncludingAncestors(
this, requiredType, true, descriptor.isEager());
Map<String, Object> result = new LinkedHashMap<>(candidateNames.length);
......
for (String candidate : candidateNames) {

if (!isSelfReference(beanName, candidate) && isAutowireCandidate(candidate, descriptor)) {

addCandidateEntry(result, candidate, descriptor, requiredType);
}
}
......
return result;
}
private void addCandidateEntry(Map<String, Object> candidates, String candidateName,
DependencyDescriptor descriptor, Class<?> requiredType) {

if (descriptor instanceof MultiElementDescriptor) {

Object beanInstance = descriptor.resolveCandidate(candidateName, requiredType, this);
if (!(beanInstance instanceof NullBean)) {

candidates.put(candidateName, beanInstance);
}
}
else if (containsSingleton(candidateName) || (descriptor instanceof StreamDependencyDescriptor &&
((StreamDependencyDescriptor) descriptor).isOrdered())) {

Object beanInstance = descriptor.resolveCandidate(candidateName, requiredType, this);
candidates.put(candidateName, (beanInstance instanceof NullBean ? null : beanInstance));
}
else {

candidates.put(candidateName, getType(candidateName));
}
}

First, through beanNamesForTypeIncludingAncestors Method to get all the implementation classes of the dependent class beanName, And then call addCandidateEntry take beanName And the corresponding example perhaps Class The object is put into Map in .
Then go back to doResolveDependency In the method :

if (matchingBeans.size() > 1) {

// according to @Primary、@Priority And names in turn 
autowiredBeanName = determineAutowireCandidate(matchingBeans, descriptor);
if (autowiredBeanName == null) {

if (isRequired(descriptor) || !indicatesMultipleBeans(type)) {

return descriptor.resolveNotUnique(descriptor.getResolvableType(), 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 you get class object , adopt getBean Instantiation return 
if (instanceCandidate instanceof Class) {

instanceCandidate = descriptor.resolveCandidate(autowiredBeanName, type, this);
}
Object result = instanceCandidate;

If there is only one instance, the instance is returned directly , If there are multiple implementation classes, call determineAutowireCandidate To determine which instance object to use , The rules are as follows :

  • First, judge whether there is @Primary annotation , If one is found, the current instance will be returned , If more than one is found, an error will be reported .
  • If there is no sign @Primary annotation , Then determine whether the priority is specified , And only through @Priority The note specifies ,@Order I won't support it .
  • None of the above has got the right Bean Then get... By property name Bean.

After getting the corresponding instance , Finally, reflection injection can . That's all @Autowired Implementation details .

summary

This article analyzes in detail from the perspective of source code @Autowired Implementation details , Only by really reading the source code can we know more details , In development, it is more clear how to inject multiple instances and how to specify the priority of Injection , At the same time, it can be more reasonable in the interview , Instead of a unified public answer , First, according to byType, According to byName. In addition, for method injection and @Resource The handling of annotations is not covered in this article , But I believe that after reading this article, readers can easily analyze this part of the source code .

copyright:author[Don't talk at night],Please bring the original link to reprint, thank you. https://en.javamana.com/2022/02/202202130725454129.html