Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

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

Closed
spring-projects-issues opened this issue Dec 16, 2009 · 1 comment
Assignees
Labels
in: core Issues in core modules (aop, beans, core, context, expression) type: bug A general bug
Milestone

Comments

@spring-projects-issues
Copy link
Collaborator

spring-projects-issues commented Dec 16, 2009

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:

@spring-projects-issues
Copy link
Collaborator Author

Juergen Hoeller commented

This should have been fixed since 3.0 RC3 already. Let me know if any issue remains with RC3/GA.

Juergen

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
in: core Issues in core modules (aop, beans, core, context, expression) type: bug A general bug
Projects
None yet
Development

No branches or pull requests

2 participants