InjectionPoint propagated for shortcut bean name resolution as well

Issue: SPR-14400
This commit is contained in:
Juergen Hoeller 2016-06-26 00:18:54 +02:00
parent 4102c62734
commit e15f7efff8
4 changed files with 76 additions and 35 deletions

View File

@ -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);
}
}
}

View File

@ -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.

View File

@ -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()) {

View File

@ -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;
}
}