Add additional shortcut for qualifier value matching target bean name

Closes gh-17677
See gh-28122
This commit is contained in:
Juergen Hoeller 2024-02-19 22:39:37 +01:00
parent 874e61a0c6
commit a001319f1f
4 changed files with 59 additions and 11 deletions

View File

@ -282,7 +282,7 @@ public class QualifierAnnotationAutowireCandidateResolver extends GenericTypeAwa
} }
if (actualValue == null && attributeName.equals(AutowireCandidateQualifier.VALUE_KEY) && if (actualValue == null && attributeName.equals(AutowireCandidateQualifier.VALUE_KEY) &&
expectedValue instanceof String name && bdHolder.matchesName(name)) { expectedValue instanceof String name && bdHolder.matchesName(name)) {
// Fall back on bean name (or alias) match // Finally, check bean name (or alias) match
continue; continue;
} }
if (actualValue == null && qualifier != null) { if (actualValue == null && qualifier != null) {
@ -333,14 +333,28 @@ public class QualifierAnnotationAutowireCandidateResolver extends GenericTypeAwa
*/ */
@Override @Override
public boolean hasQualifier(DependencyDescriptor descriptor) { public boolean hasQualifier(DependencyDescriptor descriptor) {
for (Annotation ann : descriptor.getAnnotations()) { for (Annotation annotation : descriptor.getAnnotations()) {
if (isQualifier(ann.annotationType())) { if (isQualifier(annotation.annotationType())) {
return true; return true;
} }
} }
return false; return false;
} }
@Override
@Nullable
public String getSuggestedName(DependencyDescriptor descriptor) {
for (Annotation annotation : descriptor.getAnnotations()) {
if (isQualifier(annotation.annotationType())) {
Object value = AnnotationUtils.getValue(annotation);
if (value instanceof String str) {
return str;
}
}
}
return null;
}
/** /**
* Determine whether the given dependency declares a value annotation. * Determine whether the given dependency declares a value annotation.
* @see Value * @see Value

View File

@ -1,5 +1,5 @@
/* /*
* Copyright 2002-2022 the original author or authors. * Copyright 2002-2024 the original author or authors.
* *
* Licensed under the Apache License, Version 2.0 (the "License"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License.
@ -72,6 +72,18 @@ public interface AutowireCandidateResolver {
return false; return false;
} }
/**
* Determine whether a target bean name is suggested for the given dependency
* (typically - but not necessarily - declared with a single-value qualifier).
* @param descriptor the descriptor for the target method parameter or field
* @return the qualifier value, if any
* @since 6.2
*/
@Nullable
default String getSuggestedName(DependencyDescriptor descriptor) {
return null;
}
/** /**
* Determine whether a default value is suggested for the given dependency. * Determine whether a default value is suggested for the given dependency.
* <p>The default implementation simply returns {@code null}. * <p>The default implementation simply returns {@code null}.

View File

@ -1400,9 +1400,13 @@ public class DefaultListableBeanFactory extends AbstractAutowireCapableBeanFacto
} }
} }
// Step 3: shortcut for declared dependency name matching target bean name // Step 3: shortcut for declared dependency name or qualifier-suggested name matching target bean name
String dependencyName = descriptor.getDependencyName(); String dependencyName = descriptor.getDependencyName();
if (dependencyName != null && containsBean(dependencyName) && if (dependencyName == null || !containsBean(dependencyName)) {
String suggestedName = getAutowireCandidateResolver().getSuggestedName(descriptor);
dependencyName = (suggestedName != null && containsBean(suggestedName) ? suggestedName : null);
}
if (dependencyName != null &&
isTypeMatch(dependencyName, type) && isAutowireCandidate(dependencyName, descriptor) && isTypeMatch(dependencyName, type) && isAutowireCandidate(dependencyName, descriptor) &&
!hasPrimaryConflict(dependencyName, type) && !isSelfReference(beanName, dependencyName)) { !hasPrimaryConflict(dependencyName, type) && !isSelfReference(beanName, dependencyName)) {
if (autowiredBeanNames != null) { if (autowiredBeanNames != null) {
@ -1747,10 +1751,22 @@ public class DefaultListableBeanFactory extends AbstractAutowireCapableBeanFacto
if (primaryCandidate != null) { if (primaryCandidate != null) {
return primaryCandidate; return primaryCandidate;
} }
// Step 2: check bean name match // Step 2a: match bean name against declared dependency name
for (String candidateName : candidates.keySet()) { String dependencyName = descriptor.getDependencyName();
if (matchesBeanName(candidateName, descriptor.getDependencyName())) { if (dependencyName != null) {
return candidateName; for (String beanName : candidates.keySet()) {
if (matchesBeanName(beanName, dependencyName)) {
return beanName;
}
}
}
// Step 2b: match bean name against qualifier-suggested name
String suggestedName = getAutowireCandidateResolver().getSuggestedName(descriptor);
if (suggestedName != null) {
for (String beanName : candidates.keySet()) {
if (matchesBeanName(beanName, suggestedName)) {
return beanName;
}
} }
} }
// Step 3: check highest priority candidate // Step 3: check highest priority candidate

View File

@ -1,5 +1,5 @@
/* /*
* Copyright 2002-2022 the original author or authors. * Copyright 2002-2024 the original author or authors.
* *
* Licensed under the Apache License, Version 2.0 (the "License"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License.
@ -52,6 +52,12 @@ public class SimpleAutowireCandidateResolver implements AutowireCandidateResolve
return false; return false;
} }
@Override
@Nullable
public String getSuggestedName(DependencyDescriptor descriptor) {
return null;
}
@Override @Override
@Nullable @Nullable
public Object getSuggestedValue(DependencyDescriptor descriptor) { public Object getSuggestedValue(DependencyDescriptor descriptor) {