Skip to content

Commit 0042243

Browse files
committed
SmartLifecycle beans in Lifecycle dependency graphs are only being started when isAutoStartup=true (SPR-8912)
1 parent 2fa9ef9 commit 0042243

File tree

2 files changed

+46
-19
lines changed

2 files changed

+46
-19
lines changed

org.springframework.context/src/main/java/org/springframework/context/support/DefaultLifecycleProcessor.java

Lines changed: 19 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright 2002-2010 the original author or authors.
2+
* Copyright 2002-2011 the original author or authors.
33
*
44
* Licensed under the Apache License, Version 2.0 (the "License");
55
* you may not use this file except in compliance with the License.
@@ -125,15 +125,15 @@ private void startBeans(boolean autoStartupOnly) {
125125
Map<String, Lifecycle> lifecycleBeans = getLifecycleBeans();
126126
Map<Integer, LifecycleGroup> phases = new HashMap<Integer, LifecycleGroup>();
127127
for (Map.Entry<String, ? extends Lifecycle> entry : lifecycleBeans.entrySet()) {
128-
Lifecycle lifecycle = entry.getValue();
129-
if (!autoStartupOnly || (lifecycle instanceof SmartLifecycle && ((SmartLifecycle) lifecycle).isAutoStartup())) {
130-
int phase = getPhase(lifecycle);
128+
Lifecycle bean = entry.getValue();
129+
if (!autoStartupOnly || (bean instanceof SmartLifecycle && ((SmartLifecycle) bean).isAutoStartup())) {
130+
int phase = getPhase(bean);
131131
LifecycleGroup group = phases.get(phase);
132132
if (group == null) {
133-
group = new LifecycleGroup(phase, this.timeoutPerShutdownPhase, lifecycleBeans);
133+
group = new LifecycleGroup(phase, this.timeoutPerShutdownPhase, lifecycleBeans, autoStartupOnly);
134134
phases.put(phase, group);
135135
}
136-
group.add(entry.getKey(), lifecycle);
136+
group.add(entry.getKey(), bean);
137137
}
138138
}
139139
if (phases.size() > 0) {
@@ -151,14 +151,15 @@ private void startBeans(boolean autoStartupOnly) {
151151
* @param lifecycleBeans Map with bean name as key and Lifecycle instance as value
152152
* @param beanName the name of the bean to start
153153
*/
154-
private void doStart(Map<String, ? extends Lifecycle> lifecycleBeans, String beanName) {
154+
private void doStart(Map<String, ? extends Lifecycle> lifecycleBeans, String beanName, boolean autoStartupOnly) {
155155
Lifecycle bean = lifecycleBeans.remove(beanName);
156156
if (bean != null && !this.equals(bean)) {
157157
String[] dependenciesForBean = this.beanFactory.getDependenciesForBean(beanName);
158158
for (String dependency : dependenciesForBean) {
159-
doStart(lifecycleBeans, dependency);
159+
doStart(lifecycleBeans, dependency, autoStartupOnly);
160160
}
161-
if (!bean.isRunning()) {
161+
if (!bean.isRunning() &&
162+
(!autoStartupOnly || !(bean instanceof SmartLifecycle) || ((SmartLifecycle) bean).isAutoStartup())) {
162163
if (logger.isDebugEnabled()) {
163164
logger.debug("Starting bean '" + beanName + "' of type [" + bean.getClass() + "]");
164165
}
@@ -179,14 +180,14 @@ private void stopBeans() {
179180
Map<String, Lifecycle> lifecycleBeans = getLifecycleBeans();
180181
Map<Integer, LifecycleGroup> phases = new HashMap<Integer, LifecycleGroup>();
181182
for (Map.Entry<String, Lifecycle> entry : lifecycleBeans.entrySet()) {
182-
Lifecycle lifecycle = entry.getValue();
183-
int shutdownOrder = getPhase(lifecycle);
183+
Lifecycle bean = entry.getValue();
184+
int shutdownOrder = getPhase(bean);
184185
LifecycleGroup group = phases.get(shutdownOrder);
185186
if (group == null) {
186-
group = new LifecycleGroup(shutdownOrder, this.timeoutPerShutdownPhase, lifecycleBeans);
187+
group = new LifecycleGroup(shutdownOrder, this.timeoutPerShutdownPhase, lifecycleBeans, false);
187188
phases.put(shutdownOrder, group);
188189
}
189-
group.add(entry.getKey(), lifecycle);
190+
group.add(entry.getKey(), bean);
190191
}
191192
if (phases.size() > 0) {
192193
List<Integer> keys = new ArrayList<Integer>(phases.keySet());
@@ -309,10 +310,13 @@ private class LifecycleGroup {
309310

310311
private final long timeout;
311312

312-
public LifecycleGroup(int phase, long timeout, Map<String, ? extends Lifecycle> lifecycleBeans) {
313+
private final boolean autoStartupOnly;
314+
315+
public LifecycleGroup(int phase, long timeout, Map<String, ? extends Lifecycle> lifecycleBeans, boolean autoStartupOnly) {
313316
this.phase = phase;
314317
this.timeout = timeout;
315318
this.lifecycleBeans = lifecycleBeans;
319+
this.autoStartupOnly = autoStartupOnly;
316320
}
317321

318322
public void add(String name, Lifecycle bean) {
@@ -332,7 +336,7 @@ public void start() {
332336
Collections.sort(this.members);
333337
for (LifecycleGroupMember member : this.members) {
334338
if (this.lifecycleBeans.containsKey(member.name)) {
335-
doStart(this.lifecycleBeans, member.name);
339+
doStart(this.lifecycleBeans, member.name, this.autoStartupOnly);
336340
}
337341
}
338342
}

org.springframework.context/src/test/java/org/springframework/context/support/DefaultLifecycleProcessorTests.java

Lines changed: 27 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright 2002-2009 the original author or authors.
2+
* Copyright 2002-2011 the original author or authors.
33
*
44
* Licensed under the Apache License, Version 2.0 (the "License");
55
* you may not use this file except in compliance with the License.
@@ -18,7 +18,6 @@
1818

1919
import java.util.concurrent.CopyOnWriteArrayList;
2020

21-
import static org.junit.Assert.*;
2221
import org.junit.Test;
2322

2423
import org.springframework.beans.DirectFieldAccessor;
@@ -29,6 +28,8 @@
2928
import org.springframework.context.LifecycleProcessor;
3029
import org.springframework.context.SmartLifecycle;
3130

31+
import static org.junit.Assert.*;
32+
3233
/**
3334
* @author Mark Fisher
3435
* @since 3.0
@@ -55,7 +56,8 @@ public void customLifecycleProcessorInstance() {
5556
Object contextLifecycleProcessor = new DirectFieldAccessor(context).getPropertyValue("lifecycleProcessor");
5657
assertNotNull(contextLifecycleProcessor);
5758
assertSame(bean, contextLifecycleProcessor);
58-
assertEquals(1000L, new DirectFieldAccessor(contextLifecycleProcessor).getPropertyValue("timeoutPerShutdownPhase"));
59+
assertEquals(1000L, new DirectFieldAccessor(contextLifecycleProcessor).getPropertyValue(
60+
"timeoutPerShutdownPhase"));
5961
}
6062

6163
@Test
@@ -116,6 +118,28 @@ public void singleSmartLifecycleWithoutAutoStartup() throws Exception {
116118
context.stop();
117119
}
118120

121+
@Test
122+
public void singleSmartLifecycleAutoStartupWithNonAutoStartupDependency() throws Exception {
123+
CopyOnWriteArrayList<Lifecycle> startedBeans = new CopyOnWriteArrayList<Lifecycle>();
124+
TestSmartLifecycleBean bean = TestSmartLifecycleBean.forStartupTests(1, startedBeans);
125+
bean.setAutoStartup(true);
126+
TestSmartLifecycleBean dependency = TestSmartLifecycleBean.forStartupTests(1, startedBeans);
127+
dependency.setAutoStartup(false);
128+
StaticApplicationContext context = new StaticApplicationContext();
129+
context.getBeanFactory().registerSingleton("bean", bean);
130+
context.getBeanFactory().registerSingleton("dependency", dependency);
131+
context.getBeanFactory().registerDependentBean("dependency", "bean");
132+
assertFalse(bean.isRunning());
133+
assertFalse(dependency.isRunning());
134+
context.refresh();
135+
assertTrue(bean.isRunning());
136+
assertFalse(dependency.isRunning());
137+
context.stop();
138+
assertFalse(bean.isRunning());
139+
assertFalse(dependency.isRunning());
140+
assertEquals(1, startedBeans.size());
141+
}
142+
119143
@Test
120144
public void smartLifecycleGroupStartup() throws Exception {
121145
CopyOnWriteArrayList<Lifecycle> startedBeans = new CopyOnWriteArrayList<Lifecycle>();
@@ -578,7 +602,6 @@ public void stop() {
578602
}
579603
this.running = false;
580604
}
581-
582605
}
583606

584607

0 commit comments

Comments
 (0)