diff --git a/spring-beans/src/main/java/org/springframework/beans/factory/annotation/AutowiredAnnotationBeanPostProcessor.java b/spring-beans/src/main/java/org/springframework/beans/factory/annotation/AutowiredAnnotationBeanPostProcessor.java
index 10a0dc76fc0..3848510f98f 100644
--- a/spring-beans/src/main/java/org/springframework/beans/factory/annotation/AutowiredAnnotationBeanPostProcessor.java
+++ b/spring-beans/src/main/java/org/springframework/beans/factory/annotation/AutowiredAnnotationBeanPostProcessor.java
@@ -51,7 +51,6 @@ import org.springframework.beans.factory.UnsatisfiedDependencyException;
import org.springframework.beans.factory.config.ConfigurableListableBeanFactory;
import org.springframework.beans.factory.config.DependencyDescriptor;
import org.springframework.beans.factory.config.InstantiationAwareBeanPostProcessorAdapter;
-import org.springframework.beans.factory.config.RuntimeBeanReference;
import org.springframework.beans.factory.support.LookupOverride;
import org.springframework.beans.factory.support.MergedBeanDefinitionPostProcessor;
import org.springframework.beans.factory.support.RootBeanDefinition;
@@ -529,9 +528,6 @@ public class AutowiredAnnotationBeanPostProcessor extends InstantiationAwareBean
DependencyDescriptor descriptor = (DependencyDescriptor) cachedArgument;
return this.beanFactory.resolveDependency(descriptor, beanName, null, null);
}
- else if (cachedArgument instanceof RuntimeBeanReference) {
- return this.beanFactory.getBean(((RuntimeBeanReference) cachedArgument).getBeanName());
- }
else {
return cachedArgument;
}
@@ -581,7 +577,7 @@ public class AutowiredAnnotationBeanPostProcessor extends InstantiationAwareBean
String autowiredBeanName = autowiredBeanNames.iterator().next();
if (beanFactory.containsBean(autowiredBeanName)) {
if (beanFactory.isTypeMatch(autowiredBeanName, field.getType())) {
- this.cachedFieldValue = new RuntimeBeanReference(autowiredBeanName);
+ this.cachedFieldValue = new ShortcutDependencyDescriptor(desc, autowiredBeanName);
}
}
}
@@ -665,7 +661,8 @@ public class AutowiredAnnotationBeanPostProcessor extends InstantiationAwareBean
String autowiredBeanName = it.next();
if (beanFactory.containsBean(autowiredBeanName)) {
if (beanFactory.isTypeMatch(autowiredBeanName, paramTypes[i])) {
- this.cachedMethodArguments[i] = new RuntimeBeanReference(autowiredBeanName);
+ this.cachedMethodArguments[i] =
+ new ShortcutDependencyDescriptor(descriptors[i], autowiredBeanName);
}
}
}
@@ -701,4 +698,24 @@ public class AutowiredAnnotationBeanPostProcessor extends InstantiationAwareBean
}
}
+
+ /**
+ * DependencyDescriptor variant with a pre-resolved target bean name.
+ */
+ @SuppressWarnings("serial")
+ private static class ShortcutDependencyDescriptor extends DependencyDescriptor {
+
+ private final String shortcutBeanName;
+
+ public ShortcutDependencyDescriptor(DependencyDescriptor original, String shortcutBeanName) {
+ super(original);
+ this.shortcutBeanName = shortcutBeanName;
+ }
+
+ @Override
+ public Object resolveShortcut(BeanFactory beanFactory) {
+ return resolveCandidate(this.shortcutBeanName, beanFactory);
+ }
+ }
+
}
diff --git a/spring-beans/src/main/java/org/springframework/beans/factory/config/DependencyDescriptor.java b/spring-beans/src/main/java/org/springframework/beans/factory/config/DependencyDescriptor.java
index c38deb74800..3533840635a 100644
--- a/spring-beans/src/main/java/org/springframework/beans/factory/config/DependencyDescriptor.java
+++ b/spring-beans/src/main/java/org/springframework/beans/factory/config/DependencyDescriptor.java
@@ -187,6 +187,21 @@ public class DependencyDescriptor extends InjectionPoint implements Serializable
return beanFactory.getBean(beanName);
}
+ /**
+ * Resolve a shortcut for this dependency against the given factory, for example
+ * taking some pre-resolved information into account.
+ *
The resolution algorithm will first attempt to resolve a shortcut through this
+ * method before going into the regular type matching algorithm across all beans.
+ * Subclasses may override this method to improve resolution performance based on
+ * pre-cached information while still receiving {@link InjectionPoint} exposure etc.
+ * @param beanFactory the associated factory
+ * @return the shortcut result if any, or {@code null} if none
+ * @since 4.3.1
+ */
+ public Object resolveShortcut(BeanFactory beanFactory) {
+ return null;
+ }
+
/**
* Increase this descriptor's nesting level.
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 4516cc5f01c..6205fa69cfe 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
@@ -1024,27 +1024,32 @@ public class DefaultListableBeanFactory extends AbstractAutowireCapableBeanFacto
public Object doResolveDependency(DependencyDescriptor descriptor, String beanName,
Set autowiredBeanNames, TypeConverter typeConverter) throws BeansException {
- 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()));
- }
-
- Object multipleBeans = resolveMultipleBeans(descriptor, beanName, autowiredBeanNames, typeConverter);
- if (multipleBeans != null) {
- return multipleBeans;
- }
-
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()));
+ }
+
+ Object multipleBeans = resolveMultipleBeans(descriptor, beanName, autowiredBeanNames, typeConverter);
+ if (multipleBeans != null) {
+ return multipleBeans;
+ }
+
Map matchingBeans = findAutowireCandidates(beanName, type, descriptor);
if (matchingBeans.isEmpty()) {
if (descriptor.isRequired()) {
diff --git a/spring-context/src/test/java/org/springframework/context/annotation/configuration/ConfigurationClassProcessingTests.java b/spring-context/src/test/java/org/springframework/context/annotation/configuration/ConfigurationClassProcessingTests.java
index 498453338e7..bf4c9e6a9eb 100644
--- a/spring-context/src/test/java/org/springframework/context/annotation/configuration/ConfigurationClassProcessingTests.java
+++ b/spring-context/src/test/java/org/springframework/context/annotation/configuration/ConfigurationClassProcessingTests.java
@@ -31,9 +31,7 @@ import org.springframework.beans.factory.InjectionPoint;
import org.springframework.beans.factory.ListableBeanFactory;
import org.springframework.beans.factory.NoSuchBeanDefinitionException;
import org.springframework.beans.factory.annotation.Autowired;
-import org.springframework.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor;
import org.springframework.beans.factory.annotation.Qualifier;
-import org.springframework.beans.factory.annotation.QualifierAnnotationAutowireCandidateResolver;
import org.springframework.beans.factory.annotation.Required;
import org.springframework.beans.factory.annotation.RequiredAnnotationBeanPostProcessor;
import org.springframework.beans.factory.annotation.Value;
@@ -210,16 +208,17 @@ public class ConfigurationClassProcessingTests {
@Test
public void configurationWithAdaptivePrototypes() {
- DefaultListableBeanFactory factory =
- initBeanFactory(ConfigWithPrototypeBean.class, AdaptiveInjectionPoints.class);
- AutowiredAnnotationBeanPostProcessor aabpp = new AutowiredAnnotationBeanPostProcessor();
- aabpp.setBeanFactory(factory);
- factory.setAutowireCandidateResolver(new QualifierAnnotationAutowireCandidateResolver());
- factory.addBeanPostProcessor(aabpp);
+ AnnotationConfigApplicationContext factory = new AnnotationConfigApplicationContext();
+ factory.register(ConfigWithPrototypeBean.class, AdaptiveInjectionPoints.class);
+ factory.refresh();
AdaptiveInjectionPoints adaptive = factory.getBean(AdaptiveInjectionPoints.class);
assertEquals("adaptiveInjectionPoint1", adaptive.adaptiveInjectionPoint1.getName());
- assertEquals("adaptiveInjectionPoint2", adaptive.adaptiveInjectionPoint2.getName());
+ assertEquals("setAdaptiveInjectionPoint2", adaptive.adaptiveInjectionPoint2.getName());
+
+ adaptive = factory.getBean(AdaptiveInjectionPoints.class);
+ assertEquals("adaptiveInjectionPoint1", adaptive.adaptiveInjectionPoint1.getName());
+ assertEquals("setAdaptiveInjectionPoint2", adaptive.adaptiveInjectionPoint2.getName());
}
@Test
@@ -357,13 +356,18 @@ public class ConfigurationClassProcessingTests {
}
+ @Scope("prototype")
static class AdaptiveInjectionPoints {
@Autowired @Qualifier("adaptive1")
public TestBean adaptiveInjectionPoint1;
- @Autowired @Qualifier("adaptive2")
public TestBean adaptiveInjectionPoint2;
+
+ @Autowired @Qualifier("adaptive2")
+ public void setAdaptiveInjectionPoint2(TestBean adaptiveInjectionPoint2) {
+ this.adaptiveInjectionPoint2 = adaptiveInjectionPoint2;
+ }
}