/* * Copyright 2002-2016 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.springframework.context.support; import java.util.concurrent.CopyOnWriteArrayList; import org.junit.Test; import org.springframework.beans.DirectFieldAccessor; import org.springframework.beans.factory.FactoryBean; import org.springframework.beans.factory.config.BeanDefinition; import org.springframework.beans.factory.support.RootBeanDefinition; import org.springframework.context.Lifecycle; import org.springframework.context.LifecycleProcessor; import org.springframework.context.SmartLifecycle; import org.springframework.tests.Assume; import org.springframework.tests.TestGroup; import static org.junit.Assert.*; /** * @author Mark Fisher * @since 3.0 */ public class DefaultLifecycleProcessorTests { @Test public void defaultLifecycleProcessorInstance() { StaticApplicationContext context = new StaticApplicationContext(); context.refresh(); Object lifecycleProcessor = new DirectFieldAccessor(context).getPropertyValue("lifecycleProcessor"); assertNotNull(lifecycleProcessor); assertEquals(DefaultLifecycleProcessor.class, lifecycleProcessor.getClass()); } @Test public void customLifecycleProcessorInstance() { BeanDefinition beanDefinition = new RootBeanDefinition(DefaultLifecycleProcessor.class); beanDefinition.getPropertyValues().addPropertyValue("timeoutPerShutdownPhase", 1000); StaticApplicationContext context = new StaticApplicationContext(); context.registerBeanDefinition("lifecycleProcessor", beanDefinition); context.refresh(); LifecycleProcessor bean = context.getBean("lifecycleProcessor", LifecycleProcessor.class); Object contextLifecycleProcessor = new DirectFieldAccessor(context).getPropertyValue("lifecycleProcessor"); assertNotNull(contextLifecycleProcessor); assertSame(bean, contextLifecycleProcessor); assertEquals(1000L, new DirectFieldAccessor(contextLifecycleProcessor).getPropertyValue( "timeoutPerShutdownPhase")); } @Test public void singleSmartLifecycleAutoStartup() throws Exception { CopyOnWriteArrayList<Lifecycle> 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 singleSmartLifecycleAutoStartupWithLazyInit() throws Exception { StaticApplicationContext context = new StaticApplicationContext(); RootBeanDefinition bd = new RootBeanDefinition(DummySmartLifecycleBean.class); bd.setLazyInit(true); context.registerBeanDefinition("bean", bd); context.refresh(); DummySmartLifecycleBean bean = context.getBean("bean", DummySmartLifecycleBean.class); assertTrue(bean.isRunning()); context.stop(); assertFalse(bean.isRunning()); } @Test public void singleSmartLifecycleAutoStartupWithLazyInitFactoryBean() throws Exception { StaticApplicationContext context = new StaticApplicationContext(); RootBeanDefinition bd = new RootBeanDefinition(DummySmartLifecycleFactoryBean.class); bd.setLazyInit(true); context.registerBeanDefinition("bean", bd); context.refresh(); DummySmartLifecycleFactoryBean bean = context.getBean("&bean", DummySmartLifecycleFactoryBean.class); assertTrue(bean.isRunning()); context.stop(); assertFalse(bean.isRunning()); } @Test public void singleSmartLifecycleWithoutAutoStartup() throws Exception { CopyOnWriteArrayList<Lifecycle> 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 singleSmartLifecycleAutoStartupWithNonAutoStartupDependency() throws Exception { CopyOnWriteArrayList<Lifecycle> startedBeans = new CopyOnWriteArrayList<>(); TestSmartLifecycleBean bean = TestSmartLifecycleBean.forStartupTests(1, startedBeans); bean.setAutoStartup(true); TestSmartLifecycleBean dependency = TestSmartLifecycleBean.forStartupTests(1, startedBeans); dependency.setAutoStartup(false); StaticApplicationContext context = new StaticApplicationContext(); context.getBeanFactory().registerSingleton("bean", bean); context.getBeanFactory().registerSingleton("dependency", dependency); context.getBeanFactory().registerDependentBean("dependency", "bean"); assertFalse(bean.isRunning()); assertFalse(dependency.isRunning()); context.refresh(); assertTrue(bean.isRunning()); assertFalse(dependency.isRunning()); context.stop(); assertFalse(bean.isRunning()); assertFalse(dependency.isRunning()); assertEquals(1, startedBeans.size()); } @Test public void smartLifecycleGroupStartup() throws Exception { CopyOnWriteArrayList<Lifecycle> 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<Lifecycle> 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<Lifecycle> 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 { Assume.group(TestGroup.PERFORMANCE); CopyOnWriteArrayList<Lifecycle> stoppedBeans = new CopyOnWriteArrayList<>(); 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); 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(); context.stop(); 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 { Assume.group(TestGroup.PERFORMANCE); CopyOnWriteArrayList<Lifecycle> stoppedBeans = new CopyOnWriteArrayList<>(); TestSmartLifecycleBean bean = TestSmartLifecycleBean.forShutdownTests(99, 300, stoppedBeans); StaticApplicationContext context = new StaticApplicationContext(); context.getBeanFactory().registerSingleton("bean", bean); context.refresh(); assertTrue(bean.isRunning()); context.stop(); assertEquals(1, stoppedBeans.size()); assertFalse(bean.isRunning()); assertEquals(bean, stoppedBeans.get(0)); } @Test public void singleLifecycleShutdown() throws Exception { CopyOnWriteArrayList<Lifecycle> stoppedBeans = new CopyOnWriteArrayList<>(); Lifecycle bean = new TestLifecycleBean(null, stoppedBeans); StaticApplicationContext context = new StaticApplicationContext(); context.getBeanFactory().registerSingleton("bean", bean); context.refresh(); assertFalse(bean.isRunning()); bean.start(); assertTrue(bean.isRunning()); context.stop(); assertEquals(1, stoppedBeans.size()); assertFalse(bean.isRunning()); assertEquals(bean, stoppedBeans.get(0)); } @Test public void mixedShutdown() throws Exception { CopyOnWriteArrayList<Lifecycle> stoppedBeans = new CopyOnWriteArrayList<>(); 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(bean4.isRunning()); context.stop(); assertFalse(bean1.isRunning()); assertFalse(bean2.isRunning()); assertFalse(bean3.isRunning()); assertFalse(bean4.isRunning()); assertFalse(bean5.isRunning()); 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 dependencyStartedFirstEvenIfItsPhaseIsHigher() throws Exception { CopyOnWriteArrayList<Lifecycle> 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 { Assume.group(TestGroup.PERFORMANCE); CopyOnWriteArrayList<Lifecycle> 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("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()); 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 dependencyStartedFirstAndIsSmartLifecycle() throws Exception { CopyOnWriteArrayList<Lifecycle> 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 { Assume.group(TestGroup.PERFORMANCE); CopyOnWriteArrayList<Lifecycle> 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<Lifecycle> 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 { Assume.group(TestGroup.PERFORMANCE); CopyOnWriteArrayList<Lifecycle> 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().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(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 getPhase(Lifecycle lifecycle) { return (lifecycle instanceof SmartLifecycle) ? ((SmartLifecycle) lifecycle).getPhase() : 0; } private static class TestLifecycleBean implements Lifecycle { private final CopyOnWriteArrayList<Lifecycle> startedBeans; private final CopyOnWriteArrayList<Lifecycle> stoppedBeans; private volatile boolean running; static TestLifecycleBean forStartupTests(CopyOnWriteArrayList<Lifecycle> startedBeans) { return new TestLifecycleBean(startedBeans, null); } static TestLifecycleBean forShutdownTests(CopyOnWriteArrayList<Lifecycle> stoppedBeans) { return new TestLifecycleBean(null, stoppedBeans); } private TestLifecycleBean(CopyOnWriteArrayList<Lifecycle> startedBeans, CopyOnWriteArrayList<Lifecycle> stoppedBeans) { this.startedBeans = startedBeans; this.stoppedBeans = stoppedBeans; } @Override public boolean isRunning() { return this.running; } @Override public void start() { if (this.startedBeans != null) { this.startedBeans.add(this); } this.running = true; } @Override public void stop() { if (this.stoppedBeans != null) { this.stoppedBeans.add(this); } this.running = false; } } private static class TestSmartLifecycleBean extends TestLifecycleBean implements SmartLifecycle { private final int phase; private final int shutdownDelay; private volatile boolean autoStartup = true; static TestSmartLifecycleBean forStartupTests(int phase, CopyOnWriteArrayList<Lifecycle> startedBeans) { return new TestSmartLifecycleBean(phase, 0, startedBeans, null); } static TestSmartLifecycleBean forShutdownTests(int phase, int shutdownDelay, CopyOnWriteArrayList<Lifecycle> stoppedBeans) { return new TestSmartLifecycleBean(phase, shutdownDelay, null, stoppedBeans); } private TestSmartLifecycleBean(int phase, int shutdownDelay, CopyOnWriteArrayList<Lifecycle> startedBeans, CopyOnWriteArrayList<Lifecycle> stoppedBeans) { super(startedBeans, stoppedBeans); this.phase = phase; this.shutdownDelay = shutdownDelay; } @Override public int getPhase() { return this.phase; } @Override public boolean isAutoStartup() { return this.autoStartup; } public void setAutoStartup(boolean autoStartup) { this.autoStartup = autoStartup; } @Override 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() { @Override public void run() { try { Thread.sleep(delay); } catch (InterruptedException e) { // ignore } finally { callback.run(); } } }).start(); } } public static class DummySmartLifecycleBean implements SmartLifecycle { public boolean running = false; @Override public boolean isAutoStartup() { return true; } @Override public void stop(Runnable callback) { this.running = false; callback.run(); } @Override public void start() { this.running = true; } @Override public void stop() { this.running = false; } @Override public boolean isRunning() { return this.running; } @Override public int getPhase() { return 0; } } public static class DummySmartLifecycleFactoryBean implements FactoryBean<Object>, SmartLifecycle { public boolean running = false; DummySmartLifecycleBean bean = new DummySmartLifecycleBean(); @Override public Object getObject() throws Exception { return this.bean; } @Override public Class<?> getObjectType() { return DummySmartLifecycleBean.class; } @Override public boolean isSingleton() { return true; } @Override public boolean isAutoStartup() { return true; } @Override public void stop(Runnable callback) { this.running = false; callback.run(); } @Override public void start() { this.running = true; } @Override public void stop() { this.running = false; } @Override public boolean isRunning() { return this.running; } @Override public int getPhase() { return 0; } } }