From a001319f1f5789e7c9987d79574bdf3e49f1027d Mon Sep 17 00:00:00 2001 From: Juergen Hoeller Date: Mon, 19 Feb 2024 22:39:37 +0100 Subject: [PATCH] Add additional shortcut for qualifier value matching target bean name Closes gh-17677 See gh-28122 --- ...erAnnotationAutowireCandidateResolver.java | 20 +++++++++++-- .../support/AutowireCandidateResolver.java | 14 +++++++++- .../support/DefaultListableBeanFactory.java | 28 +++++++++++++++---- .../SimpleAutowireCandidateResolver.java | 8 +++++- 4 files changed, 59 insertions(+), 11 deletions(-) diff --git a/spring-beans/src/main/java/org/springframework/beans/factory/annotation/QualifierAnnotationAutowireCandidateResolver.java b/spring-beans/src/main/java/org/springframework/beans/factory/annotation/QualifierAnnotationAutowireCandidateResolver.java index 2f0b6bc2a09c..940ce0207df6 100644 --- a/spring-beans/src/main/java/org/springframework/beans/factory/annotation/QualifierAnnotationAutowireCandidateResolver.java +++ b/spring-beans/src/main/java/org/springframework/beans/factory/annotation/QualifierAnnotationAutowireCandidateResolver.java @@ -282,7 +282,7 @@ protected boolean checkQualifier( } if (actualValue == null && attributeName.equals(AutowireCandidateQualifier.VALUE_KEY) && expectedValue instanceof String name && bdHolder.matchesName(name)) { - // Fall back on bean name (or alias) match + // Finally, check bean name (or alias) match continue; } if (actualValue == null && qualifier != null) { @@ -333,14 +333,28 @@ public boolean isRequired(DependencyDescriptor descriptor) { */ @Override public boolean hasQualifier(DependencyDescriptor descriptor) { - for (Annotation ann : descriptor.getAnnotations()) { - if (isQualifier(ann.annotationType())) { + for (Annotation annotation : descriptor.getAnnotations()) { + if (isQualifier(annotation.annotationType())) { return true; } } 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. * @see Value diff --git a/spring-beans/src/main/java/org/springframework/beans/factory/support/AutowireCandidateResolver.java b/spring-beans/src/main/java/org/springframework/beans/factory/support/AutowireCandidateResolver.java index e7eafe4158c8..d69daa2e4118 100644 --- a/spring-beans/src/main/java/org/springframework/beans/factory/support/AutowireCandidateResolver.java +++ b/spring-beans/src/main/java/org/springframework/beans/factory/support/AutowireCandidateResolver.java @@ -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"); * you may not use this file except in compliance with the License. @@ -72,6 +72,18 @@ default boolean hasQualifier(DependencyDescriptor descriptor) { 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. *

The default implementation simply returns {@code null}. diff --git a/spring-beans/src/main/java/org/springframework/beans/factory/support/DefaultListableBeanFactory.java b/spring-beans/src/main/java/org/springframework/beans/factory/support/DefaultListableBeanFactory.java index e71a526d8561..0bcd895f7f62 100644 --- a/spring-beans/src/main/java/org/springframework/beans/factory/support/DefaultListableBeanFactory.java +++ b/spring-beans/src/main/java/org/springframework/beans/factory/support/DefaultListableBeanFactory.java @@ -1400,9 +1400,13 @@ public Object doResolveDependency(DependencyDescriptor descriptor, @Nullable Str } } - // 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(); - 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) && !hasPrimaryConflict(dependencyName, type) && !isSelfReference(beanName, dependencyName)) { if (autowiredBeanNames != null) { @@ -1747,10 +1751,22 @@ protected String determineAutowireCandidate(Map candidates, Depe if (primaryCandidate != null) { return primaryCandidate; } - // Step 2: check bean name match - for (String candidateName : candidates.keySet()) { - if (matchesBeanName(candidateName, descriptor.getDependencyName())) { - return candidateName; + // Step 2a: match bean name against declared dependency name + String dependencyName = descriptor.getDependencyName(); + if (dependencyName != null) { + 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 diff --git a/spring-beans/src/main/java/org/springframework/beans/factory/support/SimpleAutowireCandidateResolver.java b/spring-beans/src/main/java/org/springframework/beans/factory/support/SimpleAutowireCandidateResolver.java index 2afdf73924a4..1c7e3cb808c9 100644 --- a/spring-beans/src/main/java/org/springframework/beans/factory/support/SimpleAutowireCandidateResolver.java +++ b/spring-beans/src/main/java/org/springframework/beans/factory/support/SimpleAutowireCandidateResolver.java @@ -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"); * you may not use this file except in compliance with the License. @@ -52,6 +52,12 @@ public boolean hasQualifier(DependencyDescriptor descriptor) { return false; } + @Override + @Nullable + public String getSuggestedName(DependencyDescriptor descriptor) { + return null; + } + @Override @Nullable public Object getSuggestedValue(DependencyDescriptor descriptor) {