InjectionPoint propagated for shortcut bean name resolution as well
Issue: SPR-14400
This commit is contained in:
parent
4102c62734
commit
e15f7efff8
|
|
@ -51,7 +51,6 @@ import org.springframework.beans.factory.UnsatisfiedDependencyException;
|
||||||
import org.springframework.beans.factory.config.ConfigurableListableBeanFactory;
|
import org.springframework.beans.factory.config.ConfigurableListableBeanFactory;
|
||||||
import org.springframework.beans.factory.config.DependencyDescriptor;
|
import org.springframework.beans.factory.config.DependencyDescriptor;
|
||||||
import org.springframework.beans.factory.config.InstantiationAwareBeanPostProcessorAdapter;
|
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.LookupOverride;
|
||||||
import org.springframework.beans.factory.support.MergedBeanDefinitionPostProcessor;
|
import org.springframework.beans.factory.support.MergedBeanDefinitionPostProcessor;
|
||||||
import org.springframework.beans.factory.support.RootBeanDefinition;
|
import org.springframework.beans.factory.support.RootBeanDefinition;
|
||||||
|
|
@ -529,9 +528,6 @@ public class AutowiredAnnotationBeanPostProcessor extends InstantiationAwareBean
|
||||||
DependencyDescriptor descriptor = (DependencyDescriptor) cachedArgument;
|
DependencyDescriptor descriptor = (DependencyDescriptor) cachedArgument;
|
||||||
return this.beanFactory.resolveDependency(descriptor, beanName, null, null);
|
return this.beanFactory.resolveDependency(descriptor, beanName, null, null);
|
||||||
}
|
}
|
||||||
else if (cachedArgument instanceof RuntimeBeanReference) {
|
|
||||||
return this.beanFactory.getBean(((RuntimeBeanReference) cachedArgument).getBeanName());
|
|
||||||
}
|
|
||||||
else {
|
else {
|
||||||
return cachedArgument;
|
return cachedArgument;
|
||||||
}
|
}
|
||||||
|
|
@ -581,7 +577,7 @@ public class AutowiredAnnotationBeanPostProcessor extends InstantiationAwareBean
|
||||||
String autowiredBeanName = autowiredBeanNames.iterator().next();
|
String autowiredBeanName = autowiredBeanNames.iterator().next();
|
||||||
if (beanFactory.containsBean(autowiredBeanName)) {
|
if (beanFactory.containsBean(autowiredBeanName)) {
|
||||||
if (beanFactory.isTypeMatch(autowiredBeanName, field.getType())) {
|
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();
|
String autowiredBeanName = it.next();
|
||||||
if (beanFactory.containsBean(autowiredBeanName)) {
|
if (beanFactory.containsBean(autowiredBeanName)) {
|
||||||
if (beanFactory.isTypeMatch(autowiredBeanName, paramTypes[i])) {
|
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);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -187,6 +187,21 @@ public class DependencyDescriptor extends InjectionPoint implements Serializable
|
||||||
return beanFactory.getBean(beanName);
|
return beanFactory.getBean(beanName);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Resolve a shortcut for this dependency against the given factory, for example
|
||||||
|
* taking some pre-resolved information into account.
|
||||||
|
* <p>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.
|
* Increase this descriptor's nesting level.
|
||||||
|
|
|
||||||
|
|
@ -1024,27 +1024,32 @@ public class DefaultListableBeanFactory extends AbstractAutowireCapableBeanFacto
|
||||||
public Object doResolveDependency(DependencyDescriptor descriptor, String beanName,
|
public Object doResolveDependency(DependencyDescriptor descriptor, String beanName,
|
||||||
Set<String> autowiredBeanNames, TypeConverter typeConverter) throws BeansException {
|
Set<String> 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);
|
InjectionPoint previousInjectionPoint = ConstructorResolver.setCurrentInjectionPoint(descriptor);
|
||||||
try {
|
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<String, Object> matchingBeans = findAutowireCandidates(beanName, type, descriptor);
|
Map<String, Object> matchingBeans = findAutowireCandidates(beanName, type, descriptor);
|
||||||
if (matchingBeans.isEmpty()) {
|
if (matchingBeans.isEmpty()) {
|
||||||
if (descriptor.isRequired()) {
|
if (descriptor.isRequired()) {
|
||||||
|
|
|
||||||
|
|
@ -31,9 +31,7 @@ import org.springframework.beans.factory.InjectionPoint;
|
||||||
import org.springframework.beans.factory.ListableBeanFactory;
|
import org.springframework.beans.factory.ListableBeanFactory;
|
||||||
import org.springframework.beans.factory.NoSuchBeanDefinitionException;
|
import org.springframework.beans.factory.NoSuchBeanDefinitionException;
|
||||||
import org.springframework.beans.factory.annotation.Autowired;
|
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.Qualifier;
|
||||||
import org.springframework.beans.factory.annotation.QualifierAnnotationAutowireCandidateResolver;
|
|
||||||
import org.springframework.beans.factory.annotation.Required;
|
import org.springframework.beans.factory.annotation.Required;
|
||||||
import org.springframework.beans.factory.annotation.RequiredAnnotationBeanPostProcessor;
|
import org.springframework.beans.factory.annotation.RequiredAnnotationBeanPostProcessor;
|
||||||
import org.springframework.beans.factory.annotation.Value;
|
import org.springframework.beans.factory.annotation.Value;
|
||||||
|
|
@ -210,16 +208,17 @@ public class ConfigurationClassProcessingTests {
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void configurationWithAdaptivePrototypes() {
|
public void configurationWithAdaptivePrototypes() {
|
||||||
DefaultListableBeanFactory factory =
|
AnnotationConfigApplicationContext factory = new AnnotationConfigApplicationContext();
|
||||||
initBeanFactory(ConfigWithPrototypeBean.class, AdaptiveInjectionPoints.class);
|
factory.register(ConfigWithPrototypeBean.class, AdaptiveInjectionPoints.class);
|
||||||
AutowiredAnnotationBeanPostProcessor aabpp = new AutowiredAnnotationBeanPostProcessor();
|
factory.refresh();
|
||||||
aabpp.setBeanFactory(factory);
|
|
||||||
factory.setAutowireCandidateResolver(new QualifierAnnotationAutowireCandidateResolver());
|
|
||||||
factory.addBeanPostProcessor(aabpp);
|
|
||||||
|
|
||||||
AdaptiveInjectionPoints adaptive = factory.getBean(AdaptiveInjectionPoints.class);
|
AdaptiveInjectionPoints adaptive = factory.getBean(AdaptiveInjectionPoints.class);
|
||||||
assertEquals("adaptiveInjectionPoint1", adaptive.adaptiveInjectionPoint1.getName());
|
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
|
@Test
|
||||||
|
|
@ -357,13 +356,18 @@ public class ConfigurationClassProcessingTests {
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@Scope("prototype")
|
||||||
static class AdaptiveInjectionPoints {
|
static class AdaptiveInjectionPoints {
|
||||||
|
|
||||||
@Autowired @Qualifier("adaptive1")
|
@Autowired @Qualifier("adaptive1")
|
||||||
public TestBean adaptiveInjectionPoint1;
|
public TestBean adaptiveInjectionPoint1;
|
||||||
|
|
||||||
@Autowired @Qualifier("adaptive2")
|
|
||||||
public TestBean adaptiveInjectionPoint2;
|
public TestBean adaptiveInjectionPoint2;
|
||||||
|
|
||||||
|
@Autowired @Qualifier("adaptive2")
|
||||||
|
public void setAdaptiveInjectionPoint2(TestBean adaptiveInjectionPoint2) {
|
||||||
|
this.adaptiveInjectionPoint2 = adaptiveInjectionPoint2;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue