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