Detect depends-on cycles and throw proper exception
Issue: SPR-7966
This commit is contained in:
parent
de890fd100
commit
bd8469990d
|
|
@ -286,8 +286,12 @@ public abstract class AbstractBeanFactory extends FactoryBeanRegistrySupport imp
|
|||
String[] dependsOn = mbd.getDependsOn();
|
||||
if (dependsOn != null) {
|
||||
for (String dependsOnBean : dependsOn) {
|
||||
getBean(dependsOnBean);
|
||||
if (isDependent(beanName, dependsOnBean)) {
|
||||
throw new BeanCreationException("Circular depends-on relationship between '" +
|
||||
beanName + "' and '" + dependsOnBean + "'");
|
||||
}
|
||||
registerDependentBean(dependsOnBean, beanName);
|
||||
getBean(dependsOnBean);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -412,6 +412,28 @@ public class DefaultSingletonBeanRegistry extends SimpleAliasRegistry implements
|
|||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Determine whether the specified dependent bean has been registered as
|
||||
* dependent on the given bean or on any of its transitive dependencies.
|
||||
* @param beanName the name of the bean to check
|
||||
* @param dependentBeanName the name of the dependent bean
|
||||
*/
|
||||
protected boolean isDependent(String beanName, String dependentBeanName) {
|
||||
Set<String> dependentBeans = this.dependentBeanMap.get(beanName);
|
||||
if (dependentBeans == null) {
|
||||
return false;
|
||||
}
|
||||
if (dependentBeans.contains(dependentBeanName)) {
|
||||
return true;
|
||||
}
|
||||
for (String transitiveDependency : dependentBeans) {
|
||||
if (isDependent(transitiveDependency, dependentBeanName)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Determine whether a dependent bean has been registered for the given name.
|
||||
* @param beanName the name of the bean to check
|
||||
|
|
|
|||
|
|
@ -1219,8 +1219,8 @@ public class DefaultListableBeanFactoryTests {
|
|||
}
|
||||
catch (UnsatisfiedDependencyException ex) {
|
||||
// expected
|
||||
assertTrue(ex.getMessage().indexOf("rod") != -1);
|
||||
assertTrue(ex.getMessage().indexOf("rod2") != -1);
|
||||
assertTrue(ex.getMessage().contains("rod"));
|
||||
assertTrue(ex.getMessage().contains("rod2"));
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -1290,6 +1290,51 @@ public class DefaultListableBeanFactoryTests {
|
|||
assertNull(bean.getSpouse());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testDependsOnCycle() {
|
||||
DefaultListableBeanFactory lbf = new DefaultListableBeanFactory();
|
||||
RootBeanDefinition bd1 = new RootBeanDefinition(TestBean.class);
|
||||
bd1.setDependsOn(new String[] {"tb2"});
|
||||
lbf.registerBeanDefinition("tb1", bd1);
|
||||
RootBeanDefinition bd2 = new RootBeanDefinition(TestBean.class);
|
||||
bd2.setDependsOn(new String[] {"tb1"});
|
||||
lbf.registerBeanDefinition("tb2", bd2);
|
||||
try {
|
||||
lbf.preInstantiateSingletons();
|
||||
fail("Should have thrown BeanCreationException");
|
||||
}
|
||||
catch (BeanCreationException ex) {
|
||||
// expected
|
||||
assertTrue(ex.getMessage().contains("Circular"));
|
||||
assertTrue(ex.getMessage().contains("'tb2'"));
|
||||
assertTrue(ex.getMessage().contains("'tb1'"));
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testImplicitDependsOnCycle() {
|
||||
DefaultListableBeanFactory lbf = new DefaultListableBeanFactory();
|
||||
RootBeanDefinition bd1 = new RootBeanDefinition(TestBean.class);
|
||||
bd1.setDependsOn(new String[] {"tb2"});
|
||||
lbf.registerBeanDefinition("tb1", bd1);
|
||||
RootBeanDefinition bd2 = new RootBeanDefinition(TestBean.class);
|
||||
bd2.setDependsOn(new String[] {"tb3"});
|
||||
lbf.registerBeanDefinition("tb2", bd2);
|
||||
RootBeanDefinition bd3 = new RootBeanDefinition(TestBean.class);
|
||||
bd3.setDependsOn(new String[] {"tb1"});
|
||||
lbf.registerBeanDefinition("tb3", bd3);
|
||||
try {
|
||||
lbf.preInstantiateSingletons();
|
||||
fail("Should have thrown BeanCreationException");
|
||||
}
|
||||
catch (BeanCreationException ex) {
|
||||
// expected
|
||||
assertTrue(ex.getMessage().contains("Circular"));
|
||||
assertTrue(ex.getMessage().contains("'tb3'"));
|
||||
assertTrue(ex.getMessage().contains("'tb1'"));
|
||||
}
|
||||
}
|
||||
|
||||
@Test(expected=NoSuchBeanDefinitionException.class)
|
||||
public void testGetBeanByTypeWithNoneFound() {
|
||||
DefaultListableBeanFactory lbf = new DefaultListableBeanFactory();
|
||||
|
|
@ -2174,7 +2219,7 @@ public class DefaultListableBeanFactoryTests {
|
|||
AbstractBeanDefinition beanDefinition = builder.getBeanDefinition();
|
||||
beanDefinition.setScope("he put himself so low could hardly look me in the face");
|
||||
|
||||
final DefaultListableBeanFactory factory = new DefaultListableBeanFactory();
|
||||
DefaultListableBeanFactory factory = new DefaultListableBeanFactory();
|
||||
factory.registerBeanDefinition("testBean", beanDefinition);
|
||||
factory.getBean("testBean");
|
||||
}
|
||||
|
|
@ -2186,8 +2231,7 @@ public class DefaultListableBeanFactoryTests {
|
|||
RootBeanDefinition parent = new RootBeanDefinition();
|
||||
parent.setScope(RootBeanDefinition.SCOPE_PROTOTYPE);
|
||||
|
||||
AbstractBeanDefinition child = BeanDefinitionBuilder
|
||||
.childBeanDefinition("parent").getBeanDefinition();
|
||||
AbstractBeanDefinition child = BeanDefinitionBuilder.childBeanDefinition("parent").getBeanDefinition();
|
||||
child.setBeanClass(TestBean.class);
|
||||
child.setScope(theChildScope);
|
||||
|
||||
|
|
|
|||
Loading…
Reference in New Issue