Skip to content

Application context does not properly handle non-running SmartLifecyle beans [SPR-6572] #11238

Closed
@spring-projects-issues

Description

@spring-projects-issues

Lance Arlaus opened SPR-6572 and commented

Application contexts do not close properly when the context contains a SmartLifecycle bean that is in a non-running state (isRunning() returns false).

This issue was first noticed when using a DefaultMessageListenerContainer, but it affects any similar bean.

Root Cause
The DefaultLifecycleProcessor used by the AbstractApplicationContext class does not properly maintain its internal countdown latch. The latch is initialized with the total SmartLifecycle bean count. However, if a bean returns false from its isRunning() method, the latch is never decremented in the {{doStop()} method. The result is a timeout during close waiting for the latch to be decremented.

Unless I'm missing something, a simple else block with a decrement on the latch should do the trick.

Note to the team - this was a nasty little bug that took quite some time to ferret out.

Relevant code and test case follow.

	private void doStop(Map<String, Lifecycle> lifecycleBeans, String beanName, final CountDownLatch latch) {
		Lifecycle bean = lifecycleBeans.get(beanName);
		if (bean != null) {
			String[] dependentBeans = this.beanFactory.getDependentBeans(beanName);
			for (String dependentBean : dependentBeans) {
				doStop(lifecycleBeans, dependentBean, latch);
			}
			if (bean.isRunning()) {
				if (bean instanceof SmartLifecycle) {
					((SmartLifecycle) bean).stop(new Runnable() {
						public void run() {
							latch.countDown();
						}
					});
				}
				else {
					bean.stop();
				}
			}
			// =====================================
			// Latch is never decremented

			lifecycleBeans.remove(beanName);
		}
	}
public class SmartLifecycleBugCheck {

	@Test(timeout=2000)
	public void testNotRunningBean() {
		final ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext();
		
		context.refresh();
		context.getBeanFactory().registerSingleton("testBean", new TestBean());
		
		context.start();
		context.close();
	}
	
	
	public static class TestBean implements SmartLifecycle {
		public int getShutdownOrder() {
			return 0;
		}
		public boolean isAutoStartup() {
			return false;
		}
		public void stop(Runnable callback) {
			callback.run();
		}
		public boolean isRunning() {
			return false;
		}
		public void start() {
			
		}
		public void stop() {
		}
	}
	
}

Affects: 3.0 RC2

Issue Links:

Metadata

Metadata

Assignees

Labels

in: coreIssues in core modules (aop, beans, core, context, expression)type: bugA general bug

Type

No type

Projects

No projects

Milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions