From 0042243a119cde1b5dbbe76cd2a8cb310265dfd4 Mon Sep 17 00:00:00 2001 From: Juergen Hoeller Date: Mon, 12 Dec 2011 18:33:29 +0000 Subject: [PATCH] SmartLifecycle beans in Lifecycle dependency graphs are only being started when isAutoStartup=true (SPR-8912) --- .../support/DefaultLifecycleProcessor.java | 34 +++++++++++-------- .../DefaultLifecycleProcessorTests.java | 31 ++++++++++++++--- 2 files changed, 46 insertions(+), 19 deletions(-) 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 f0b326ec8b..025f4cfb96 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 @@ -1,5 +1,5 @@ /* - * Copyright 2002-2010 the original author or authors. + * Copyright 2002-2011 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. @@ -125,15 +125,15 @@ public class DefaultLifecycleProcessor implements LifecycleProcessor, BeanFactor 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); + Lifecycle bean = entry.getValue(); + if (!autoStartupOnly || (bean instanceof SmartLifecycle && ((SmartLifecycle) bean).isAutoStartup())) { + int phase = getPhase(bean); LifecycleGroup group = phases.get(phase); if (group == null) { - group = new LifecycleGroup(phase, this.timeoutPerShutdownPhase, lifecycleBeans); + group = new LifecycleGroup(phase, this.timeoutPerShutdownPhase, lifecycleBeans, autoStartupOnly); phases.put(phase, group); } - group.add(entry.getKey(), lifecycle); + group.add(entry.getKey(), bean); } } if (phases.size() > 0) { @@ -151,14 +151,15 @@ 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 start */ - private void doStart(Map lifecycleBeans, String beanName) { + private void doStart(Map lifecycleBeans, String beanName, boolean autoStartupOnly) { Lifecycle bean = lifecycleBeans.remove(beanName); if (bean != null && !this.equals(bean)) { String[] dependenciesForBean = this.beanFactory.getDependenciesForBean(beanName); for (String dependency : dependenciesForBean) { - doStart(lifecycleBeans, dependency); + doStart(lifecycleBeans, dependency, autoStartupOnly); } - if (!bean.isRunning()) { + if (!bean.isRunning() && + (!autoStartupOnly || !(bean instanceof SmartLifecycle) || ((SmartLifecycle) bean).isAutoStartup())) { if (logger.isDebugEnabled()) { logger.debug("Starting bean '" + beanName + "' of type [" + bean.getClass() + "]"); } @@ -179,14 +180,14 @@ public class DefaultLifecycleProcessor implements LifecycleProcessor, BeanFactor Map lifecycleBeans = getLifecycleBeans(); Map phases = new HashMap(); for (Map.Entry entry : lifecycleBeans.entrySet()) { - Lifecycle lifecycle = entry.getValue(); - int shutdownOrder = getPhase(lifecycle); + Lifecycle bean = entry.getValue(); + int shutdownOrder = getPhase(bean); LifecycleGroup group = phases.get(shutdownOrder); if (group == null) { - group = new LifecycleGroup(shutdownOrder, this.timeoutPerShutdownPhase, lifecycleBeans); + group = new LifecycleGroup(shutdownOrder, this.timeoutPerShutdownPhase, lifecycleBeans, false); phases.put(shutdownOrder, group); } - group.add(entry.getKey(), lifecycle); + group.add(entry.getKey(), bean); } if (phases.size() > 0) { List keys = new ArrayList(phases.keySet()); @@ -309,10 +310,13 @@ public class DefaultLifecycleProcessor implements LifecycleProcessor, BeanFactor private final long timeout; - public LifecycleGroup(int phase, long timeout, Map lifecycleBeans) { + private final boolean autoStartupOnly; + + public LifecycleGroup(int phase, long timeout, Map lifecycleBeans, boolean autoStartupOnly) { this.phase = phase; this.timeout = timeout; this.lifecycleBeans = lifecycleBeans; + this.autoStartupOnly = autoStartupOnly; } public void add(String name, Lifecycle bean) { @@ -332,7 +336,7 @@ public class DefaultLifecycleProcessor implements LifecycleProcessor, BeanFactor Collections.sort(this.members); for (LifecycleGroupMember member : this.members) { if (this.lifecycleBeans.containsKey(member.name)) { - doStart(this.lifecycleBeans, member.name); + doStart(this.lifecycleBeans, member.name, this.autoStartupOnly); } } } 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 b9a37d9617..18bd081d2d 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 @@ -1,5 +1,5 @@ /* - * Copyright 2002-2009 the original author or authors. + * Copyright 2002-2011 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. @@ -18,7 +18,6 @@ package org.springframework.context.support; import java.util.concurrent.CopyOnWriteArrayList; -import static org.junit.Assert.*; import org.junit.Test; import org.springframework.beans.DirectFieldAccessor; @@ -29,6 +28,8 @@ import org.springframework.context.Lifecycle; import org.springframework.context.LifecycleProcessor; import org.springframework.context.SmartLifecycle; +import static org.junit.Assert.*; + /** * @author Mark Fisher * @since 3.0 @@ -55,7 +56,8 @@ public class DefaultLifecycleProcessorTests { Object contextLifecycleProcessor = new DirectFieldAccessor(context).getPropertyValue("lifecycleProcessor"); assertNotNull(contextLifecycleProcessor); assertSame(bean, contextLifecycleProcessor); - assertEquals(1000L, new DirectFieldAccessor(contextLifecycleProcessor).getPropertyValue("timeoutPerShutdownPhase")); + assertEquals(1000L, new DirectFieldAccessor(contextLifecycleProcessor).getPropertyValue( + "timeoutPerShutdownPhase")); } @Test @@ -116,6 +118,28 @@ public class DefaultLifecycleProcessorTests { context.stop(); } + @Test + public void singleSmartLifecycleAutoStartupWithNonAutoStartupDependency() throws Exception { + CopyOnWriteArrayList 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 startedBeans = new CopyOnWriteArrayList(); @@ -578,7 +602,6 @@ public class DefaultLifecycleProcessorTests { } this.running = false; } - }