Various DefaultListableBeanFactory clarifications

* getBeanDefinitionNames defensively returns a copy of the bean definition names array.
* copyConfigurationFrom provides an independent AutowireCandidateResolver instance and copies a ConversionService and dependency comparator configuration as well.
* findAutowireCandidates only considers a self reference fallback for direct dependency declarations, not as a collection element.

Issue: SPR-14897
Issue: SPR-14921
Issue: SPR-14965
This commit is contained in:
Juergen Hoeller 2016-11-30 22:07:55 +01:00
parent 2f9a775a8e
commit ac5933a7ac
4 changed files with 93 additions and 19 deletions

View File

@ -131,16 +131,14 @@ public abstract class AbstractBeanFactory extends FactoryBeanRegistrySupport imp
private ConversionService conversionService;
/** Custom PropertyEditorRegistrars to apply to the beans of this factory */
private final Set<PropertyEditorRegistrar> propertyEditorRegistrars =
new LinkedHashSet<>(4);
private final Set<PropertyEditorRegistrar> propertyEditorRegistrars = new LinkedHashSet<>(4);
/** Custom PropertyEditors to apply to the beans of this factory */
private final Map<Class<?>, Class<? extends PropertyEditor>> customEditors = new HashMap<>(4);
/** A custom TypeConverter to use, overriding the default PropertyEditor mechanism */
private TypeConverter typeConverter;
/** Custom PropertyEditors to apply to the beans of this factory */
private final Map<Class<?>, Class<? extends PropertyEditor>> customEditors =
new HashMap<>(4);
/** String resolvers to apply e.g. to annotation attribute values */
private final List<StringValueResolver> embeddedValueResolvers = new LinkedList<>();
@ -919,10 +917,12 @@ public abstract class AbstractBeanFactory extends FactoryBeanRegistrySupport imp
setBeanClassLoader(otherFactory.getBeanClassLoader());
setCacheBeanMetadata(otherFactory.isCacheBeanMetadata());
setBeanExpressionResolver(otherFactory.getBeanExpressionResolver());
setConversionService(otherFactory.getConversionService());
if (otherFactory instanceof AbstractBeanFactory) {
AbstractBeanFactory otherAbstractFactory = (AbstractBeanFactory) otherFactory;
this.customEditors.putAll(otherAbstractFactory.customEditors);
this.propertyEditorRegistrars.addAll(otherAbstractFactory.propertyEditorRegistrars);
this.customEditors.putAll(otherAbstractFactory.customEditors);
this.typeConverter = otherAbstractFactory.typeConverter;
this.beanPostProcessors.addAll(otherAbstractFactory.beanPostProcessors);
this.hasInstantiationAwareBeanPostProcessors = this.hasInstantiationAwareBeanPostProcessors ||
otherAbstractFactory.hasInstantiationAwareBeanPostProcessors;
@ -933,6 +933,10 @@ public abstract class AbstractBeanFactory extends FactoryBeanRegistrySupport imp
}
else {
setTypeConverter(otherFactory.getTypeConverter());
String[] otherScopeNames = otherFactory.getRegisteredScopeNames();
for (String scopeName : otherScopeNames) {
this.scopes.put(scopeName, otherFactory.getRegisteredScope(scopeName));
}
}
}

View File

@ -43,6 +43,7 @@ import java.util.Set;
import java.util.concurrent.ConcurrentHashMap;
import javax.inject.Provider;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.BeansException;
import org.springframework.beans.TypeConverter;
import org.springframework.beans.factory.BeanCreationException;
@ -256,6 +257,7 @@ public class DefaultListableBeanFactory extends AbstractAutowireCapableBeanFacto
/**
* Set a {@link java.util.Comparator} for dependency Lists and arrays.
* @since 4.0
* @see org.springframework.core.OrderComparator
* @see org.springframework.core.annotation.AnnotationAwareOrderComparator
*/
@ -265,6 +267,7 @@ public class DefaultListableBeanFactory extends AbstractAutowireCapableBeanFacto
/**
* Return the dependency comparator for this BeanFactory (may be {@code null}.
* @since 4.0
*/
public Comparator<Object> getDependencyComparator() {
return this.dependencyComparator;
@ -279,11 +282,10 @@ public class DefaultListableBeanFactory extends AbstractAutowireCapableBeanFacto
Assert.notNull(autowireCandidateResolver, "AutowireCandidateResolver must not be null");
if (autowireCandidateResolver instanceof BeanFactoryAware) {
if (System.getSecurityManager() != null) {
final BeanFactory target = this;
AccessController.doPrivileged(new PrivilegedAction<Object>() {
@Override
public Object run() {
((BeanFactoryAware) autowireCandidateResolver).setBeanFactory(target);
((BeanFactoryAware) autowireCandidateResolver).setBeanFactory(DefaultListableBeanFactory.this);
return null;
}
}, getAccessControlContext());
@ -310,7 +312,10 @@ public class DefaultListableBeanFactory extends AbstractAutowireCapableBeanFacto
DefaultListableBeanFactory otherListableFactory = (DefaultListableBeanFactory) otherFactory;
this.allowBeanDefinitionOverriding = otherListableFactory.allowBeanDefinitionOverriding;
this.allowEagerClassLoading = otherListableFactory.allowEagerClassLoading;
this.autowireCandidateResolver = otherListableFactory.autowireCandidateResolver;
this.dependencyComparator = otherListableFactory.dependencyComparator;
// A clone of the AutowireCandidateResolver since it is potentially BeanFactoryAware...
setAutowireCandidateResolver(BeanUtils.instantiateClass(getAutowireCandidateResolver().getClass()));
// Make resolvable dependencies (e.g. ResourceLoader) available here as well...
this.resolvableDependencies.putAll(otherListableFactory.resolvableDependencies);
}
}
@ -357,7 +362,7 @@ public class DefaultListableBeanFactory extends AbstractAutowireCapableBeanFacto
@Override
public String[] getBeanDefinitionNames() {
if (this.frozenBeanDefinitionNames != null) {
return this.frozenBeanDefinitionNames;
return this.frozenBeanDefinitionNames.clone();
}
else {
return StringUtils.toStringArray(this.beanDefinitionNames);
@ -1256,8 +1261,9 @@ public class DefaultListableBeanFactory extends AbstractAutowireCapableBeanFacto
addCandidateEntry(result, candidateName, descriptor, requiredType);
}
}
if (result.isEmpty()) {
// Consider self references before as a final pass
if (result.isEmpty() && !(descriptor instanceof MultiElementDependencyDescriptor)) {
// Consider self references as a final pass...
// but not as collection elements, just for direct dependency declarations.
for (String candidateName : candidateNames) {
if (isSelfReference(beanName, candidateName) && isAutowireCandidate(candidateName, fallbackDescriptor)) {
addCandidateEntry(result, candidateName, descriptor, requiredType);
@ -1466,10 +1472,10 @@ public class DefaultListableBeanFactory extends AbstractAutowireCapableBeanFacto
Class<?> targetType = mbd.getTargetType();
if (targetType != null && type.isAssignableFrom(targetType) &&
isAutowireCandidate(beanName, mbd, descriptor, getAutowireCandidateResolver())) {
// Probably a poxy interfering with target type match -> throw meaningful exception.
// Probably a proxy interfering with target type match -> throw meaningful exception.
Object beanInstance = getSingleton(beanName, false);
Class<?> beanType = (beanInstance != null ? beanInstance.getClass() : predictBeanType(beanName, mbd));
if (type != beanType) {
if (!type.isAssignableFrom((beanType))) {
throw new BeanNotOfRequiredTypeException(beanName, type, beanType);
}
}

View File

@ -776,6 +776,7 @@ public class DefaultListableBeanFactoryTests {
private void testSingleTestBean(ListableBeanFactory lbf) {
assertTrue("1 beans defined", lbf.getBeanDefinitionCount() == 1);
String[] names = lbf.getBeanDefinitionNames();
assertTrue(names != lbf.getBeanDefinitionNames());
assertTrue("Array length == 1", names.length == 1);
assertTrue("0th element == test", names[0].equals("test"));
TestBean tb = (TestBean) lbf.getBean("test");

View File

@ -29,6 +29,7 @@ import java.util.HashMap;
import java.util.HashSet;
import java.util.LinkedHashMap;
import java.util.LinkedHashSet;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;
import java.util.Properties;
@ -978,11 +979,59 @@ public class AutowiredAnnotationBeanPostProcessorTests {
AutowiredAnnotationBeanPostProcessor bpp = new AutowiredAnnotationBeanPostProcessor();
bpp.setBeanFactory(bf);
bf.addBeanPostProcessor(bpp);
RootBeanDefinition bd = new RootBeanDefinition(SelfInjectionBean.class);
bf.registerBeanDefinition("annotatedBean", bd);
bf.registerBeanDefinition("annotatedBean", new RootBeanDefinition(SelfInjectionBean.class));
SelfInjectionBean bean = (SelfInjectionBean) bf.getBean("annotatedBean");
assertSame(bean, bean.selfReference);
assertSame(bean, bean.reference);
assertNull(bean.referenceCollection);
}
@Test
public void testSelfReferenceWithOther() {
DefaultListableBeanFactory bf = new DefaultListableBeanFactory();
bf.setAutowireCandidateResolver(new QualifierAnnotationAutowireCandidateResolver());
AutowiredAnnotationBeanPostProcessor bpp = new AutowiredAnnotationBeanPostProcessor();
bpp.setBeanFactory(bf);
bf.addBeanPostProcessor(bpp);
bf.registerBeanDefinition("annotatedBean", new RootBeanDefinition(SelfInjectionBean.class));
bf.registerBeanDefinition("annotatedBean2", new RootBeanDefinition(SelfInjectionBean.class));
SelfInjectionBean bean = (SelfInjectionBean) bf.getBean("annotatedBean");
SelfInjectionBean bean2 = (SelfInjectionBean) bf.getBean("annotatedBean2");
assertSame(bean2, bean.reference);
assertEquals(1, bean.referenceCollection.size());
assertSame(bean2, bean.referenceCollection.get(0));
}
@Test
public void testSelfReferenceCollection() {
DefaultListableBeanFactory bf = new DefaultListableBeanFactory();
bf.setAutowireCandidateResolver(new QualifierAnnotationAutowireCandidateResolver());
AutowiredAnnotationBeanPostProcessor bpp = new AutowiredAnnotationBeanPostProcessor();
bpp.setBeanFactory(bf);
bf.addBeanPostProcessor(bpp);
bf.registerBeanDefinition("annotatedBean", new RootBeanDefinition(SelfInjectionCollectionBean.class));
SelfInjectionCollectionBean bean = (SelfInjectionCollectionBean) bf.getBean("annotatedBean");
assertSame(bean, bean.reference);
assertNull(bean.referenceCollection);
}
@Test
public void testSelfReferenceCollectionWithOther() {
DefaultListableBeanFactory bf = new DefaultListableBeanFactory();
bf.setAutowireCandidateResolver(new QualifierAnnotationAutowireCandidateResolver());
AutowiredAnnotationBeanPostProcessor bpp = new AutowiredAnnotationBeanPostProcessor();
bpp.setBeanFactory(bf);
bf.addBeanPostProcessor(bpp);
bf.registerBeanDefinition("annotatedBean", new RootBeanDefinition(SelfInjectionCollectionBean.class));
bf.registerBeanDefinition("annotatedBean2", new RootBeanDefinition(SelfInjectionCollectionBean.class));
SelfInjectionCollectionBean bean = (SelfInjectionCollectionBean) bf.getBean("annotatedBean");
SelfInjectionCollectionBean bean2 = (SelfInjectionCollectionBean) bf.getBean("annotatedBean2");
assertSame(bean2, bean.reference);
assertSame(1, bean2.referenceCollection.size());
assertSame(bean2, bean.referenceCollection.get(0));
}
@Test
@ -2582,7 +2631,21 @@ public class AutowiredAnnotationBeanPostProcessorTests {
public static class SelfInjectionBean {
@Autowired
public SelfInjectionBean selfReference;
public SelfInjectionBean reference;
@Autowired(required = false)
public List<SelfInjectionBean> referenceCollection;
}
@SuppressWarnings("serial")
public static class SelfInjectionCollectionBean extends LinkedList<SelfInjectionCollectionBean> {
@Autowired
public SelfInjectionCollectionBean reference;
@Autowired(required = false)
public List<SelfInjectionCollectionBean> referenceCollection;
}