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.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);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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.
|
||||
* <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.
|
||||
|
|
|
|||
|
|
@ -1024,27 +1024,32 @@ public class DefaultListableBeanFactory extends AbstractAutowireCapableBeanFacto
|
|||
public Object doResolveDependency(DependencyDescriptor descriptor, String beanName,
|
||||
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);
|
||||
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);
|
||||
if (matchingBeans.isEmpty()) {
|
||||
if (descriptor.isRequired()) {
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
|
|
|||
Loading…
Reference in New Issue