Skip to content

Commit ac5933a

Browse files
committed
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
1 parent 2f9a775 commit ac5933a

File tree

4 files changed

+93
-19
lines changed

4 files changed

+93
-19
lines changed

spring-beans/src/main/java/org/springframework/beans/factory/support/AbstractBeanFactory.java

+11-7
Original file line numberDiff line numberDiff line change
@@ -131,16 +131,14 @@ public abstract class AbstractBeanFactory extends FactoryBeanRegistrySupport imp
131131
private ConversionService conversionService;
132132

133133
/** Custom PropertyEditorRegistrars to apply to the beans of this factory */
134-
private final Set<PropertyEditorRegistrar> propertyEditorRegistrars =
135-
new LinkedHashSet<>(4);
134+
private final Set<PropertyEditorRegistrar> propertyEditorRegistrars = new LinkedHashSet<>(4);
135+
136+
/** Custom PropertyEditors to apply to the beans of this factory */
137+
private final Map<Class<?>, Class<? extends PropertyEditor>> customEditors = new HashMap<>(4);
136138

137139
/** A custom TypeConverter to use, overriding the default PropertyEditor mechanism */
138140
private TypeConverter typeConverter;
139141

140-
/** Custom PropertyEditors to apply to the beans of this factory */
141-
private final Map<Class<?>, Class<? extends PropertyEditor>> customEditors =
142-
new HashMap<>(4);
143-
144142
/** String resolvers to apply e.g. to annotation attribute values */
145143
private final List<StringValueResolver> embeddedValueResolvers = new LinkedList<>();
146144

@@ -919,10 +917,12 @@ public void copyConfigurationFrom(ConfigurableBeanFactory otherFactory) {
919917
setBeanClassLoader(otherFactory.getBeanClassLoader());
920918
setCacheBeanMetadata(otherFactory.isCacheBeanMetadata());
921919
setBeanExpressionResolver(otherFactory.getBeanExpressionResolver());
920+
setConversionService(otherFactory.getConversionService());
922921
if (otherFactory instanceof AbstractBeanFactory) {
923922
AbstractBeanFactory otherAbstractFactory = (AbstractBeanFactory) otherFactory;
924-
this.customEditors.putAll(otherAbstractFactory.customEditors);
925923
this.propertyEditorRegistrars.addAll(otherAbstractFactory.propertyEditorRegistrars);
924+
this.customEditors.putAll(otherAbstractFactory.customEditors);
925+
this.typeConverter = otherAbstractFactory.typeConverter;
926926
this.beanPostProcessors.addAll(otherAbstractFactory.beanPostProcessors);
927927
this.hasInstantiationAwareBeanPostProcessors = this.hasInstantiationAwareBeanPostProcessors ||
928928
otherAbstractFactory.hasInstantiationAwareBeanPostProcessors;
@@ -933,6 +933,10 @@ public void copyConfigurationFrom(ConfigurableBeanFactory otherFactory) {
933933
}
934934
else {
935935
setTypeConverter(otherFactory.getTypeConverter());
936+
String[] otherScopeNames = otherFactory.getRegisteredScopeNames();
937+
for (String scopeName : otherScopeNames) {
938+
this.scopes.put(scopeName, otherFactory.getRegisteredScope(scopeName));
939+
}
936940
}
937941
}
938942

spring-beans/src/main/java/org/springframework/beans/factory/support/DefaultListableBeanFactory.java

+14-8
Original file line numberDiff line numberDiff line change
@@ -43,6 +43,7 @@
4343
import java.util.concurrent.ConcurrentHashMap;
4444
import javax.inject.Provider;
4545

46+
import org.springframework.beans.BeanUtils;
4647
import org.springframework.beans.BeansException;
4748
import org.springframework.beans.TypeConverter;
4849
import org.springframework.beans.factory.BeanCreationException;
@@ -256,6 +257,7 @@ public boolean isAllowEagerClassLoading() {
256257

257258
/**
258259
* Set a {@link java.util.Comparator} for dependency Lists and arrays.
260+
* @since 4.0
259261
* @see org.springframework.core.OrderComparator
260262
* @see org.springframework.core.annotation.AnnotationAwareOrderComparator
261263
*/
@@ -265,6 +267,7 @@ public void setDependencyComparator(Comparator<Object> dependencyComparator) {
265267

266268
/**
267269
* Return the dependency comparator for this BeanFactory (may be {@code null}.
270+
* @since 4.0
268271
*/
269272
public Comparator<Object> getDependencyComparator() {
270273
return this.dependencyComparator;
@@ -279,11 +282,10 @@ public void setAutowireCandidateResolver(final AutowireCandidateResolver autowir
279282
Assert.notNull(autowireCandidateResolver, "AutowireCandidateResolver must not be null");
280283
if (autowireCandidateResolver instanceof BeanFactoryAware) {
281284
if (System.getSecurityManager() != null) {
282-
final BeanFactory target = this;
283285
AccessController.doPrivileged(new PrivilegedAction<Object>() {
284286
@Override
285287
public Object run() {
286-
((BeanFactoryAware) autowireCandidateResolver).setBeanFactory(target);
288+
((BeanFactoryAware) autowireCandidateResolver).setBeanFactory(DefaultListableBeanFactory.this);
287289
return null;
288290
}
289291
}, getAccessControlContext());
@@ -310,7 +312,10 @@ public void copyConfigurationFrom(ConfigurableBeanFactory otherFactory) {
310312
DefaultListableBeanFactory otherListableFactory = (DefaultListableBeanFactory) otherFactory;
311313
this.allowBeanDefinitionOverriding = otherListableFactory.allowBeanDefinitionOverriding;
312314
this.allowEagerClassLoading = otherListableFactory.allowEagerClassLoading;
313-
this.autowireCandidateResolver = otherListableFactory.autowireCandidateResolver;
315+
this.dependencyComparator = otherListableFactory.dependencyComparator;
316+
// A clone of the AutowireCandidateResolver since it is potentially BeanFactoryAware...
317+
setAutowireCandidateResolver(BeanUtils.instantiateClass(getAutowireCandidateResolver().getClass()));
318+
// Make resolvable dependencies (e.g. ResourceLoader) available here as well...
314319
this.resolvableDependencies.putAll(otherListableFactory.resolvableDependencies);
315320
}
316321
}
@@ -357,7 +362,7 @@ public int getBeanDefinitionCount() {
357362
@Override
358363
public String[] getBeanDefinitionNames() {
359364
if (this.frozenBeanDefinitionNames != null) {
360-
return this.frozenBeanDefinitionNames;
365+
return this.frozenBeanDefinitionNames.clone();
361366
}
362367
else {
363368
return StringUtils.toStringArray(this.beanDefinitionNames);
@@ -1256,8 +1261,9 @@ protected Map<String, Object> findAutowireCandidates(
12561261
addCandidateEntry(result, candidateName, descriptor, requiredType);
12571262
}
12581263
}
1259-
if (result.isEmpty()) {
1260-
// Consider self references before as a final pass
1264+
if (result.isEmpty() && !(descriptor instanceof MultiElementDependencyDescriptor)) {
1265+
// Consider self references as a final pass...
1266+
// but not as collection elements, just for direct dependency declarations.
12611267
for (String candidateName : candidateNames) {
12621268
if (isSelfReference(beanName, candidateName) && isAutowireCandidate(candidateName, fallbackDescriptor)) {
12631269
addCandidateEntry(result, candidateName, descriptor, requiredType);
@@ -1466,10 +1472,10 @@ private void checkBeanNotOfRequiredType(Class<?> type, DependencyDescriptor desc
14661472
Class<?> targetType = mbd.getTargetType();
14671473
if (targetType != null && type.isAssignableFrom(targetType) &&
14681474
isAutowireCandidate(beanName, mbd, descriptor, getAutowireCandidateResolver())) {
1469-
// Probably a poxy interfering with target type match -> throw meaningful exception.
1475+
// Probably a proxy interfering with target type match -> throw meaningful exception.
14701476
Object beanInstance = getSingleton(beanName, false);
14711477
Class<?> beanType = (beanInstance != null ? beanInstance.getClass() : predictBeanType(beanName, mbd));
1472-
if (type != beanType) {
1478+
if (!type.isAssignableFrom((beanType))) {
14731479
throw new BeanNotOfRequiredTypeException(beanName, type, beanType);
14741480
}
14751481
}

spring-beans/src/test/java/org/springframework/beans/factory/DefaultListableBeanFactoryTests.java

+1
Original file line numberDiff line numberDiff line change
@@ -776,6 +776,7 @@ public void testNameAlreadyBound() {
776776
private void testSingleTestBean(ListableBeanFactory lbf) {
777777
assertTrue("1 beans defined", lbf.getBeanDefinitionCount() == 1);
778778
String[] names = lbf.getBeanDefinitionNames();
779+
assertTrue(names != lbf.getBeanDefinitionNames());
779780
assertTrue("Array length == 1", names.length == 1);
780781
assertTrue("0th element == test", names[0].equals("test"));
781782
TestBean tb = (TestBean) lbf.getBean("test");

spring-beans/src/test/java/org/springframework/beans/factory/annotation/AutowiredAnnotationBeanPostProcessorTests.java

+67-4
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,7 @@
2929
import java.util.HashSet;
3030
import java.util.LinkedHashMap;
3131
import java.util.LinkedHashSet;
32+
import java.util.LinkedList;
3233
import java.util.List;
3334
import java.util.Map;
3435
import java.util.Properties;
@@ -978,11 +979,59 @@ public void testSelfReference() {
978979
AutowiredAnnotationBeanPostProcessor bpp = new AutowiredAnnotationBeanPostProcessor();
979980
bpp.setBeanFactory(bf);
980981
bf.addBeanPostProcessor(bpp);
981-
RootBeanDefinition bd = new RootBeanDefinition(SelfInjectionBean.class);
982-
bf.registerBeanDefinition("annotatedBean", bd);
982+
bf.registerBeanDefinition("annotatedBean", new RootBeanDefinition(SelfInjectionBean.class));
983+
984+
SelfInjectionBean bean = (SelfInjectionBean) bf.getBean("annotatedBean");
985+
assertSame(bean, bean.reference);
986+
assertNull(bean.referenceCollection);
987+
}
988+
989+
@Test
990+
public void testSelfReferenceWithOther() {
991+
DefaultListableBeanFactory bf = new DefaultListableBeanFactory();
992+
bf.setAutowireCandidateResolver(new QualifierAnnotationAutowireCandidateResolver());
993+
AutowiredAnnotationBeanPostProcessor bpp = new AutowiredAnnotationBeanPostProcessor();
994+
bpp.setBeanFactory(bf);
995+
bf.addBeanPostProcessor(bpp);
996+
bf.registerBeanDefinition("annotatedBean", new RootBeanDefinition(SelfInjectionBean.class));
997+
bf.registerBeanDefinition("annotatedBean2", new RootBeanDefinition(SelfInjectionBean.class));
983998

984999
SelfInjectionBean bean = (SelfInjectionBean) bf.getBean("annotatedBean");
985-
assertSame(bean, bean.selfReference);
1000+
SelfInjectionBean bean2 = (SelfInjectionBean) bf.getBean("annotatedBean2");
1001+
assertSame(bean2, bean.reference);
1002+
assertEquals(1, bean.referenceCollection.size());
1003+
assertSame(bean2, bean.referenceCollection.get(0));
1004+
}
1005+
1006+
@Test
1007+
public void testSelfReferenceCollection() {
1008+
DefaultListableBeanFactory bf = new DefaultListableBeanFactory();
1009+
bf.setAutowireCandidateResolver(new QualifierAnnotationAutowireCandidateResolver());
1010+
AutowiredAnnotationBeanPostProcessor bpp = new AutowiredAnnotationBeanPostProcessor();
1011+
bpp.setBeanFactory(bf);
1012+
bf.addBeanPostProcessor(bpp);
1013+
bf.registerBeanDefinition("annotatedBean", new RootBeanDefinition(SelfInjectionCollectionBean.class));
1014+
1015+
SelfInjectionCollectionBean bean = (SelfInjectionCollectionBean) bf.getBean("annotatedBean");
1016+
assertSame(bean, bean.reference);
1017+
assertNull(bean.referenceCollection);
1018+
}
1019+
1020+
@Test
1021+
public void testSelfReferenceCollectionWithOther() {
1022+
DefaultListableBeanFactory bf = new DefaultListableBeanFactory();
1023+
bf.setAutowireCandidateResolver(new QualifierAnnotationAutowireCandidateResolver());
1024+
AutowiredAnnotationBeanPostProcessor bpp = new AutowiredAnnotationBeanPostProcessor();
1025+
bpp.setBeanFactory(bf);
1026+
bf.addBeanPostProcessor(bpp);
1027+
bf.registerBeanDefinition("annotatedBean", new RootBeanDefinition(SelfInjectionCollectionBean.class));
1028+
bf.registerBeanDefinition("annotatedBean2", new RootBeanDefinition(SelfInjectionCollectionBean.class));
1029+
1030+
SelfInjectionCollectionBean bean = (SelfInjectionCollectionBean) bf.getBean("annotatedBean");
1031+
SelfInjectionCollectionBean bean2 = (SelfInjectionCollectionBean) bf.getBean("annotatedBean2");
1032+
assertSame(bean2, bean.reference);
1033+
assertSame(1, bean2.referenceCollection.size());
1034+
assertSame(bean2, bean.referenceCollection.get(0));
9861035
}
9871036

9881037
@Test
@@ -2582,7 +2631,21 @@ public Set<TestBean> getTestBeanSet() {
25822631
public static class SelfInjectionBean {
25832632

25842633
@Autowired
2585-
public SelfInjectionBean selfReference;
2634+
public SelfInjectionBean reference;
2635+
2636+
@Autowired(required = false)
2637+
public List<SelfInjectionBean> referenceCollection;
2638+
}
2639+
2640+
2641+
@SuppressWarnings("serial")
2642+
public static class SelfInjectionCollectionBean extends LinkedList<SelfInjectionCollectionBean> {
2643+
2644+
@Autowired
2645+
public SelfInjectionCollectionBean reference;
2646+
2647+
@Autowired(required = false)
2648+
public List<SelfInjectionCollectionBean> referenceCollection;
25862649
}
25872650

25882651

0 commit comments

Comments
 (0)