You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
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() {
}
}
}
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 theAbstractApplicationContext
class does not properly maintain its internal countdown latch. The latch is initialized with the totalSmartLifecycle
bean count. However, if a bean returns false from itsisRunning()
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.
Affects: 3.0 RC2
Issue Links:
The text was updated successfully, but these errors were encountered: