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:
parent
2f9a775a8e
commit
ac5933a7ac
|
@ -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));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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");
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
||||
|
||||
|
|
Loading…
Reference in New Issue