Skip to content

Commit c8ff562

Browse files
committed
DefaultSingletonBeanRegistry's isDependent defensively checks for circular recursion
Issue: SPR-10787 (cherry picked from commit 15d3b88)
1 parent 1d6978a commit c8ff562

File tree

2 files changed

+48
-15
lines changed

2 files changed

+48
-15
lines changed

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

Lines changed: 16 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@
1818

1919
import java.util.Collections;
2020
import java.util.HashMap;
21+
import java.util.HashSet;
2122
import java.util.Iterator;
2223
import java.util.LinkedHashMap;
2324
import java.util.LinkedHashSet;
@@ -415,17 +416,30 @@ public void registerDependentBean(String beanName, String dependentBeanName) {
415416
* dependent on the given bean or on any of its transitive dependencies.
416417
* @param beanName the name of the bean to check
417418
* @param dependentBeanName the name of the dependent bean
419+
* @since 4.0
418420
*/
419421
protected boolean isDependent(String beanName, String dependentBeanName) {
420-
Set<String> dependentBeans = this.dependentBeanMap.get(beanName);
422+
return isDependent(beanName, dependentBeanName, null);
423+
}
424+
425+
private boolean isDependent(String beanName, String dependentBeanName, Set<String> alreadySeen) {
426+
String canonicalName = canonicalName(beanName);
427+
if (alreadySeen != null && alreadySeen.contains(beanName)) {
428+
return false;
429+
}
430+
Set<String> dependentBeans = this.dependentBeanMap.get(canonicalName);
421431
if (dependentBeans == null) {
422432
return false;
423433
}
424434
if (dependentBeans.contains(dependentBeanName)) {
425435
return true;
426436
}
427437
for (String transitiveDependency : dependentBeans) {
428-
if (isDependent(transitiveDependency, dependentBeanName)) {
438+
if (alreadySeen == null) {
439+
alreadySeen = new HashSet<String>();
440+
}
441+
alreadySeen.add(beanName);
442+
if (isDependent(transitiveDependency, dependentBeanName, alreadySeen)) {
429443
return true;
430444
}
431445
}

spring-beans/src/test/java/org/springframework/beans/factory/SharedBeanRegistryTests.java renamed to spring-beans/src/test/java/org/springframework/beans/factory/support/DefaultSingletonBeanRegistryTests.java

Lines changed: 32 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright 2002-2013 the original author or authors.
2+
* Copyright 2002-2014 the original author or authors.
33
*
44
* Licensed under the Apache License, Version 2.0 (the "License");
55
* you may not use this file except in compliance with the License.
@@ -14,24 +14,23 @@
1414
* limitations under the License.
1515
*/
1616

17-
package org.springframework.beans.factory;
18-
19-
import static org.junit.Assert.*;
20-
21-
import java.util.Arrays;
17+
package org.springframework.beans.factory.support;
2218

2319
import org.junit.Test;
20+
2421
import org.springframework.beans.BeansException;
25-
import org.springframework.beans.factory.support.DefaultSingletonBeanRegistry;
22+
import org.springframework.beans.factory.ObjectFactory;
2623
import org.springframework.tests.sample.beans.DerivedTestBean;
2724
import org.springframework.tests.sample.beans.TestBean;
2825

26+
import static org.junit.Assert.*;
27+
2928
/**
3029
* @author Juergen Hoeller
3130
* @author Chris Beams
3231
* @since 04.07.2006
3332
*/
34-
public final class SharedBeanRegistryTests {
33+
public class DefaultSingletonBeanRegistryTests {
3534

3635
@Test
3736
public void testSingletons() {
@@ -52,9 +51,10 @@ public Object getObject() throws BeansException {
5251
assertSame(tb, beanRegistry.getSingleton("tb"));
5352
assertSame(tb2, beanRegistry.getSingleton("tb2"));
5453
assertEquals(2, beanRegistry.getSingletonCount());
55-
assertEquals(2, beanRegistry.getSingletonNames().length);
56-
assertTrue(Arrays.asList(beanRegistry.getSingletonNames()).contains("tb"));
57-
assertTrue(Arrays.asList(beanRegistry.getSingletonNames()).contains("tb2"));
54+
String[] names = beanRegistry.getSingletonNames();
55+
assertEquals(2, names.length);
56+
assertEquals("tb", names[0]);
57+
assertEquals("tb2", names[1]);
5858

5959
beanRegistry.destroySingletons();
6060
assertEquals(0, beanRegistry.getSingletonCount());
@@ -72,8 +72,9 @@ public void testDisposableBean() {
7272

7373
assertSame(tb, beanRegistry.getSingleton("tb"));
7474
assertEquals(1, beanRegistry.getSingletonCount());
75-
assertEquals(1, beanRegistry.getSingletonNames().length);
76-
assertTrue(Arrays.asList(beanRegistry.getSingletonNames()).contains("tb"));
75+
String[] names = beanRegistry.getSingletonNames();
76+
assertEquals(1, names.length);
77+
assertEquals("tb", names[0]);
7778
assertFalse(tb.wasDestroyed());
7879

7980
beanRegistry.destroySingletons();
@@ -82,4 +83,22 @@ public void testDisposableBean() {
8283
assertTrue(tb.wasDestroyed());
8384
}
8485

86+
@Test
87+
public void testDependentRegistration() {
88+
DefaultSingletonBeanRegistry beanRegistry = new DefaultSingletonBeanRegistry();
89+
90+
beanRegistry.registerDependentBean("a", "b");
91+
beanRegistry.registerDependentBean("b", "c");
92+
beanRegistry.registerDependentBean("c", "b");
93+
assertTrue(beanRegistry.isDependent("a", "b"));
94+
assertTrue(beanRegistry.isDependent("b", "c"));
95+
assertTrue(beanRegistry.isDependent("c", "b"));
96+
assertTrue(beanRegistry.isDependent("a", "c"));
97+
assertFalse(beanRegistry.isDependent("c", "a"));
98+
assertFalse(beanRegistry.isDependent("b", "a"));
99+
assertFalse(beanRegistry.isDependent("a", "a"));
100+
assertTrue(beanRegistry.isDependent("b", "b"));
101+
assertTrue(beanRegistry.isDependent("c", "c"));
102+
}
103+
85104
}

0 commit comments

Comments
 (0)