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; } /**