diff --git a/org.springframework.context.support/src/main/java/org/springframework/scheduling/quartz/SchedulerFactoryBean.java b/org.springframework.context.support/src/main/java/org/springframework/scheduling/quartz/SchedulerFactoryBean.java
index 8da348f00a..c52418dc95 100644
--- a/org.springframework.context.support/src/main/java/org/springframework/scheduling/quartz/SchedulerFactoryBean.java
+++ b/org.springframework.context.support/src/main/java/org/springframework/scheduling/quartz/SchedulerFactoryBean.java
@@ -190,7 +190,7 @@ public class SchedulerFactoryBean extends SchedulerAccessor implements FactoryBe
private int startupDelay = 0;
- private int shutdownOrder = Integer.MAX_VALUE;
+ private int phase = Integer.MAX_VALUE;
private boolean exposeSchedulerInRepository = false;
@@ -376,18 +376,21 @@ public class SchedulerFactoryBean extends SchedulerAccessor implements FactoryBe
}
/**
- * Specify the order in which this scheduler should be stopped.
- * By default it will be stopped in the last group.
+ * Specify the phase in which this scheduler should be started and
+ * stopped. The startup order proceeds from lowest to highest, and
+ * the shutdown order is the reverse of that. By default this value
+ * is Integer.MAX_VALUE meaning that this scheduler starts as late
+ * as possible and stops as soon as possible.
*/
- public void setShutdownOrder(int shutdownOrder) {
- this.shutdownOrder = shutdownOrder;
+ public void setPhase(int phase) {
+ this.phase = phase;
}
/**
- * Return the order in which this scheduler will be stopped.
+ * Return the phase in which this scheduler will be started and stopped.
*/
- public int getShutdownOrder() {
- return this.shutdownOrder;
+ public int getPhase() {
+ return this.phase;
}
/**
diff --git a/org.springframework.context.support/src/test/resources/org/springframework/scheduling/quartz/quartzSchedulerLifecycleTests.xml b/org.springframework.context.support/src/test/resources/org/springframework/scheduling/quartz/quartzSchedulerLifecycleTests.xml
index 91df4ec539..1708cce9c7 100644
--- a/org.springframework.context.support/src/test/resources/org/springframework/scheduling/quartz/quartzSchedulerLifecycleTests.xml
+++ b/org.springframework.context.support/src/test/resources/org/springframework/scheduling/quartz/quartzSchedulerLifecycleTests.xml
@@ -7,7 +7,7 @@
-
+
diff --git a/org.springframework.context/src/main/java/org/springframework/context/SmartLifecycle.java b/org.springframework.context/src/main/java/org/springframework/context/SmartLifecycle.java
index 6ccab94123..5b1f060a9b 100644
--- a/org.springframework.context/src/main/java/org/springframework/context/SmartLifecycle.java
+++ b/org.springframework.context/src/main/java/org/springframework/context/SmartLifecycle.java
@@ -33,14 +33,28 @@ public interface SmartLifecycle extends Lifecycle {
boolean isAutoStartup();
/**
- * Return the order in which this Lifecycle component should be stopped.
- * The shutdown process begins with the component(s) having the lowest
- * value and ends with the highest value (Integer.MIN_VALUE is the lowest
- * possible, and Integer.MAX_VALUE is the highest possible). Any Lifecycle
- * components within the context that do not also implement SmartLifecycle
- * will be treated as if they have a value of Integer.MAX_VALUE.
+ * Return the phase within which this Lifecycle component should be started
+ * and stopped. The startup process begins with the lowest phase
+ * value and ends with the highest phase value (Integer.MIN_VALUE is
+ * the lowest possible, and Integer.MAX_VALUE is the highest possible). The
+ * shutdown process will apply the reverse order. Any components with the
+ * same value will be arbitrarily ordered within the same phase.
+ *
+ * Example: if component B depends on component A having already started, then
+ * component A should have a lower phase value than component B. During the
+ * shutdown process, component B would be stopped before component A.
+ *
+ * Any Lifecycle components within the context that do not also implement
+ * SmartLifecycle will be treated as if they have a phase value of 0. That
+ * way a SmartLifecycle implementation may start before those Lifecycle
+ * components if it has a negative phase value, or it may start after
+ * those components if it has a positive phase value.
+ *
+ * Any explicit "depends-on" relationship will take precedence over
+ * the phase order such that the dependent bean always starts after its
+ * dependency and always stops before its dependency.
*/
- int getShutdownOrder();
+ int getPhase();
/**
* Indicates that a Lifecycle component must stop if it is currently running.
diff --git a/org.springframework.context/src/main/java/org/springframework/context/support/DefaultLifecycleProcessor.java b/org.springframework.context/src/main/java/org/springframework/context/support/DefaultLifecycleProcessor.java
index 626278e45e..3d74ea11f9 100644
--- a/org.springframework.context/src/main/java/org/springframework/context/support/DefaultLifecycleProcessor.java
+++ b/org.springframework.context/src/main/java/org/springframework/context/support/DefaultLifecycleProcessor.java
@@ -20,7 +20,6 @@ import java.util.ArrayList;
import java.util.Collections;
import java.util.HashMap;
import java.util.LinkedHashMap;
-import java.util.LinkedHashSet;
import java.util.List;
import java.util.Map;
import java.util.concurrent.CountDownLatch;
@@ -47,7 +46,7 @@ public class DefaultLifecycleProcessor implements LifecycleProcessor, BeanFactor
private final Log logger = LogFactory.getLog(this.getClass());
- private volatile long shutdownGroupTimeout = 30000;
+ private volatile long timeoutPerShutdownPhase = 30000;
private volatile boolean running;
@@ -55,12 +54,12 @@ public class DefaultLifecycleProcessor implements LifecycleProcessor, BeanFactor
/**
- * Specify the maximum time allotted for the shutdown of any group of
- * SmartLifecycle beans (those with the same 'order' value). The default
- * value is 30 seconds.
+ * Specify the maximum time allotted for the shutdown of any phase
+ * (group of SmartLifecycle beans with the same 'phase' value).
+ * The default value is 30 seconds.
*/
- public void setShutdownGroupTimeout(long shutdownGroupTimeout) {
- this.shutdownGroupTimeout = shutdownGroupTimeout;
+ public void setTimeoutPerShutdownPhase(long timeoutPerShutdownPhase) {
+ this.timeoutPerShutdownPhase = timeoutPerShutdownPhase;
}
public void setBeanFactory(BeanFactory beanFactory) {
@@ -77,58 +76,84 @@ public class DefaultLifecycleProcessor implements LifecycleProcessor, BeanFactor
return this.running;
}
+ /**
+ * Start all registered beans that implement Lifecycle and are
+ * not already running. Any bean that implements SmartLifecycle
+ * will be started within its 'phase', and all phases will be ordered
+ * from lowest to highest value. All beans that do not implement
+ * SmartLifecycle will be started in the default phase 0. A bean
+ * declared as a dependency of another bean will be started before
+ * the dependent bean regardless of the declared phase.
+ */
public void start() {
- Map lifecycleBeans = getLifecycleBeans();
- for (String beanName : new LinkedHashSet(lifecycleBeans.keySet())) {
- doStart(lifecycleBeans, beanName);
- }
- this.running = true;
+ this.startBeans(false);
}
+ /**
+ * Stop all registered beans that implement Lifecycle and are
+ * currently running. Any bean that implements SmartLifecycle
+ * will be stopped within its 'phase', and all phases will be ordered
+ * from highest to lowest value. All beans that do not implement
+ * SmartLifecycle will be stopped in the default phase 0. A bean
+ * declared as dependent on another bean will be stopped before
+ * the dependency bean regardless of the declared phase.
+ */
public void stop() {
Map lifecycleBeans = getLifecycleBeans();
- Map shutdownGroups = new HashMap();
+ Map phases = new HashMap();
for (Map.Entry entry : lifecycleBeans.entrySet()) {
Lifecycle lifecycle = entry.getValue();
- int shutdownOrder = getShutdownOrder(lifecycle);
- ShutdownGroup group = shutdownGroups.get(shutdownOrder);
+ int shutdownOrder = getPhase(lifecycle);
+ LifecycleGroup group = phases.get(shutdownOrder);
if (group == null) {
- group = new ShutdownGroup(shutdownOrder, this.shutdownGroupTimeout, lifecycleBeans);
- shutdownGroups.put(shutdownOrder, group);
+ group = new LifecycleGroup(shutdownOrder, this.timeoutPerShutdownPhase, lifecycleBeans);
+ phases.put(shutdownOrder, group);
}
group.add(entry.getKey(), lifecycle);
}
- if (shutdownGroups.size() > 0) {
- List keys = new ArrayList(shutdownGroups.keySet());
- Collections.sort(keys);
+ if (phases.size() > 0) {
+ List keys = new ArrayList(phases.keySet());
+ Collections.sort(keys, Collections.reverseOrder());
for (Integer key : keys) {
- shutdownGroups.get(key).shutdown();
+ phases.get(key).stop();
}
}
this.running = false;
}
public void onRefresh() {
- Map lifecycleBeans = getSmartLifecycleBeans();
- for (String beanName : new LinkedHashSet(lifecycleBeans.keySet())) {
- SmartLifecycle bean = lifecycleBeans.get(beanName);
- if (bean != null && bean.isAutoStartup()) {
- String[] dependenciesForBean = this.beanFactory.getDependenciesForBean(beanName);
- for (String dependency : dependenciesForBean) {
- doStart(lifecycleBeans, dependency);
- }
- if (!bean.isRunning()) {
- bean.start();
- }
- lifecycleBeans.remove(beanName);
- }
- }
+ this.startBeans(true);
}
public void onClose() {
stop();
}
+ private void startBeans(boolean autoStartupOnly) {
+ Map lifecycleBeans = getLifecycleBeans();
+ Map phases = new HashMap();
+ for (Map.Entry entry : lifecycleBeans.entrySet()) {
+ Lifecycle lifecycle = entry.getValue();
+ if (!autoStartupOnly || (lifecycle instanceof SmartLifecycle && ((SmartLifecycle) lifecycle).isAutoStartup())) {
+ int phase = getPhase(lifecycle);
+ LifecycleGroup group = phases.get(phase);
+ if (group == null) {
+ group = new LifecycleGroup(phase, this.timeoutPerShutdownPhase, lifecycleBeans);
+ phases.put(phase, group);
+ }
+ group.add(entry.getKey(), lifecycle);
+ }
+ }
+ if (phases.size() > 0) {
+ List keys = new ArrayList(phases.keySet());
+ Collections.sort(keys);
+ for (Integer key : keys) {
+ phases.get(key).start();
+ }
+ }
+ this.running = true;
+ }
+
/**
* Start the specified bean as part of the given set of Lifecycle beans,
* making sure that any beans that it depends on are started first.
@@ -155,7 +180,7 @@ public class DefaultLifecycleProcessor implements LifecycleProcessor, BeanFactor
* @param lifecycleBeans Map with bean name as key and Lifecycle instance as value
* @param beanName the name of the bean to stop
*/
- private void doStop(Map lifecycleBeans, String beanName, final CountDownLatch latch) {
+ private void doStop(Map lifecycleBeans, String beanName, final CountDownLatch latch) {
Lifecycle bean = lifecycleBeans.get(beanName);
if (bean != null) {
String[] dependentBeans = this.beanFactory.getDependentBeans(beanName);
@@ -194,44 +219,31 @@ public class DefaultLifecycleProcessor implements LifecycleProcessor, BeanFactor
return beans;
}
- private Map getSmartLifecycleBeans() {
- String[] beanNames = beanFactory.getSingletonNames();
- Map beans = new LinkedHashMap();
- for (String beanName : beanNames) {
- Object bean = beanFactory.getSingleton(beanName);
- if (bean instanceof SmartLifecycle) {
- beans.put(beanName, (SmartLifecycle) bean);
- }
- }
- return beans;
- }
-
-
- private static int getShutdownOrder(Lifecycle bean) {
+ private static int getPhase(Lifecycle bean) {
return (bean instanceof SmartLifecycle) ?
- ((SmartLifecycle) bean).getShutdownOrder() : Integer.MAX_VALUE;
+ ((SmartLifecycle) bean).getPhase() : 0;
}
/**
- * Helper class for maintaining a group of Lifecycle beans that should be shutdown
- * together based on their 'shutdownOrder' value (or the default MAX_INTEGER value).
+ * Helper class for maintaining a group of Lifecycle beans that should be started
+ * and stopped together based on their 'phase' value (or the default value of 0).
*/
- private class ShutdownGroup {
+ private class LifecycleGroup {
- private final List members = new ArrayList();
+ private final List members = new ArrayList();
- private Map lifecycleBeans = getLifecycleBeans();
+ private Map lifecycleBeans = getLifecycleBeans();
private volatile int smartMemberCount;
- private final int order;
+ private final int phase;
private final long timeout;
- ShutdownGroup(int order, long timeout, Map lifecycleBeans) {
- this.order = order;
+ LifecycleGroup(int phase, long timeout, Map lifecycleBeans) {
+ this.phase = phase;
this.timeout = timeout;
this.lifecycleBeans = lifecycleBeans;
}
@@ -240,16 +252,28 @@ public class DefaultLifecycleProcessor implements LifecycleProcessor, BeanFactor
if (bean instanceof SmartLifecycle) {
this.smartMemberCount++;
}
- this.members.add(new ShutdownGroupMember(name, bean));
+ this.members.add(new LifecycleGroupMember(name, bean));
}
- void shutdown() {
+ void start() {
if (members.size() == 0) {
return;
}
Collections.sort(members);
+ for (LifecycleGroupMember member : members) {
+ if (lifecycleBeans.containsKey(member.name)) {
+ doStart(lifecycleBeans, member.name);
+ }
+ }
+ }
+
+ void stop() {
+ if (members.size() == 0) {
+ return;
+ }
+ Collections.sort(members, Collections.reverseOrder());
final CountDownLatch latch = new CountDownLatch(this.smartMemberCount);
- for (ShutdownGroupMember member : members) {
+ for (LifecycleGroupMember member : members) {
if (lifecycleBeans.containsKey(member.name)) {
doStop(lifecycleBeans, member.name, latch);
}
@@ -262,8 +286,8 @@ public class DefaultLifecycleProcessor implements LifecycleProcessor, BeanFactor
latch.await(this.timeout, TimeUnit.MILLISECONDS);
if (latch.getCount() != 0) {
if (logger.isWarnEnabled()) {
- logger.warn("failed to shutdown beans with order " +
- this.order + " within timeout of " + this.timeout);
+ logger.warn("failed to shutdown beans with phase value " +
+ this.phase + " within timeout of " + this.timeout);
}
}
}
@@ -274,20 +298,20 @@ public class DefaultLifecycleProcessor implements LifecycleProcessor, BeanFactor
}
- private static class ShutdownGroupMember implements Comparable {
+ private static class LifecycleGroupMember implements Comparable {
- private String name;
+ private final String name;
- private Lifecycle bean;
+ private final Lifecycle bean;
- ShutdownGroupMember(String name, Lifecycle bean) {
+ LifecycleGroupMember(String name, Lifecycle bean) {
this.name = name;
this.bean = bean;
}
- public int compareTo(ShutdownGroupMember other) {
- int thisOrder = getShutdownOrder(this.bean);
- int otherOrder = getShutdownOrder(other.bean);
+ public int compareTo(LifecycleGroupMember other) {
+ int thisOrder = getPhase(this.bean);
+ int otherOrder = getPhase(other.bean);
return (thisOrder == otherOrder) ? 0 : (thisOrder < otherOrder) ? -1 : 1;
}
}
diff --git a/org.springframework.context/src/test/java/org/springframework/context/support/DefaultLifecycleProcessorTests.java b/org.springframework.context/src/test/java/org/springframework/context/support/DefaultLifecycleProcessorTests.java
index 6b7c1c51db..116743d5ec 100644
--- a/org.springframework.context/src/test/java/org/springframework/context/support/DefaultLifecycleProcessorTests.java
+++ b/org.springframework.context/src/test/java/org/springframework/context/support/DefaultLifecycleProcessorTests.java
@@ -33,16 +33,157 @@ import org.springframework.context.SmartLifecycle;
*/
public class DefaultLifecycleProcessorTests {
+ @Test
+ public void singleSmartLifecycleAutoStartup() throws Exception {
+ CopyOnWriteArrayList startedBeans = new CopyOnWriteArrayList();
+ TestSmartLifecycleBean bean = TestSmartLifecycleBean.forStartupTests(1, startedBeans);
+ bean.setAutoStartup(true);
+ StaticApplicationContext context = new StaticApplicationContext();
+ context.getBeanFactory().registerSingleton("bean", bean);
+ assertFalse(bean.isRunning());
+ context.refresh();
+ assertTrue(bean.isRunning());
+ context.stop();
+ assertFalse(bean.isRunning());
+ assertEquals(1, startedBeans.size());
+ }
+
+ @Test
+ public void singleSmartLifecycleWithoutAutoStartup() throws Exception {
+ CopyOnWriteArrayList startedBeans = new CopyOnWriteArrayList();
+ TestSmartLifecycleBean bean = TestSmartLifecycleBean.forStartupTests(1, startedBeans);
+ bean.setAutoStartup(false);
+ StaticApplicationContext context = new StaticApplicationContext();
+ context.getBeanFactory().registerSingleton("bean", bean);
+ assertFalse(bean.isRunning());
+ context.refresh();
+ assertFalse(bean.isRunning());
+ assertEquals(0, startedBeans.size());
+ context.start();
+ assertTrue(bean.isRunning());
+ assertEquals(1, startedBeans.size());
+ context.stop();
+ }
+
+ @Test
+ public void smartLifecycleGroupStartup() throws Exception {
+ CopyOnWriteArrayList startedBeans = new CopyOnWriteArrayList();
+ TestSmartLifecycleBean beanMin = TestSmartLifecycleBean.forStartupTests(Integer.MIN_VALUE, startedBeans);
+ TestSmartLifecycleBean bean1 = TestSmartLifecycleBean.forStartupTests(1, startedBeans);
+ TestSmartLifecycleBean bean2 = TestSmartLifecycleBean.forStartupTests(2, startedBeans);
+ TestSmartLifecycleBean bean3 = TestSmartLifecycleBean.forStartupTests(3, startedBeans);
+ TestSmartLifecycleBean beanMax = TestSmartLifecycleBean.forStartupTests(Integer.MAX_VALUE, startedBeans);
+ StaticApplicationContext context = new StaticApplicationContext();
+ context.getBeanFactory().registerSingleton("bean3", bean3);
+ context.getBeanFactory().registerSingleton("beanMin", beanMin);
+ context.getBeanFactory().registerSingleton("bean2", bean2);
+ context.getBeanFactory().registerSingleton("beanMax", beanMax);
+ context.getBeanFactory().registerSingleton("bean1", bean1);
+ assertFalse(beanMin.isRunning());
+ assertFalse(bean1.isRunning());
+ assertFalse(bean2.isRunning());
+ assertFalse(bean3.isRunning());
+ assertFalse(beanMax.isRunning());
+ context.refresh();
+ assertTrue(beanMin.isRunning());
+ assertTrue(bean1.isRunning());
+ assertTrue(bean2.isRunning());
+ assertTrue(bean3.isRunning());
+ assertTrue(beanMax.isRunning());
+ context.stop();
+ assertEquals(5, startedBeans.size());
+ assertEquals(Integer.MIN_VALUE, getPhase(startedBeans.get(0)));
+ assertEquals(1, getPhase(startedBeans.get(1)));
+ assertEquals(2, getPhase(startedBeans.get(2)));
+ assertEquals(3, getPhase(startedBeans.get(3)));
+ assertEquals(Integer.MAX_VALUE, getPhase(startedBeans.get(4)));
+ }
+
+ @Test
+ public void contextRefreshThenStartWithMixedBeans() throws Exception {
+ CopyOnWriteArrayList startedBeans = new CopyOnWriteArrayList();
+ TestLifecycleBean simpleBean1 = TestLifecycleBean.forStartupTests(startedBeans);
+ TestLifecycleBean simpleBean2 = TestLifecycleBean.forStartupTests(startedBeans);
+ TestSmartLifecycleBean smartBean1 = TestSmartLifecycleBean.forStartupTests(5, startedBeans);
+ TestSmartLifecycleBean smartBean2 = TestSmartLifecycleBean.forStartupTests(-3, startedBeans);
+ StaticApplicationContext context = new StaticApplicationContext();
+ context.getBeanFactory().registerSingleton("simpleBean1", simpleBean1);
+ context.getBeanFactory().registerSingleton("smartBean1", smartBean1);
+ context.getBeanFactory().registerSingleton("simpleBean2", simpleBean2);
+ context.getBeanFactory().registerSingleton("smartBean2", smartBean2);
+ assertFalse(simpleBean1.isRunning());
+ assertFalse(simpleBean2.isRunning());
+ assertFalse(smartBean1.isRunning());
+ assertFalse(smartBean2.isRunning());
+ context.refresh();
+ assertTrue(smartBean1.isRunning());
+ assertTrue(smartBean2.isRunning());
+ assertFalse(simpleBean1.isRunning());
+ assertFalse(simpleBean2.isRunning());
+ assertEquals(2, startedBeans.size());
+ assertEquals(-3, getPhase(startedBeans.get(0)));
+ assertEquals(5, getPhase(startedBeans.get(1)));
+ context.start();
+ assertTrue(smartBean1.isRunning());
+ assertTrue(smartBean2.isRunning());
+ assertTrue(simpleBean1.isRunning());
+ assertTrue(simpleBean2.isRunning());
+ assertEquals(4, startedBeans.size());
+ assertEquals(0, getPhase(startedBeans.get(2)));
+ assertEquals(0, getPhase(startedBeans.get(3)));
+ }
+
+ @Test
+ public void contextRefreshThenStopAndRestartWithMixedBeans() throws Exception {
+ CopyOnWriteArrayList startedBeans = new CopyOnWriteArrayList();
+ TestLifecycleBean simpleBean1 = TestLifecycleBean.forStartupTests(startedBeans);
+ TestLifecycleBean simpleBean2 = TestLifecycleBean.forStartupTests(startedBeans);
+ TestSmartLifecycleBean smartBean1 = TestSmartLifecycleBean.forStartupTests(5, startedBeans);
+ TestSmartLifecycleBean smartBean2 = TestSmartLifecycleBean.forStartupTests(-3, startedBeans);
+ StaticApplicationContext context = new StaticApplicationContext();
+ context.getBeanFactory().registerSingleton("simpleBean1", simpleBean1);
+ context.getBeanFactory().registerSingleton("smartBean1", smartBean1);
+ context.getBeanFactory().registerSingleton("simpleBean2", simpleBean2);
+ context.getBeanFactory().registerSingleton("smartBean2", smartBean2);
+ assertFalse(simpleBean1.isRunning());
+ assertFalse(simpleBean2.isRunning());
+ assertFalse(smartBean1.isRunning());
+ assertFalse(smartBean2.isRunning());
+ context.refresh();
+ assertTrue(smartBean1.isRunning());
+ assertTrue(smartBean2.isRunning());
+ assertFalse(simpleBean1.isRunning());
+ assertFalse(simpleBean2.isRunning());
+ assertEquals(2, startedBeans.size());
+ assertEquals(-3, getPhase(startedBeans.get(0)));
+ assertEquals(5, getPhase(startedBeans.get(1)));
+ context.stop();
+ assertFalse(simpleBean1.isRunning());
+ assertFalse(simpleBean2.isRunning());
+ assertFalse(smartBean1.isRunning());
+ assertFalse(smartBean2.isRunning());
+ context.start();
+ assertTrue(smartBean1.isRunning());
+ assertTrue(smartBean2.isRunning());
+ assertTrue(simpleBean1.isRunning());
+ assertTrue(simpleBean2.isRunning());
+ assertEquals(6, startedBeans.size());
+ assertEquals(-3, getPhase(startedBeans.get(2)));
+ assertEquals(0, getPhase(startedBeans.get(3)));
+ assertEquals(0, getPhase(startedBeans.get(4)));
+ assertEquals(5, getPhase(startedBeans.get(5)));
+ }
+
@Test
public void smartLifecycleGroupShutdown() throws Exception {
CopyOnWriteArrayList stoppedBeans = new CopyOnWriteArrayList();
- TestSmartLifecycleBean bean1 = new TestSmartLifecycleBean(1, 300, stoppedBeans);
- TestSmartLifecycleBean bean2 = new TestSmartLifecycleBean(3, 100, stoppedBeans);
- TestSmartLifecycleBean bean3 = new TestSmartLifecycleBean(1, 600, stoppedBeans);
- TestSmartLifecycleBean bean4 = new TestSmartLifecycleBean(2, 400, stoppedBeans);
- TestSmartLifecycleBean bean5 = new TestSmartLifecycleBean(2, 700, stoppedBeans);
- TestSmartLifecycleBean bean6 = new TestSmartLifecycleBean(Integer.MAX_VALUE, 200, stoppedBeans);
- TestSmartLifecycleBean bean7 = new TestSmartLifecycleBean(3, 200, stoppedBeans);
+ TestSmartLifecycleBean bean1 = TestSmartLifecycleBean.forShutdownTests(1, 300, stoppedBeans);
+ TestSmartLifecycleBean bean2 = TestSmartLifecycleBean.forShutdownTests(3, 100, stoppedBeans);
+ TestSmartLifecycleBean bean3 = TestSmartLifecycleBean.forShutdownTests(1, 600, stoppedBeans);
+ TestSmartLifecycleBean bean4 = TestSmartLifecycleBean.forShutdownTests(2, 400, stoppedBeans);
+ TestSmartLifecycleBean bean5 = TestSmartLifecycleBean.forShutdownTests(2, 700, stoppedBeans);
+ TestSmartLifecycleBean bean6 = TestSmartLifecycleBean.forShutdownTests(Integer.MAX_VALUE, 200, stoppedBeans);
+ TestSmartLifecycleBean bean7 = TestSmartLifecycleBean.forShutdownTests(3, 200, stoppedBeans);
StaticApplicationContext context = new StaticApplicationContext();
context.getBeanFactory().registerSingleton("bean1", bean1);
context.getBeanFactory().registerSingleton("bean2", bean2);
@@ -53,19 +194,19 @@ public class DefaultLifecycleProcessorTests {
context.getBeanFactory().registerSingleton("bean7", bean7);
context.refresh();
context.stop();
- assertEquals(1, getShutdownOrder(stoppedBeans.get(0)));
- assertEquals(1, getShutdownOrder(stoppedBeans.get(1)));
- assertEquals(2, getShutdownOrder(stoppedBeans.get(2)));
- assertEquals(2, getShutdownOrder(stoppedBeans.get(3)));
- assertEquals(3, getShutdownOrder(stoppedBeans.get(4)));
- assertEquals(3, getShutdownOrder(stoppedBeans.get(5)));
- assertEquals(Integer.MAX_VALUE, getShutdownOrder(stoppedBeans.get(6)));
+ assertEquals(Integer.MAX_VALUE, getPhase(stoppedBeans.get(0)));
+ assertEquals(3, getPhase(stoppedBeans.get(1)));
+ assertEquals(3, getPhase(stoppedBeans.get(2)));
+ assertEquals(2, getPhase(stoppedBeans.get(3)));
+ assertEquals(2, getPhase(stoppedBeans.get(4)));
+ assertEquals(1, getPhase(stoppedBeans.get(5)));
+ assertEquals(1, getPhase(stoppedBeans.get(6)));
}
@Test
public void singleSmartLifecycleShutdown() throws Exception {
CopyOnWriteArrayList stoppedBeans = new CopyOnWriteArrayList();
- TestSmartLifecycleBean bean = new TestSmartLifecycleBean(99, 300, stoppedBeans);
+ TestSmartLifecycleBean bean = TestSmartLifecycleBean.forShutdownTests(99, 300, stoppedBeans);
StaticApplicationContext context = new StaticApplicationContext();
context.getBeanFactory().registerSingleton("bean", bean);
context.refresh();
@@ -79,7 +220,7 @@ public class DefaultLifecycleProcessorTests {
@Test
public void singleLifecycleShutdown() throws Exception {
CopyOnWriteArrayList stoppedBeans = new CopyOnWriteArrayList();
- Lifecycle bean = new TestLifecycleBean(stoppedBeans);
+ Lifecycle bean = new TestLifecycleBean(null, stoppedBeans);
StaticApplicationContext context = new StaticApplicationContext();
context.getBeanFactory().registerSingleton("bean", bean);
context.refresh();
@@ -95,120 +236,277 @@ public class DefaultLifecycleProcessorTests {
@Test
public void mixedShutdown() throws Exception {
CopyOnWriteArrayList stoppedBeans = new CopyOnWriteArrayList();
- Lifecycle bean1 = new TestLifecycleBean(stoppedBeans);
- Lifecycle bean2 = new TestSmartLifecycleBean(500, 200, stoppedBeans);
- Lifecycle bean3 = new TestSmartLifecycleBean(Integer.MAX_VALUE, 100, stoppedBeans);
- Lifecycle bean4 = new TestLifecycleBean(stoppedBeans);
- Lifecycle bean5 = new TestSmartLifecycleBean(1, 200, stoppedBeans);
+ Lifecycle bean1 = TestLifecycleBean.forShutdownTests(stoppedBeans);
+ Lifecycle bean2 = TestSmartLifecycleBean.forShutdownTests(500, 200, stoppedBeans);
+ Lifecycle bean3 = TestSmartLifecycleBean.forShutdownTests(Integer.MAX_VALUE, 100, stoppedBeans);
+ Lifecycle bean4 = TestLifecycleBean.forShutdownTests(stoppedBeans);
+ Lifecycle bean5 = TestSmartLifecycleBean.forShutdownTests(1, 200, stoppedBeans);
+ Lifecycle bean6 = TestSmartLifecycleBean.forShutdownTests(-1, 100, stoppedBeans);
+ Lifecycle bean7 = TestSmartLifecycleBean.forShutdownTests(Integer.MIN_VALUE, 300, stoppedBeans);
StaticApplicationContext context = new StaticApplicationContext();
context.getBeanFactory().registerSingleton("bean1", bean1);
context.getBeanFactory().registerSingleton("bean2", bean2);
context.getBeanFactory().registerSingleton("bean3", bean3);
context.getBeanFactory().registerSingleton("bean4", bean4);
context.getBeanFactory().registerSingleton("bean5", bean5);
+ context.getBeanFactory().registerSingleton("bean6", bean6);
+ context.getBeanFactory().registerSingleton("bean7", bean7);
context.refresh();
+ assertTrue(bean2.isRunning());
+ assertTrue(bean3.isRunning());
+ assertTrue(bean5.isRunning());
+ assertTrue(bean6.isRunning());
+ assertTrue(bean7.isRunning());
assertFalse(bean1.isRunning());
assertFalse(bean4.isRunning());
bean1.start();
bean4.start();
assertTrue(bean1.isRunning());
- assertTrue(bean2.isRunning());
- assertTrue(bean3.isRunning());
assertTrue(bean4.isRunning());
- assertTrue(bean5.isRunning());
context.stop();
assertFalse(bean1.isRunning());
assertFalse(bean2.isRunning());
assertFalse(bean3.isRunning());
assertFalse(bean4.isRunning());
assertFalse(bean5.isRunning());
- assertEquals(5, stoppedBeans.size());
- assertEquals(1, getShutdownOrder(stoppedBeans.get(0)));
- assertEquals(500, getShutdownOrder(stoppedBeans.get(1)));
- assertEquals(Integer.MAX_VALUE, getShutdownOrder(stoppedBeans.get(2)));
- assertEquals(Integer.MAX_VALUE, getShutdownOrder(stoppedBeans.get(3)));
- assertEquals(Integer.MAX_VALUE, getShutdownOrder(stoppedBeans.get(4)));
+ assertFalse(bean6.isRunning());
+ assertFalse(bean7.isRunning());
+ assertEquals(7, stoppedBeans.size());
+ assertEquals(Integer.MAX_VALUE, getPhase(stoppedBeans.get(0)));
+ assertEquals(500, getPhase(stoppedBeans.get(1)));
+ assertEquals(1, getPhase(stoppedBeans.get(2)));
+ assertEquals(0, getPhase(stoppedBeans.get(3)));
+ assertEquals(0, getPhase(stoppedBeans.get(4)));
+ assertEquals(-1, getPhase(stoppedBeans.get(5)));
+ assertEquals(Integer.MIN_VALUE, getPhase(stoppedBeans.get(6)));
}
@Test
- public void dependantShutdownFirstEvenIfItsOrderIsHigher() throws Exception {
- CopyOnWriteArrayList stoppedBeans = new CopyOnWriteArrayList();
- TestSmartLifecycleBean bean1 = new TestSmartLifecycleBean(1, 200, stoppedBeans);
- TestSmartLifecycleBean bean99 = new TestSmartLifecycleBean(99, 100, stoppedBeans);
- TestSmartLifecycleBean bean2 = new TestSmartLifecycleBean(2, 300, stoppedBeans);
- TestSmartLifecycleBean bean7 = new TestSmartLifecycleBean(7, 400, stoppedBeans);
- TestSmartLifecycleBean beanLast = new TestSmartLifecycleBean(Integer.MAX_VALUE, 400, stoppedBeans);
+ public void dependencyStartedFirstEvenIfItsPhaseIsHigher() throws Exception {
+ CopyOnWriteArrayList startedBeans = new CopyOnWriteArrayList();
+ TestSmartLifecycleBean beanMin = TestSmartLifecycleBean.forStartupTests(Integer.MIN_VALUE, startedBeans);
+ TestSmartLifecycleBean bean2 = TestSmartLifecycleBean.forStartupTests(2, startedBeans);
+ TestSmartLifecycleBean bean99 = TestSmartLifecycleBean.forStartupTests(99, startedBeans);
+ TestSmartLifecycleBean beanMax = TestSmartLifecycleBean.forStartupTests(Integer.MAX_VALUE, startedBeans);
StaticApplicationContext context = new StaticApplicationContext();
+ context.getBeanFactory().registerSingleton("beanMin", beanMin);
+ context.getBeanFactory().registerSingleton("bean2", bean2);
+ context.getBeanFactory().registerSingleton("bean99", bean99);
+ context.getBeanFactory().registerSingleton("beanMax", beanMax);
+ context.getBeanFactory().registerDependentBean("bean99", "bean2");
+ context.refresh();
+ assertTrue(beanMin.isRunning());
+ assertTrue(bean2.isRunning());
+ assertTrue(bean99.isRunning());
+ assertTrue(beanMax.isRunning());
+ assertEquals(4, startedBeans.size());
+ assertEquals(Integer.MIN_VALUE, getPhase(startedBeans.get(0)));
+ assertEquals(99, getPhase(startedBeans.get(1)));
+ assertEquals(bean99, startedBeans.get(1));
+ assertEquals(2, getPhase(startedBeans.get(2)));
+ assertEquals(bean2, startedBeans.get(2));
+ assertEquals(Integer.MAX_VALUE, getPhase(startedBeans.get(3)));
+ context.stop();
+ }
+
+ @Test
+ public void dependentShutdownFirstEvenIfItsPhaseIsLower() throws Exception {
+ CopyOnWriteArrayList stoppedBeans = new CopyOnWriteArrayList();
+ TestSmartLifecycleBean beanMin = TestSmartLifecycleBean.forShutdownTests(Integer.MIN_VALUE, 100, stoppedBeans);
+ TestSmartLifecycleBean bean1 = TestSmartLifecycleBean.forShutdownTests(1, 200, stoppedBeans);
+ TestSmartLifecycleBean bean99 = TestSmartLifecycleBean.forShutdownTests(99, 100, stoppedBeans);
+ TestSmartLifecycleBean bean2 = TestSmartLifecycleBean.forShutdownTests(2, 300, stoppedBeans);
+ TestSmartLifecycleBean bean7 = TestSmartLifecycleBean.forShutdownTests(7, 400, stoppedBeans);
+ TestSmartLifecycleBean beanMax = TestSmartLifecycleBean.forShutdownTests(Integer.MAX_VALUE, 400, stoppedBeans);
+ StaticApplicationContext context = new StaticApplicationContext();
+ context.getBeanFactory().registerSingleton("beanMin", beanMin);
context.getBeanFactory().registerSingleton("bean1", bean1);
context.getBeanFactory().registerSingleton("bean2", bean2);
context.getBeanFactory().registerSingleton("bean7", bean7);
context.getBeanFactory().registerSingleton("bean99", bean99);
- context.getBeanFactory().registerSingleton("beanLast", beanLast);
- context.getBeanFactory().registerDependentBean("bean2", "bean99");
+ context.getBeanFactory().registerSingleton("beanMax", beanMax);
+ context.getBeanFactory().registerDependentBean("bean99", "bean2");
context.refresh();
+ assertTrue(beanMin.isRunning());
assertTrue(bean1.isRunning());
+ assertTrue(bean2.isRunning());
assertTrue(bean7.isRunning());
assertTrue(bean99.isRunning());
+ assertTrue(beanMax.isRunning());
context.stop();
+ assertFalse(beanMin.isRunning());
assertFalse(bean1.isRunning());
+ assertFalse(bean2.isRunning());
assertFalse(bean7.isRunning());
assertFalse(bean99.isRunning());
- assertEquals(5, stoppedBeans.size());
- assertEquals(1, getShutdownOrder(stoppedBeans.get(0)));
- assertEquals(99, getShutdownOrder(stoppedBeans.get(1)));
- assertEquals(2, getShutdownOrder(stoppedBeans.get(2)));
- assertEquals(7, getShutdownOrder(stoppedBeans.get(3)));
- assertEquals(Integer.MAX_VALUE, getShutdownOrder(stoppedBeans.get(4)));
+ assertFalse(beanMax.isRunning());
+ assertEquals(6, stoppedBeans.size());
+ assertEquals(Integer.MAX_VALUE, getPhase(stoppedBeans.get(0)));
+ assertEquals(2, getPhase(stoppedBeans.get(1)));
+ assertEquals(bean2, stoppedBeans.get(1));
+ assertEquals(99, getPhase(stoppedBeans.get(2)));
+ assertEquals(bean99, stoppedBeans.get(2));
+ assertEquals(7, getPhase(stoppedBeans.get(3)));
+ assertEquals(1, getPhase(stoppedBeans.get(4)));
+ assertEquals(Integer.MIN_VALUE, getPhase(stoppedBeans.get(5)));
}
@Test
- public void dependantShutdownFirstEvenIfNotSmartLifecycle() throws Exception {
- CopyOnWriteArrayList stoppedBeans = new CopyOnWriteArrayList();
- TestSmartLifecycleBean bean1 = new TestSmartLifecycleBean(1, 200, stoppedBeans);
- TestLifecycleBean simpleBean = new TestLifecycleBean(stoppedBeans);
- TestSmartLifecycleBean bean2 = new TestSmartLifecycleBean(2, 300, stoppedBeans);
- TestSmartLifecycleBean bean7 = new TestSmartLifecycleBean(7, 400, stoppedBeans);
- TestSmartLifecycleBean beanLast = new TestSmartLifecycleBean(Integer.MAX_VALUE, 400, stoppedBeans);
+ public void dependencyStartedFirstAndIsSmartLifecycle() throws Exception {
+ CopyOnWriteArrayList startedBeans = new CopyOnWriteArrayList();
+ TestSmartLifecycleBean beanNegative = TestSmartLifecycleBean.forStartupTests(-99, startedBeans);
+ TestSmartLifecycleBean bean99 = TestSmartLifecycleBean.forStartupTests(99, startedBeans);
+ TestSmartLifecycleBean bean7 = TestSmartLifecycleBean.forStartupTests(7, startedBeans);
+ TestLifecycleBean simpleBean = TestLifecycleBean.forStartupTests(startedBeans);
StaticApplicationContext context = new StaticApplicationContext();
+ context.getBeanFactory().registerSingleton("beanNegative", beanNegative);
+ context.getBeanFactory().registerSingleton("bean7", bean7);
+ context.getBeanFactory().registerSingleton("bean99", bean99);
+ context.getBeanFactory().registerSingleton("simpleBean", simpleBean);
+ context.getBeanFactory().registerDependentBean("bean7", "simpleBean");
+ context.refresh();
+ context.stop();
+ startedBeans.clear();
+ // clean start so that simpleBean is included
+ context.start();
+ assertTrue(beanNegative.isRunning());
+ assertTrue(bean99.isRunning());
+ assertTrue(bean7.isRunning());
+ assertTrue(simpleBean.isRunning());
+ assertEquals(4, startedBeans.size());
+ assertEquals(-99, getPhase(startedBeans.get(0)));
+ assertEquals(7, getPhase(startedBeans.get(1)));
+ assertEquals(0, getPhase(startedBeans.get(2)));
+ assertEquals(99, getPhase(startedBeans.get(3)));
+ context.stop();
+ }
+
+ @Test
+ public void dependentShutdownFirstAndIsSmartLifecycle() throws Exception {
+ CopyOnWriteArrayList stoppedBeans = new CopyOnWriteArrayList();
+ TestSmartLifecycleBean beanMin = TestSmartLifecycleBean.forShutdownTests(Integer.MIN_VALUE, 400, stoppedBeans);
+ TestSmartLifecycleBean beanNegative = TestSmartLifecycleBean.forShutdownTests(-99, 100, stoppedBeans);
+ TestSmartLifecycleBean bean1 = TestSmartLifecycleBean.forShutdownTests(1, 200, stoppedBeans);
+ TestSmartLifecycleBean bean2 = TestSmartLifecycleBean.forShutdownTests(2, 300, stoppedBeans);
+ TestSmartLifecycleBean bean7 = TestSmartLifecycleBean.forShutdownTests(7, 400, stoppedBeans);
+ TestLifecycleBean simpleBean = TestLifecycleBean.forShutdownTests(stoppedBeans);
+ StaticApplicationContext context = new StaticApplicationContext();
+ context.getBeanFactory().registerSingleton("beanMin", beanMin);
+ context.getBeanFactory().registerSingleton("beanNegative", beanNegative);
+ context.getBeanFactory().registerSingleton("bean1", bean1);
+ context.getBeanFactory().registerSingleton("bean2", bean2);
+ context.getBeanFactory().registerSingleton("bean7", bean7);
+ context.getBeanFactory().registerSingleton("simpleBean", simpleBean);
+ context.getBeanFactory().registerDependentBean("simpleBean", "beanNegative");
+ context.refresh();
+ assertTrue(beanMin.isRunning());
+ assertTrue(beanNegative.isRunning());
+ assertTrue(bean1.isRunning());
+ assertTrue(bean2.isRunning());
+ assertTrue(bean7.isRunning());
+ // should start since it's a dependency of an auto-started bean
+ assertTrue(simpleBean.isRunning());
+ context.stop();
+ assertFalse(beanMin.isRunning());
+ assertFalse(beanNegative.isRunning());
+ assertFalse(bean1.isRunning());
+ assertFalse(bean2.isRunning());
+ assertFalse(bean7.isRunning());
+ assertFalse(simpleBean.isRunning());
+ assertEquals(6, stoppedBeans.size());
+ assertEquals(7, getPhase(stoppedBeans.get(0)));
+ assertEquals(2, getPhase(stoppedBeans.get(1)));
+ assertEquals(1, getPhase(stoppedBeans.get(2)));
+ assertEquals(-99, getPhase(stoppedBeans.get(3)));
+ assertEquals(0, getPhase(stoppedBeans.get(4)));
+ assertEquals(Integer.MIN_VALUE, getPhase(stoppedBeans.get(5)));
+ }
+
+ @Test
+ public void dependencyStartedFirstButNotSmartLifecycle() throws Exception {
+ CopyOnWriteArrayList startedBeans = new CopyOnWriteArrayList();
+ TestSmartLifecycleBean beanMin = TestSmartLifecycleBean.forStartupTests(Integer.MIN_VALUE, startedBeans);
+ TestSmartLifecycleBean bean7 = TestSmartLifecycleBean.forStartupTests(7, startedBeans);
+ TestLifecycleBean simpleBean = TestLifecycleBean.forStartupTests(startedBeans);
+ StaticApplicationContext context = new StaticApplicationContext();
+ context.getBeanFactory().registerSingleton("beanMin", beanMin);
+ context.getBeanFactory().registerSingleton("bean7", bean7);
+ context.getBeanFactory().registerSingleton("simpleBean", simpleBean);
+ context.getBeanFactory().registerDependentBean("simpleBean", "beanMin");
+ context.refresh();
+ assertTrue(beanMin.isRunning());
+ assertTrue(bean7.isRunning());
+ assertTrue(simpleBean.isRunning());
+ assertEquals(3, startedBeans.size());
+ assertEquals(0, getPhase(startedBeans.get(0)));
+ assertEquals(Integer.MIN_VALUE, getPhase(startedBeans.get(1)));
+ assertEquals(7, getPhase(startedBeans.get(2)));
+ context.stop();
+ }
+
+ @Test
+ public void dependentShutdownFirstButNotSmartLifecycle() throws Exception {
+ CopyOnWriteArrayList stoppedBeans = new CopyOnWriteArrayList();
+ TestSmartLifecycleBean bean1 = TestSmartLifecycleBean.forShutdownTests(1, 200, stoppedBeans);
+ TestLifecycleBean simpleBean = TestLifecycleBean.forShutdownTests(stoppedBeans);
+ TestSmartLifecycleBean bean2 = TestSmartLifecycleBean.forShutdownTests(2, 300, stoppedBeans);
+ TestSmartLifecycleBean bean7 = TestSmartLifecycleBean.forShutdownTests(7, 400, stoppedBeans);
+ TestSmartLifecycleBean beanMin = TestSmartLifecycleBean.forShutdownTests(Integer.MIN_VALUE, 400, stoppedBeans);
+ StaticApplicationContext context = new StaticApplicationContext();
+ context.getBeanFactory().registerSingleton("beanMin", beanMin);
context.getBeanFactory().registerSingleton("bean1", bean1);
context.getBeanFactory().registerSingleton("bean2", bean2);
context.getBeanFactory().registerSingleton("bean7", bean7);
context.getBeanFactory().registerSingleton("simpleBean", simpleBean);
- context.getBeanFactory().registerSingleton("beanLast", beanLast);
context.getBeanFactory().registerDependentBean("bean2", "simpleBean");
context.refresh();
+ assertTrue(beanMin.isRunning());
assertTrue(bean1.isRunning());
+ assertTrue(bean2.isRunning());
assertTrue(bean7.isRunning());
assertFalse(simpleBean.isRunning());
simpleBean.start();
assertTrue(simpleBean.isRunning());
context.stop();
+ assertFalse(beanMin.isRunning());
assertFalse(bean1.isRunning());
+ assertFalse(bean2.isRunning());
assertFalse(bean7.isRunning());
assertFalse(simpleBean.isRunning());
assertEquals(5, stoppedBeans.size());
- assertEquals(1, getShutdownOrder(stoppedBeans.get(0)));
- assertEquals(Integer.MAX_VALUE, getShutdownOrder(stoppedBeans.get(1)));
- assertEquals(2, getShutdownOrder(stoppedBeans.get(2)));
- assertEquals(7, getShutdownOrder(stoppedBeans.get(3)));
- assertEquals(Integer.MAX_VALUE, getShutdownOrder(stoppedBeans.get(4)));
+ assertEquals(7, getPhase(stoppedBeans.get(0)));
+ assertEquals(0, getPhase(stoppedBeans.get(1)));
+ assertEquals(2, getPhase(stoppedBeans.get(2)));
+ assertEquals(1, getPhase(stoppedBeans.get(3)));
+ assertEquals(Integer.MIN_VALUE, getPhase(stoppedBeans.get(4)));
}
- private static int getShutdownOrder(Lifecycle lifecycle) {
+ private static int getPhase(Lifecycle lifecycle) {
return (lifecycle instanceof SmartLifecycle) ?
- ((SmartLifecycle) lifecycle).getShutdownOrder() : Integer.MAX_VALUE;
+ ((SmartLifecycle) lifecycle).getPhase() : 0;
}
- private class TestLifecycleBean implements Lifecycle {
+ private static class TestLifecycleBean implements Lifecycle {
- protected final CopyOnWriteArrayList stoppedBeans;
+ private final CopyOnWriteArrayList startedBeans;
+
+ private final CopyOnWriteArrayList stoppedBeans;
private volatile boolean running;
- TestLifecycleBean(CopyOnWriteArrayList stoppedBeans) {
+ static TestLifecycleBean forStartupTests(CopyOnWriteArrayList startedBeans) {
+ return new TestLifecycleBean(startedBeans, null);
+ }
+
+ static TestLifecycleBean forShutdownTests(CopyOnWriteArrayList stoppedBeans) {
+ return new TestLifecycleBean(null, stoppedBeans);
+ }
+
+ private TestLifecycleBean(CopyOnWriteArrayList startedBeans, CopyOnWriteArrayList stoppedBeans) {
+ this.startedBeans = startedBeans;
this.stoppedBeans = stoppedBeans;
}
@@ -217,45 +515,65 @@ public class DefaultLifecycleProcessorTests {
}
public void start() {
+ if (this.startedBeans != null) {
+ this.startedBeans.add(this);
+ }
this.running = true;
}
public void stop() {
- this.stoppedBeans.add(this);
+ if (this.stoppedBeans != null) {
+ this.stoppedBeans.add(this);
+ }
this.running = false;
}
}
- private class TestSmartLifecycleBean extends TestLifecycleBean implements SmartLifecycle {
+ private static class TestSmartLifecycleBean extends TestLifecycleBean implements SmartLifecycle {
- private final int shutdownOrder;
+ private final int phase;
private final int shutdownDelay;
+ private volatile boolean autoStartup = true;
- TestSmartLifecycleBean(int shutdownOrder, int shutdownDelay, CopyOnWriteArrayList stoppedBeans) {
- super(stoppedBeans);
- this.shutdownOrder = shutdownOrder;
+ static TestSmartLifecycleBean forStartupTests(int phase, CopyOnWriteArrayList startedBeans) {
+ return new TestSmartLifecycleBean(phase, 0, startedBeans, null);
+ }
+
+ static TestSmartLifecycleBean forShutdownTests(int phase, int shutdownDelay, CopyOnWriteArrayList stoppedBeans) {
+ return new TestSmartLifecycleBean(phase, shutdownDelay, null, stoppedBeans);
+ }
+
+ private TestSmartLifecycleBean(int phase, int shutdownDelay, CopyOnWriteArrayList startedBeans, CopyOnWriteArrayList stoppedBeans) {
+ super(startedBeans, stoppedBeans);
+ this.phase = phase;
this.shutdownDelay = shutdownDelay;
}
- public int getShutdownOrder() {
- return this.shutdownOrder;
+ public int getPhase() {
+ return this.phase;
}
public boolean isAutoStartup() {
- return true;
+ return this.autoStartup;
+ }
+
+ public void setAutoStartup(boolean autoStartup) {
+ this.autoStartup = autoStartup;
}
public void stop(final Runnable callback) {
+ // calling stop() before the delay to preserve
+ // invocation order in the 'stoppedBeans' list
+ stop();
final int delay = this.shutdownDelay;
new Thread(new Runnable() {
public void run() {
try {
Thread.sleep(delay);
- stop();
}
catch (InterruptedException e) {
// ignore
diff --git a/org.springframework.jms/src/main/java/org/springframework/jms/listener/AbstractJmsListeningContainer.java b/org.springframework.jms/src/main/java/org/springframework/jms/listener/AbstractJmsListeningContainer.java
index a3d5e01536..975798ace2 100644
--- a/org.springframework.jms/src/main/java/org/springframework/jms/listener/AbstractJmsListeningContainer.java
+++ b/org.springframework.jms/src/main/java/org/springframework/jms/listener/AbstractJmsListeningContainer.java
@@ -65,7 +65,7 @@ public abstract class AbstractJmsListeningContainer extends JmsDestinationAccess
private boolean autoStartup = true;
- private int shutdownOrder = Integer.MAX_VALUE;
+ private int phase = Integer.MAX_VALUE;
private String beanName;
@@ -119,18 +119,21 @@ public abstract class AbstractJmsListeningContainer extends JmsDestinationAccess
}
/**
- * Specify the order in which this container should be stopped.
- * By default it will be stopped in the last group.
+ * Specify the phase in which this container should be started and
+ * stopped. The startup order proceeds from lowest to highest, and
+ * the shutdown order is the reverse of that. By default this value
+ * is Integer.MAX_VALUE meaning that this container starts as late
+ * as possible and stops as soon as possible.
*/
- public void setShutdownOrder(int shutdownOrder) {
- this.shutdownOrder = shutdownOrder;
+ public void setPhase(int phase) {
+ this.phase = phase;
}
/**
- * Return the order in which this container will be stopped.
+ * Return the phase in which this container will be started and stopped.
*/
- public int getShutdownOrder() {
- return this.shutdownOrder;
+ public int getPhase() {
+ return this.phase;
}
public void setBeanName(String beanName) {
diff --git a/org.springframework.transaction/src/main/java/org/springframework/jca/endpoint/GenericMessageEndpointManager.java b/org.springframework.transaction/src/main/java/org/springframework/jca/endpoint/GenericMessageEndpointManager.java
index 3993bcb425..56682b49fd 100644
--- a/org.springframework.transaction/src/main/java/org/springframework/jca/endpoint/GenericMessageEndpointManager.java
+++ b/org.springframework.transaction/src/main/java/org/springframework/jca/endpoint/GenericMessageEndpointManager.java
@@ -154,7 +154,7 @@ public class GenericMessageEndpointManager implements SmartLifecycle, Initializi
private boolean autoStartup = true;
- private int shutdownOrder = Integer.MAX_VALUE;
+ private int phase = Integer.MAX_VALUE;
private boolean running = false;
@@ -229,18 +229,21 @@ public class GenericMessageEndpointManager implements SmartLifecycle, Initializi
}
/**
- * Specify the order in which this endpoint manager should be stopped.
- * By default it will be stopped in the last group.
+ * Specify the phase in which this endpoint manager should be started
+ * and stopped. The startup order proceeds from lowest to highest, and
+ * the shutdown order is the reverse of that. By default this value is
+ * Integer.MAX_VALUE meaning that this endpoint manager starts as late
+ * as possible and stops as soon as possible.
*/
- public void setShutdownOrder(int shutdownOrder) {
- this.shutdownOrder = shutdownOrder;
+ public void setPhase(int phase) {
+ this.phase = phase;
}
/**
- * Return the order in which this endpoint manager will be stopped.
+ * Return the phase in which this endpoint manager will be started and stopped.
*/
- public int getShutdownOrder() {
- return this.shutdownOrder;
+ public int getPhase() {
+ return this.phase;
}
/**