View Javadoc
1   /*
2    * Copyright 2002-2013 the original author or authors.
3    *
4    * Licensed under the Apache License, Version 2.0 (the "License");
5    * you may not use this file except in compliance with the License.
6    * You may obtain a copy of the License at
7    *
8    *      http://www.apache.org/licenses/LICENSE-2.0
9    *
10   * Unless required by applicable law or agreed to in writing, software
11   * distributed under the License is distributed on an "AS IS" BASIS,
12   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13   * See the License for the specific language governing permissions and
14   * limitations under the License.
15   */
16  
17  package org.springframework.context.support;
18  
19  import java.util.concurrent.CopyOnWriteArrayList;
20  
21  import org.junit.Test;
22  
23  import org.springframework.beans.DirectFieldAccessor;
24  import org.springframework.beans.factory.FactoryBean;
25  import org.springframework.beans.factory.config.BeanDefinition;
26  import org.springframework.beans.factory.support.RootBeanDefinition;
27  import org.springframework.context.Lifecycle;
28  import org.springframework.context.LifecycleProcessor;
29  import org.springframework.context.SmartLifecycle;
30  import org.springframework.tests.Assume;
31  import org.springframework.tests.TestGroup;
32  
33  import static org.junit.Assert.*;
34  
35  /**
36   * @author Mark Fisher
37   * @since 3.0
38   */
39  public class DefaultLifecycleProcessorTests {
40  
41  	@Test
42  	public void defaultLifecycleProcessorInstance() {
43  		StaticApplicationContext context = new StaticApplicationContext();
44  		context.refresh();
45  		Object lifecycleProcessor = new DirectFieldAccessor(context).getPropertyValue("lifecycleProcessor");
46  		assertNotNull(lifecycleProcessor);
47  		assertEquals(DefaultLifecycleProcessor.class, lifecycleProcessor.getClass());
48  	}
49  
50  	@Test
51  	public void customLifecycleProcessorInstance() {
52  		BeanDefinition beanDefinition = new RootBeanDefinition(DefaultLifecycleProcessor.class);
53  		beanDefinition.getPropertyValues().addPropertyValue("timeoutPerShutdownPhase", 1000);
54  		StaticApplicationContext context = new StaticApplicationContext();
55  		context.registerBeanDefinition("lifecycleProcessor", beanDefinition);
56  		context.refresh();
57  		LifecycleProcessor bean = context.getBean("lifecycleProcessor", LifecycleProcessor.class);
58  		Object contextLifecycleProcessor = new DirectFieldAccessor(context).getPropertyValue("lifecycleProcessor");
59  		assertNotNull(contextLifecycleProcessor);
60  		assertSame(bean, contextLifecycleProcessor);
61  		assertEquals(1000L, new DirectFieldAccessor(contextLifecycleProcessor).getPropertyValue(
62  				"timeoutPerShutdownPhase"));
63  	}
64  
65  	@Test
66  	public void singleSmartLifecycleAutoStartup() throws Exception {
67  		CopyOnWriteArrayList<Lifecycle> startedBeans = new CopyOnWriteArrayList<Lifecycle>();
68  		TestSmartLifecycleBean bean = TestSmartLifecycleBean.forStartupTests(1, startedBeans);
69  		bean.setAutoStartup(true);
70  		StaticApplicationContext context = new StaticApplicationContext();
71  		context.getBeanFactory().registerSingleton("bean", bean);
72  		assertFalse(bean.isRunning());
73  		context.refresh();
74  		assertTrue(bean.isRunning());
75  		context.stop();
76  		assertFalse(bean.isRunning());
77  		assertEquals(1, startedBeans.size());
78  	}
79  
80  	@Test
81  	public void singleSmartLifecycleAutoStartupWithLazyInit() throws Exception {
82  		StaticApplicationContext context = new StaticApplicationContext();
83  		RootBeanDefinition bd = new RootBeanDefinition(DummySmartLifecycleBean.class);
84  		bd.setLazyInit(true);
85  		context.registerBeanDefinition("bean", bd);
86  		context.refresh();
87  		DummySmartLifecycleBean bean = context.getBean("bean", DummySmartLifecycleBean.class);
88  		assertTrue(bean.isRunning());
89  		context.stop();
90  		assertFalse(bean.isRunning());
91  	}
92  
93  	@Test
94  	public void singleSmartLifecycleAutoStartupWithLazyInitFactoryBean() throws Exception {
95  		StaticApplicationContext context = new StaticApplicationContext();
96  		RootBeanDefinition bd = new RootBeanDefinition(DummySmartLifecycleFactoryBean.class);
97  		bd.setLazyInit(true);
98  		context.registerBeanDefinition("bean", bd);
99  		context.refresh();
100 		DummySmartLifecycleFactoryBean bean = context.getBean("&bean", DummySmartLifecycleFactoryBean.class);
101 		assertTrue(bean.isRunning());
102 		context.stop();
103 		assertFalse(bean.isRunning());
104 	}
105 
106 	@Test
107 	public void singleSmartLifecycleWithoutAutoStartup() throws Exception {
108 		CopyOnWriteArrayList<Lifecycle> startedBeans = new CopyOnWriteArrayList<Lifecycle>();
109 		TestSmartLifecycleBean bean = TestSmartLifecycleBean.forStartupTests(1, startedBeans);
110 		bean.setAutoStartup(false);
111 		StaticApplicationContext context = new StaticApplicationContext();
112 		context.getBeanFactory().registerSingleton("bean", bean);
113 		assertFalse(bean.isRunning());
114 		context.refresh();
115 		assertFalse(bean.isRunning());
116 		assertEquals(0, startedBeans.size());
117 		context.start();
118 		assertTrue(bean.isRunning());
119 		assertEquals(1, startedBeans.size());
120 		context.stop();
121 	}
122 
123 	@Test
124 	public void singleSmartLifecycleAutoStartupWithNonAutoStartupDependency() throws Exception {
125 		CopyOnWriteArrayList<Lifecycle> startedBeans = new CopyOnWriteArrayList<Lifecycle>();
126 		TestSmartLifecycleBean bean = TestSmartLifecycleBean.forStartupTests(1, startedBeans);
127 		bean.setAutoStartup(true);
128 		TestSmartLifecycleBean dependency = TestSmartLifecycleBean.forStartupTests(1, startedBeans);
129 		dependency.setAutoStartup(false);
130 		StaticApplicationContext context = new StaticApplicationContext();
131 		context.getBeanFactory().registerSingleton("bean", bean);
132 		context.getBeanFactory().registerSingleton("dependency", dependency);
133 		context.getBeanFactory().registerDependentBean("dependency", "bean");
134 		assertFalse(bean.isRunning());
135 		assertFalse(dependency.isRunning());
136 		context.refresh();
137 		assertTrue(bean.isRunning());
138 		assertFalse(dependency.isRunning());
139 		context.stop();
140 		assertFalse(bean.isRunning());
141 		assertFalse(dependency.isRunning());
142 		assertEquals(1, startedBeans.size());
143 	}
144 
145 	@Test
146 	public void smartLifecycleGroupStartup() throws Exception {
147 		CopyOnWriteArrayList<Lifecycle> startedBeans = new CopyOnWriteArrayList<Lifecycle>();
148 		TestSmartLifecycleBean beanMin = TestSmartLifecycleBean.forStartupTests(Integer.MIN_VALUE, startedBeans);
149 		TestSmartLifecycleBean bean1 = TestSmartLifecycleBean.forStartupTests(1, startedBeans);
150 		TestSmartLifecycleBean bean2 = TestSmartLifecycleBean.forStartupTests(2, startedBeans);
151 		TestSmartLifecycleBean bean3 = TestSmartLifecycleBean.forStartupTests(3, startedBeans);
152 		TestSmartLifecycleBean beanMax = TestSmartLifecycleBean.forStartupTests(Integer.MAX_VALUE, startedBeans);
153 		StaticApplicationContext context = new StaticApplicationContext();
154 		context.getBeanFactory().registerSingleton("bean3", bean3);
155 		context.getBeanFactory().registerSingleton("beanMin", beanMin);
156 		context.getBeanFactory().registerSingleton("bean2", bean2);
157 		context.getBeanFactory().registerSingleton("beanMax", beanMax);
158 		context.getBeanFactory().registerSingleton("bean1", bean1);
159 		assertFalse(beanMin.isRunning());
160 		assertFalse(bean1.isRunning());
161 		assertFalse(bean2.isRunning());
162 		assertFalse(bean3.isRunning());
163 		assertFalse(beanMax.isRunning());
164 		context.refresh();
165 		assertTrue(beanMin.isRunning());
166 		assertTrue(bean1.isRunning());
167 		assertTrue(bean2.isRunning());
168 		assertTrue(bean3.isRunning());
169 		assertTrue(beanMax.isRunning());
170 		context.stop();
171 		assertEquals(5, startedBeans.size());
172 		assertEquals(Integer.MIN_VALUE, getPhase(startedBeans.get(0)));
173 		assertEquals(1, getPhase(startedBeans.get(1)));
174 		assertEquals(2, getPhase(startedBeans.get(2)));
175 		assertEquals(3, getPhase(startedBeans.get(3)));
176 		assertEquals(Integer.MAX_VALUE, getPhase(startedBeans.get(4)));
177 	}
178 
179 	@Test
180 	public void contextRefreshThenStartWithMixedBeans() throws Exception {
181 		CopyOnWriteArrayList<Lifecycle> startedBeans = new CopyOnWriteArrayList<Lifecycle>();
182 		TestLifecycleBean simpleBean1 = TestLifecycleBean.forStartupTests(startedBeans);
183 		TestLifecycleBean simpleBean2 = TestLifecycleBean.forStartupTests(startedBeans);
184 		TestSmartLifecycleBean smartBean1 = TestSmartLifecycleBean.forStartupTests(5, startedBeans);
185 		TestSmartLifecycleBean smartBean2 = TestSmartLifecycleBean.forStartupTests(-3, startedBeans);
186 		StaticApplicationContext context = new StaticApplicationContext();
187 		context.getBeanFactory().registerSingleton("simpleBean1", simpleBean1);
188 		context.getBeanFactory().registerSingleton("smartBean1", smartBean1);
189 		context.getBeanFactory().registerSingleton("simpleBean2", simpleBean2);
190 		context.getBeanFactory().registerSingleton("smartBean2", smartBean2);
191 		assertFalse(simpleBean1.isRunning());
192 		assertFalse(simpleBean2.isRunning());
193 		assertFalse(smartBean1.isRunning());
194 		assertFalse(smartBean2.isRunning());
195 		context.refresh();
196 		assertTrue(smartBean1.isRunning());
197 		assertTrue(smartBean2.isRunning());
198 		assertFalse(simpleBean1.isRunning());
199 		assertFalse(simpleBean2.isRunning());
200 		assertEquals(2, startedBeans.size());
201 		assertEquals(-3, getPhase(startedBeans.get(0)));
202 		assertEquals(5, getPhase(startedBeans.get(1)));
203 		context.start();
204 		assertTrue(smartBean1.isRunning());
205 		assertTrue(smartBean2.isRunning());
206 		assertTrue(simpleBean1.isRunning());
207 		assertTrue(simpleBean2.isRunning());
208 		assertEquals(4, startedBeans.size());
209 		assertEquals(0, getPhase(startedBeans.get(2)));
210 		assertEquals(0, getPhase(startedBeans.get(3)));
211 	}
212 
213 	@Test
214 	public void contextRefreshThenStopAndRestartWithMixedBeans() throws Exception {
215 		CopyOnWriteArrayList<Lifecycle> startedBeans = new CopyOnWriteArrayList<Lifecycle>();
216 		TestLifecycleBean simpleBean1 = TestLifecycleBean.forStartupTests(startedBeans);
217 		TestLifecycleBean simpleBean2 = TestLifecycleBean.forStartupTests(startedBeans);
218 		TestSmartLifecycleBean smartBean1 = TestSmartLifecycleBean.forStartupTests(5, startedBeans);
219 		TestSmartLifecycleBean smartBean2 = TestSmartLifecycleBean.forStartupTests(-3, startedBeans);
220 		StaticApplicationContext context = new StaticApplicationContext();
221 		context.getBeanFactory().registerSingleton("simpleBean1", simpleBean1);
222 		context.getBeanFactory().registerSingleton("smartBean1", smartBean1);
223 		context.getBeanFactory().registerSingleton("simpleBean2", simpleBean2);
224 		context.getBeanFactory().registerSingleton("smartBean2", smartBean2);
225 		assertFalse(simpleBean1.isRunning());
226 		assertFalse(simpleBean2.isRunning());
227 		assertFalse(smartBean1.isRunning());
228 		assertFalse(smartBean2.isRunning());
229 		context.refresh();
230 		assertTrue(smartBean1.isRunning());
231 		assertTrue(smartBean2.isRunning());
232 		assertFalse(simpleBean1.isRunning());
233 		assertFalse(simpleBean2.isRunning());
234 		assertEquals(2, startedBeans.size());
235 		assertEquals(-3, getPhase(startedBeans.get(0)));
236 		assertEquals(5, getPhase(startedBeans.get(1)));
237 		context.stop();
238 		assertFalse(simpleBean1.isRunning());
239 		assertFalse(simpleBean2.isRunning());
240 		assertFalse(smartBean1.isRunning());
241 		assertFalse(smartBean2.isRunning());
242 		context.start();
243 		assertTrue(smartBean1.isRunning());
244 		assertTrue(smartBean2.isRunning());
245 		assertTrue(simpleBean1.isRunning());
246 		assertTrue(simpleBean2.isRunning());
247 		assertEquals(6, startedBeans.size());
248 		assertEquals(-3, getPhase(startedBeans.get(2)));
249 		assertEquals(0, getPhase(startedBeans.get(3)));
250 		assertEquals(0, getPhase(startedBeans.get(4)));
251 		assertEquals(5, getPhase(startedBeans.get(5)));
252 	}
253 
254 	@Test
255 	public void smartLifecycleGroupShutdown() throws Exception {
256 		Assume.group(TestGroup.PERFORMANCE);
257 
258 		CopyOnWriteArrayList<Lifecycle> stoppedBeans = new CopyOnWriteArrayList<Lifecycle>();
259 		TestSmartLifecycleBean bean1 = TestSmartLifecycleBean.forShutdownTests(1, 300, stoppedBeans);
260 		TestSmartLifecycleBean bean2 = TestSmartLifecycleBean.forShutdownTests(3, 100, stoppedBeans);
261 		TestSmartLifecycleBean bean3 = TestSmartLifecycleBean.forShutdownTests(1, 600, stoppedBeans);
262 		TestSmartLifecycleBean bean4 = TestSmartLifecycleBean.forShutdownTests(2, 400, stoppedBeans);
263 		TestSmartLifecycleBean bean5 = TestSmartLifecycleBean.forShutdownTests(2, 700, stoppedBeans);
264 		TestSmartLifecycleBean bean6 = TestSmartLifecycleBean.forShutdownTests(Integer.MAX_VALUE, 200, stoppedBeans);
265 		TestSmartLifecycleBean bean7 = TestSmartLifecycleBean.forShutdownTests(3, 200, stoppedBeans);
266 		StaticApplicationContext context = new StaticApplicationContext();
267 		context.getBeanFactory().registerSingleton("bean1", bean1);
268 		context.getBeanFactory().registerSingleton("bean2", bean2);
269 		context.getBeanFactory().registerSingleton("bean3", bean3);
270 		context.getBeanFactory().registerSingleton("bean4", bean4);
271 		context.getBeanFactory().registerSingleton("bean5", bean5);
272 		context.getBeanFactory().registerSingleton("bean6", bean6);
273 		context.getBeanFactory().registerSingleton("bean7", bean7);
274 		context.refresh();
275 		context.stop();
276 		assertEquals(Integer.MAX_VALUE, getPhase(stoppedBeans.get(0)));
277 		assertEquals(3, getPhase(stoppedBeans.get(1)));
278 		assertEquals(3, getPhase(stoppedBeans.get(2)));
279 		assertEquals(2, getPhase(stoppedBeans.get(3)));
280 		assertEquals(2, getPhase(stoppedBeans.get(4)));
281 		assertEquals(1, getPhase(stoppedBeans.get(5)));
282 		assertEquals(1, getPhase(stoppedBeans.get(6)));
283 	}
284 
285 	@Test
286 	public void singleSmartLifecycleShutdown() throws Exception {
287 		Assume.group(TestGroup.PERFORMANCE);
288 
289 		CopyOnWriteArrayList<Lifecycle> stoppedBeans = new CopyOnWriteArrayList<Lifecycle>();
290 		TestSmartLifecycleBean bean = TestSmartLifecycleBean.forShutdownTests(99, 300, stoppedBeans);
291 		StaticApplicationContext context = new StaticApplicationContext();
292 		context.getBeanFactory().registerSingleton("bean", bean);
293 		context.refresh();
294 		assertTrue(bean.isRunning());
295 		context.stop();
296 		assertEquals(1, stoppedBeans.size());
297 		assertFalse(bean.isRunning());
298 		assertEquals(bean, stoppedBeans.get(0));
299 	}
300 
301 	@Test
302 	public void singleLifecycleShutdown() throws Exception {
303 		CopyOnWriteArrayList<Lifecycle> stoppedBeans = new CopyOnWriteArrayList<Lifecycle>();
304 		Lifecycle bean = new TestLifecycleBean(null, stoppedBeans);
305 		StaticApplicationContext context = new StaticApplicationContext();
306 		context.getBeanFactory().registerSingleton("bean", bean);
307 		context.refresh();
308 		assertFalse(bean.isRunning());
309 		bean.start();
310 		assertTrue(bean.isRunning());
311 		context.stop();
312 		assertEquals(1, stoppedBeans.size());
313 		assertFalse(bean.isRunning());
314 		assertEquals(bean, stoppedBeans.get(0));
315 	}
316 
317 	@Test
318 	public void mixedShutdown() throws Exception {
319 		CopyOnWriteArrayList<Lifecycle> stoppedBeans = new CopyOnWriteArrayList<Lifecycle>();
320 		Lifecycle bean1 = TestLifecycleBean.forShutdownTests(stoppedBeans);
321 		Lifecycle bean2 = TestSmartLifecycleBean.forShutdownTests(500, 200, stoppedBeans);
322 		Lifecycle bean3 = TestSmartLifecycleBean.forShutdownTests(Integer.MAX_VALUE, 100, stoppedBeans);
323 		Lifecycle bean4 = TestLifecycleBean.forShutdownTests(stoppedBeans);
324 		Lifecycle bean5 = TestSmartLifecycleBean.forShutdownTests(1, 200, stoppedBeans);
325 		Lifecycle bean6 = TestSmartLifecycleBean.forShutdownTests(-1, 100, stoppedBeans);
326 		Lifecycle bean7 = TestSmartLifecycleBean.forShutdownTests(Integer.MIN_VALUE, 300, stoppedBeans);
327 		StaticApplicationContext context = new StaticApplicationContext();
328 		context.getBeanFactory().registerSingleton("bean1", bean1);
329 		context.getBeanFactory().registerSingleton("bean2", bean2);
330 		context.getBeanFactory().registerSingleton("bean3", bean3);
331 		context.getBeanFactory().registerSingleton("bean4", bean4);
332 		context.getBeanFactory().registerSingleton("bean5", bean5);
333 		context.getBeanFactory().registerSingleton("bean6", bean6);
334 		context.getBeanFactory().registerSingleton("bean7", bean7);
335 		context.refresh();
336 		assertTrue(bean2.isRunning());
337 		assertTrue(bean3.isRunning());
338 		assertTrue(bean5.isRunning());
339 		assertTrue(bean6.isRunning());
340 		assertTrue(bean7.isRunning());
341 		assertFalse(bean1.isRunning());
342 		assertFalse(bean4.isRunning());
343 		bean1.start();
344 		bean4.start();
345 		assertTrue(bean1.isRunning());
346 		assertTrue(bean4.isRunning());
347 		context.stop();
348 		assertFalse(bean1.isRunning());
349 		assertFalse(bean2.isRunning());
350 		assertFalse(bean3.isRunning());
351 		assertFalse(bean4.isRunning());
352 		assertFalse(bean5.isRunning());
353 		assertFalse(bean6.isRunning());
354 		assertFalse(bean7.isRunning());
355 		assertEquals(7, stoppedBeans.size());
356 		assertEquals(Integer.MAX_VALUE, getPhase(stoppedBeans.get(0)));
357 		assertEquals(500, getPhase(stoppedBeans.get(1)));
358 		assertEquals(1, getPhase(stoppedBeans.get(2)));
359 		assertEquals(0, getPhase(stoppedBeans.get(3)));
360 		assertEquals(0, getPhase(stoppedBeans.get(4)));
361 		assertEquals(-1, getPhase(stoppedBeans.get(5)));
362 		assertEquals(Integer.MIN_VALUE, getPhase(stoppedBeans.get(6)));
363 	}
364 
365 	@Test
366 	public void dependencyStartedFirstEvenIfItsPhaseIsHigher() throws Exception {
367 		CopyOnWriteArrayList<Lifecycle> startedBeans = new CopyOnWriteArrayList<Lifecycle>();
368 		TestSmartLifecycleBean beanMin = TestSmartLifecycleBean.forStartupTests(Integer.MIN_VALUE, startedBeans);
369 		TestSmartLifecycleBean bean2 = TestSmartLifecycleBean.forStartupTests(2, startedBeans);
370 		TestSmartLifecycleBean bean99 = TestSmartLifecycleBean.forStartupTests(99, startedBeans);
371 		TestSmartLifecycleBean beanMax = TestSmartLifecycleBean.forStartupTests(Integer.MAX_VALUE, startedBeans);
372 		StaticApplicationContext context = new StaticApplicationContext();
373 		context.getBeanFactory().registerSingleton("beanMin", beanMin);
374 		context.getBeanFactory().registerSingleton("bean2", bean2);
375 		context.getBeanFactory().registerSingleton("bean99", bean99);
376 		context.getBeanFactory().registerSingleton("beanMax", beanMax);
377 		context.getBeanFactory().registerDependentBean("bean99", "bean2");
378 		context.refresh();
379 		assertTrue(beanMin.isRunning());
380 		assertTrue(bean2.isRunning());
381 		assertTrue(bean99.isRunning());
382 		assertTrue(beanMax.isRunning());
383 		assertEquals(4, startedBeans.size());
384 		assertEquals(Integer.MIN_VALUE, getPhase(startedBeans.get(0)));
385 		assertEquals(99, getPhase(startedBeans.get(1)));
386 		assertEquals(bean99, startedBeans.get(1));
387 		assertEquals(2, getPhase(startedBeans.get(2)));
388 		assertEquals(bean2, startedBeans.get(2));
389 		assertEquals(Integer.MAX_VALUE, getPhase(startedBeans.get(3)));
390 		context.stop();
391 	}
392 
393 	@Test
394 	public void dependentShutdownFirstEvenIfItsPhaseIsLower() throws Exception {
395 		Assume.group(TestGroup.PERFORMANCE);
396 
397 		CopyOnWriteArrayList<Lifecycle> stoppedBeans = new CopyOnWriteArrayList<Lifecycle>();
398 		TestSmartLifecycleBean beanMin = TestSmartLifecycleBean.forShutdownTests(Integer.MIN_VALUE, 100, stoppedBeans);
399 		TestSmartLifecycleBean bean1 = TestSmartLifecycleBean.forShutdownTests(1, 200, stoppedBeans);
400 		TestSmartLifecycleBean bean99 = TestSmartLifecycleBean.forShutdownTests(99, 100, stoppedBeans);
401 		TestSmartLifecycleBean bean2 = TestSmartLifecycleBean.forShutdownTests(2, 300, stoppedBeans);
402 		TestSmartLifecycleBean bean7 = TestSmartLifecycleBean.forShutdownTests(7, 400, stoppedBeans);
403 		TestSmartLifecycleBean beanMax = TestSmartLifecycleBean.forShutdownTests(Integer.MAX_VALUE, 400, stoppedBeans);
404 		StaticApplicationContext context = new StaticApplicationContext();
405 		context.getBeanFactory().registerSingleton("beanMin", beanMin);
406 		context.getBeanFactory().registerSingleton("bean1", bean1);
407 		context.getBeanFactory().registerSingleton("bean2", bean2);
408 		context.getBeanFactory().registerSingleton("bean7", bean7);
409 		context.getBeanFactory().registerSingleton("bean99", bean99);
410 		context.getBeanFactory().registerSingleton("beanMax", beanMax);
411 		context.getBeanFactory().registerDependentBean("bean99", "bean2");
412 		context.refresh();
413 		assertTrue(beanMin.isRunning());
414 		assertTrue(bean1.isRunning());
415 		assertTrue(bean2.isRunning());
416 		assertTrue(bean7.isRunning());
417 		assertTrue(bean99.isRunning());
418 		assertTrue(beanMax.isRunning());
419 		context.stop();
420 		assertFalse(beanMin.isRunning());
421 		assertFalse(bean1.isRunning());
422 		assertFalse(bean2.isRunning());
423 		assertFalse(bean7.isRunning());
424 		assertFalse(bean99.isRunning());
425 		assertFalse(beanMax.isRunning());
426 		assertEquals(6, stoppedBeans.size());
427 		assertEquals(Integer.MAX_VALUE, getPhase(stoppedBeans.get(0)));
428 		assertEquals(2, getPhase(stoppedBeans.get(1)));
429 		assertEquals(bean2, stoppedBeans.get(1));
430 		assertEquals(99, getPhase(stoppedBeans.get(2)));
431 		assertEquals(bean99, stoppedBeans.get(2));
432 		assertEquals(7, getPhase(stoppedBeans.get(3)));
433 		assertEquals(1, getPhase(stoppedBeans.get(4)));
434 		assertEquals(Integer.MIN_VALUE, getPhase(stoppedBeans.get(5)));
435 	}
436 
437 	@Test
438 	public void dependencyStartedFirstAndIsSmartLifecycle() throws Exception {
439 		CopyOnWriteArrayList<Lifecycle> startedBeans = new CopyOnWriteArrayList<Lifecycle>();
440 		TestSmartLifecycleBean beanNegative = TestSmartLifecycleBean.forStartupTests(-99, startedBeans);
441 		TestSmartLifecycleBean bean99 = TestSmartLifecycleBean.forStartupTests(99, startedBeans);
442 		TestSmartLifecycleBean bean7 = TestSmartLifecycleBean.forStartupTests(7, startedBeans);
443 		TestLifecycleBean simpleBean = TestLifecycleBean.forStartupTests(startedBeans);
444 		StaticApplicationContext context = new StaticApplicationContext();
445 		context.getBeanFactory().registerSingleton("beanNegative", beanNegative);
446 		context.getBeanFactory().registerSingleton("bean7", bean7);
447 		context.getBeanFactory().registerSingleton("bean99", bean99);
448 		context.getBeanFactory().registerSingleton("simpleBean", simpleBean);
449 		context.getBeanFactory().registerDependentBean("bean7", "simpleBean");
450 		context.refresh();
451 		context.stop();
452 		startedBeans.clear();
453 		// clean start so that simpleBean is included
454 		context.start();
455 		assertTrue(beanNegative.isRunning());
456 		assertTrue(bean99.isRunning());
457 		assertTrue(bean7.isRunning());
458 		assertTrue(simpleBean.isRunning());
459 		assertEquals(4, startedBeans.size());
460 		assertEquals(-99, getPhase(startedBeans.get(0)));
461 		assertEquals(7, getPhase(startedBeans.get(1)));
462 		assertEquals(0, getPhase(startedBeans.get(2)));
463 		assertEquals(99, getPhase(startedBeans.get(3)));
464 		context.stop();
465 	}
466 
467 	@Test
468 	public void dependentShutdownFirstAndIsSmartLifecycle() throws Exception {
469 		Assume.group(TestGroup.PERFORMANCE);
470 
471 		CopyOnWriteArrayList<Lifecycle> stoppedBeans = new CopyOnWriteArrayList<Lifecycle>();
472 		TestSmartLifecycleBean beanMin = TestSmartLifecycleBean.forShutdownTests(Integer.MIN_VALUE, 400, stoppedBeans);
473 		TestSmartLifecycleBean beanNegative = TestSmartLifecycleBean.forShutdownTests(-99, 100, stoppedBeans);
474 		TestSmartLifecycleBean bean1 = TestSmartLifecycleBean.forShutdownTests(1, 200, stoppedBeans);
475 		TestSmartLifecycleBean bean2 = TestSmartLifecycleBean.forShutdownTests(2, 300, stoppedBeans);
476 		TestSmartLifecycleBean bean7 = TestSmartLifecycleBean.forShutdownTests(7, 400, stoppedBeans);
477 		TestLifecycleBean simpleBean = TestLifecycleBean.forShutdownTests(stoppedBeans);
478 		StaticApplicationContext context = new StaticApplicationContext();
479 		context.getBeanFactory().registerSingleton("beanMin", beanMin);
480 		context.getBeanFactory().registerSingleton("beanNegative", beanNegative);
481 		context.getBeanFactory().registerSingleton("bean1", bean1);
482 		context.getBeanFactory().registerSingleton("bean2", bean2);
483 		context.getBeanFactory().registerSingleton("bean7", bean7);
484 		context.getBeanFactory().registerSingleton("simpleBean", simpleBean);
485 		context.getBeanFactory().registerDependentBean("simpleBean", "beanNegative");
486 		context.refresh();
487 		assertTrue(beanMin.isRunning());
488 		assertTrue(beanNegative.isRunning());
489 		assertTrue(bean1.isRunning());
490 		assertTrue(bean2.isRunning());
491 		assertTrue(bean7.isRunning());
492 		// should start since it's a dependency of an auto-started bean
493 		assertTrue(simpleBean.isRunning());
494 		context.stop();
495 		assertFalse(beanMin.isRunning());
496 		assertFalse(beanNegative.isRunning());
497 		assertFalse(bean1.isRunning());
498 		assertFalse(bean2.isRunning());
499 		assertFalse(bean7.isRunning());
500 		assertFalse(simpleBean.isRunning());
501 		assertEquals(6, stoppedBeans.size());
502 		assertEquals(7, getPhase(stoppedBeans.get(0)));
503 		assertEquals(2, getPhase(stoppedBeans.get(1)));
504 		assertEquals(1, getPhase(stoppedBeans.get(2)));
505 		assertEquals(-99, getPhase(stoppedBeans.get(3)));
506 		assertEquals(0, getPhase(stoppedBeans.get(4)));
507 		assertEquals(Integer.MIN_VALUE, getPhase(stoppedBeans.get(5)));
508 	}
509 
510 	@Test
511 	public void dependencyStartedFirstButNotSmartLifecycle() throws Exception {
512 		CopyOnWriteArrayList<Lifecycle> startedBeans = new CopyOnWriteArrayList<Lifecycle>();
513 		TestSmartLifecycleBean beanMin = TestSmartLifecycleBean.forStartupTests(Integer.MIN_VALUE, startedBeans);
514 		TestSmartLifecycleBean bean7 = TestSmartLifecycleBean.forStartupTests(7, startedBeans);
515 		TestLifecycleBean simpleBean = TestLifecycleBean.forStartupTests(startedBeans);
516 		StaticApplicationContext context = new StaticApplicationContext();
517 		context.getBeanFactory().registerSingleton("beanMin", beanMin);
518 		context.getBeanFactory().registerSingleton("bean7", bean7);
519 		context.getBeanFactory().registerSingleton("simpleBean", simpleBean);
520 		context.getBeanFactory().registerDependentBean("simpleBean", "beanMin");
521 		context.refresh();
522 		assertTrue(beanMin.isRunning());
523 		assertTrue(bean7.isRunning());
524 		assertTrue(simpleBean.isRunning());
525 		assertEquals(3, startedBeans.size());
526 		assertEquals(0, getPhase(startedBeans.get(0)));
527 		assertEquals(Integer.MIN_VALUE, getPhase(startedBeans.get(1)));
528 		assertEquals(7, getPhase(startedBeans.get(2)));
529 		context.stop();
530 	}
531 
532 	@Test
533 	public void dependentShutdownFirstButNotSmartLifecycle() throws Exception {
534 		Assume.group(TestGroup.PERFORMANCE);
535 
536 		CopyOnWriteArrayList<Lifecycle> stoppedBeans = new CopyOnWriteArrayList<Lifecycle>();
537 		TestSmartLifecycleBean bean1 = TestSmartLifecycleBean.forShutdownTests(1, 200, stoppedBeans);
538 		TestLifecycleBean simpleBean = TestLifecycleBean.forShutdownTests(stoppedBeans);
539 		TestSmartLifecycleBean bean2 = TestSmartLifecycleBean.forShutdownTests(2, 300, stoppedBeans);
540 		TestSmartLifecycleBean bean7 = TestSmartLifecycleBean.forShutdownTests(7, 400, stoppedBeans);
541 		TestSmartLifecycleBean beanMin = TestSmartLifecycleBean.forShutdownTests(Integer.MIN_VALUE, 400, stoppedBeans);
542 		StaticApplicationContext context = new StaticApplicationContext();
543 		context.getBeanFactory().registerSingleton("beanMin", beanMin);
544 		context.getBeanFactory().registerSingleton("bean1", bean1);
545 		context.getBeanFactory().registerSingleton("bean2", bean2);
546 		context.getBeanFactory().registerSingleton("bean7", bean7);
547 		context.getBeanFactory().registerSingleton("simpleBean", simpleBean);
548 		context.getBeanFactory().registerDependentBean("bean2", "simpleBean");
549 		context.refresh();
550 		assertTrue(beanMin.isRunning());
551 		assertTrue(bean1.isRunning());
552 		assertTrue(bean2.isRunning());
553 		assertTrue(bean7.isRunning());
554 		assertFalse(simpleBean.isRunning());
555 		simpleBean.start();
556 		assertTrue(simpleBean.isRunning());
557 		context.stop();
558 		assertFalse(beanMin.isRunning());
559 		assertFalse(bean1.isRunning());
560 		assertFalse(bean2.isRunning());
561 		assertFalse(bean7.isRunning());
562 		assertFalse(simpleBean.isRunning());
563 		assertEquals(5, stoppedBeans.size());
564 		assertEquals(7, getPhase(stoppedBeans.get(0)));
565 		assertEquals(0, getPhase(stoppedBeans.get(1)));
566 		assertEquals(2, getPhase(stoppedBeans.get(2)));
567 		assertEquals(1, getPhase(stoppedBeans.get(3)));
568 		assertEquals(Integer.MIN_VALUE, getPhase(stoppedBeans.get(4)));
569 	}
570 
571 
572 	private static int getPhase(Lifecycle lifecycle) {
573 		return (lifecycle instanceof SmartLifecycle) ?
574 				((SmartLifecycle) lifecycle).getPhase() : 0;
575 	}
576 
577 
578 	private static class TestLifecycleBean implements Lifecycle {
579 
580 		private final CopyOnWriteArrayList<Lifecycle> startedBeans;
581 
582 		private final CopyOnWriteArrayList<Lifecycle> stoppedBeans;
583 
584 		private volatile boolean running;
585 
586 
587 		static TestLifecycleBean forStartupTests(CopyOnWriteArrayList<Lifecycle> startedBeans) {
588 			return new TestLifecycleBean(startedBeans, null);
589 		}
590 
591 		static TestLifecycleBean forShutdownTests(CopyOnWriteArrayList<Lifecycle> stoppedBeans) {
592 			return new TestLifecycleBean(null, stoppedBeans);
593 		}
594 
595 		private TestLifecycleBean(CopyOnWriteArrayList<Lifecycle> startedBeans,  CopyOnWriteArrayList<Lifecycle> stoppedBeans) {
596 			this.startedBeans = startedBeans;
597 			this.stoppedBeans = stoppedBeans;
598 		}
599 
600 		@Override
601 		public boolean isRunning() {
602 			return this.running;
603 		}
604 
605 		@Override
606 		public void start() {
607 			if (this.startedBeans != null) {
608 				this.startedBeans.add(this);
609 			}
610 			this.running = true;
611 		}
612 
613 		@Override
614 		public void stop() {
615 			if (this.stoppedBeans != null) {
616 				this.stoppedBeans.add(this);
617 			}
618 			this.running = false;
619 		}
620 	}
621 
622 
623 	private static class TestSmartLifecycleBean extends TestLifecycleBean implements SmartLifecycle {
624 
625 		private final int phase;
626 
627 		private final int shutdownDelay;
628 
629 		private volatile boolean autoStartup = true;
630 
631 		static TestSmartLifecycleBean forStartupTests(int phase, CopyOnWriteArrayList<Lifecycle> startedBeans) {
632 			return new TestSmartLifecycleBean(phase, 0, startedBeans, null);
633 		}
634 
635 		static TestSmartLifecycleBean forShutdownTests(int phase, int shutdownDelay, CopyOnWriteArrayList<Lifecycle> stoppedBeans) {
636 			return new TestSmartLifecycleBean(phase, shutdownDelay, null, stoppedBeans);
637 		}
638 
639 		private TestSmartLifecycleBean(int phase, int shutdownDelay, CopyOnWriteArrayList<Lifecycle> startedBeans, CopyOnWriteArrayList<Lifecycle> stoppedBeans) {
640 			super(startedBeans, stoppedBeans);
641 			this.phase = phase;
642 			this.shutdownDelay = shutdownDelay;
643 		}
644 
645 		@Override
646 		public int getPhase() {
647 			return this.phase;
648 		}
649 
650 		@Override
651 		public boolean isAutoStartup() {
652 			return this.autoStartup;
653 		}
654 
655 		public void setAutoStartup(boolean autoStartup) {
656 			this.autoStartup = autoStartup;
657 		}
658 
659 		@Override
660 		public void stop(final Runnable callback) {
661 			// calling stop() before the delay to preserve
662 			// invocation order in the 'stoppedBeans' list
663 			stop();
664 			final int delay = this.shutdownDelay;
665 			new Thread(new Runnable() {
666 				@Override
667 				public void run() {
668 					try {
669 						Thread.sleep(delay);
670 					}
671 					catch (InterruptedException e) {
672 						// ignore
673 					}
674 					finally {
675 						callback.run();
676 					}
677 				}
678 			}).start();
679 		}
680 	}
681 
682 
683 	public static class DummySmartLifecycleBean implements SmartLifecycle {
684 
685 		public boolean running = false;
686 
687 		@Override
688 		public boolean isAutoStartup() {
689 			return true;
690 		}
691 
692 		@Override
693 		public void stop(Runnable callback) {
694 			this.running = false;
695 			callback.run();
696 		}
697 
698 		@Override
699 		public void start() {
700 			this.running = true;
701 		}
702 
703 		@Override
704 		public void stop() {
705 			this.running = false;
706 		}
707 
708 		@Override
709 		public boolean isRunning() {
710 			return this.running;
711 		}
712 
713 		@Override
714 		public int getPhase() {
715 			return 0;
716 		}
717 	}
718 
719 
720 	public static class DummySmartLifecycleFactoryBean implements FactoryBean<Object>, SmartLifecycle {
721 
722 		public boolean running = false;
723 
724 		DummySmartLifecycleBean bean = new DummySmartLifecycleBean();
725 
726 		@Override
727 		public Object getObject() throws Exception {
728 			return this.bean;
729 		}
730 
731 		@Override
732 		public Class<?> getObjectType() {
733 			return DummySmartLifecycleBean.class;
734 		}
735 
736 		@Override
737 		public boolean isSingleton() {
738 			return true;
739 		}
740 
741 		@Override
742 		public boolean isAutoStartup() {
743 			return true;
744 		}
745 
746 		@Override
747 		public void stop(Runnable callback) {
748 			this.running = false;
749 			callback.run();
750 		}
751 
752 		@Override
753 		public void start() {
754 			this.running = true;
755 		}
756 
757 		@Override
758 		public void stop() {
759 			this.running = false;
760 		}
761 
762 		@Override
763 		public boolean isRunning() {
764 			return this.running;
765 		}
766 
767 		@Override
768 		public int getPhase() {
769 			return 0;
770 		}
771 	}
772 
773 }