SmartLifecycle beans in Lifecycle dependency graphs are only being started when isAutoStartup=true (SPR-8912)

This commit is contained in:
Juergen Hoeller 2011-12-12 18:33:29 +00:00
parent 2fa9ef9f5a
commit 0042243a11
2 changed files with 46 additions and 19 deletions

View File

@ -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"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with 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<String, Lifecycle> lifecycleBeans = getLifecycleBeans(); Map<String, Lifecycle> lifecycleBeans = getLifecycleBeans();
Map<Integer, LifecycleGroup> phases = new HashMap<Integer, LifecycleGroup>(); Map<Integer, LifecycleGroup> phases = new HashMap<Integer, LifecycleGroup>();
for (Map.Entry<String, ? extends Lifecycle> entry : lifecycleBeans.entrySet()) { for (Map.Entry<String, ? extends Lifecycle> entry : lifecycleBeans.entrySet()) {
Lifecycle lifecycle = entry.getValue(); Lifecycle bean = entry.getValue();
if (!autoStartupOnly || (lifecycle instanceof SmartLifecycle && ((SmartLifecycle) lifecycle).isAutoStartup())) { if (!autoStartupOnly || (bean instanceof SmartLifecycle && ((SmartLifecycle) bean).isAutoStartup())) {
int phase = getPhase(lifecycle); int phase = getPhase(bean);
LifecycleGroup group = phases.get(phase); LifecycleGroup group = phases.get(phase);
if (group == null) { if (group == null) {
group = new LifecycleGroup(phase, this.timeoutPerShutdownPhase, lifecycleBeans); group = new LifecycleGroup(phase, this.timeoutPerShutdownPhase, lifecycleBeans, autoStartupOnly);
phases.put(phase, group); phases.put(phase, group);
} }
group.add(entry.getKey(), lifecycle); group.add(entry.getKey(), bean);
} }
} }
if (phases.size() > 0) { 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 lifecycleBeans Map with bean name as key and Lifecycle instance as value
* @param beanName the name of the bean to start * @param beanName the name of the bean to start
*/ */
private void doStart(Map<String, ? extends Lifecycle> lifecycleBeans, String beanName) { private void doStart(Map<String, ? extends Lifecycle> lifecycleBeans, String beanName, boolean autoStartupOnly) {
Lifecycle bean = lifecycleBeans.remove(beanName); Lifecycle bean = lifecycleBeans.remove(beanName);
if (bean != null && !this.equals(bean)) { if (bean != null && !this.equals(bean)) {
String[] dependenciesForBean = this.beanFactory.getDependenciesForBean(beanName); String[] dependenciesForBean = this.beanFactory.getDependenciesForBean(beanName);
for (String dependency : dependenciesForBean) { 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()) { if (logger.isDebugEnabled()) {
logger.debug("Starting bean '" + beanName + "' of type [" + bean.getClass() + "]"); logger.debug("Starting bean '" + beanName + "' of type [" + bean.getClass() + "]");
} }
@ -179,14 +180,14 @@ public class DefaultLifecycleProcessor implements LifecycleProcessor, BeanFactor
Map<String, Lifecycle> lifecycleBeans = getLifecycleBeans(); Map<String, Lifecycle> lifecycleBeans = getLifecycleBeans();
Map<Integer, LifecycleGroup> phases = new HashMap<Integer, LifecycleGroup>(); Map<Integer, LifecycleGroup> phases = new HashMap<Integer, LifecycleGroup>();
for (Map.Entry<String, Lifecycle> entry : lifecycleBeans.entrySet()) { for (Map.Entry<String, Lifecycle> entry : lifecycleBeans.entrySet()) {
Lifecycle lifecycle = entry.getValue(); Lifecycle bean = entry.getValue();
int shutdownOrder = getPhase(lifecycle); int shutdownOrder = getPhase(bean);
LifecycleGroup group = phases.get(shutdownOrder); LifecycleGroup group = phases.get(shutdownOrder);
if (group == null) { if (group == null) {
group = new LifecycleGroup(shutdownOrder, this.timeoutPerShutdownPhase, lifecycleBeans); group = new LifecycleGroup(shutdownOrder, this.timeoutPerShutdownPhase, lifecycleBeans, false);
phases.put(shutdownOrder, group); phases.put(shutdownOrder, group);
} }
group.add(entry.getKey(), lifecycle); group.add(entry.getKey(), bean);
} }
if (phases.size() > 0) { if (phases.size() > 0) {
List<Integer> keys = new ArrayList<Integer>(phases.keySet()); List<Integer> keys = new ArrayList<Integer>(phases.keySet());
@ -309,10 +310,13 @@ public class DefaultLifecycleProcessor implements LifecycleProcessor, BeanFactor
private final long timeout; private final long timeout;
public LifecycleGroup(int phase, long timeout, Map<String, ? extends Lifecycle> lifecycleBeans) { private final boolean autoStartupOnly;
public LifecycleGroup(int phase, long timeout, Map<String, ? extends Lifecycle> lifecycleBeans, boolean autoStartupOnly) {
this.phase = phase; this.phase = phase;
this.timeout = timeout; this.timeout = timeout;
this.lifecycleBeans = lifecycleBeans; this.lifecycleBeans = lifecycleBeans;
this.autoStartupOnly = autoStartupOnly;
} }
public void add(String name, Lifecycle bean) { public void add(String name, Lifecycle bean) {
@ -332,7 +336,7 @@ public class DefaultLifecycleProcessor implements LifecycleProcessor, BeanFactor
Collections.sort(this.members); Collections.sort(this.members);
for (LifecycleGroupMember member : this.members) { for (LifecycleGroupMember member : this.members) {
if (this.lifecycleBeans.containsKey(member.name)) { if (this.lifecycleBeans.containsKey(member.name)) {
doStart(this.lifecycleBeans, member.name); doStart(this.lifecycleBeans, member.name, this.autoStartupOnly);
} }
} }
} }

View File

@ -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"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with 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 java.util.concurrent.CopyOnWriteArrayList;
import static org.junit.Assert.*;
import org.junit.Test; import org.junit.Test;
import org.springframework.beans.DirectFieldAccessor; import org.springframework.beans.DirectFieldAccessor;
@ -29,6 +28,8 @@ import org.springframework.context.Lifecycle;
import org.springframework.context.LifecycleProcessor; import org.springframework.context.LifecycleProcessor;
import org.springframework.context.SmartLifecycle; import org.springframework.context.SmartLifecycle;
import static org.junit.Assert.*;
/** /**
* @author Mark Fisher * @author Mark Fisher
* @since 3.0 * @since 3.0
@ -55,7 +56,8 @@ public class DefaultLifecycleProcessorTests {
Object contextLifecycleProcessor = new DirectFieldAccessor(context).getPropertyValue("lifecycleProcessor"); Object contextLifecycleProcessor = new DirectFieldAccessor(context).getPropertyValue("lifecycleProcessor");
assertNotNull(contextLifecycleProcessor); assertNotNull(contextLifecycleProcessor);
assertSame(bean, contextLifecycleProcessor); assertSame(bean, contextLifecycleProcessor);
assertEquals(1000L, new DirectFieldAccessor(contextLifecycleProcessor).getPropertyValue("timeoutPerShutdownPhase")); assertEquals(1000L, new DirectFieldAccessor(contextLifecycleProcessor).getPropertyValue(
"timeoutPerShutdownPhase"));
} }
@Test @Test
@ -116,6 +118,28 @@ public class DefaultLifecycleProcessorTests {
context.stop(); context.stop();
} }
@Test
public void singleSmartLifecycleAutoStartupWithNonAutoStartupDependency() throws Exception {
CopyOnWriteArrayList<Lifecycle> startedBeans = new CopyOnWriteArrayList<Lifecycle>();
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 @Test
public void smartLifecycleGroupStartup() throws Exception { public void smartLifecycleGroupStartup() throws Exception {
CopyOnWriteArrayList<Lifecycle> startedBeans = new CopyOnWriteArrayList<Lifecycle>(); CopyOnWriteArrayList<Lifecycle> startedBeans = new CopyOnWriteArrayList<Lifecycle>();
@ -578,7 +602,6 @@ public class DefaultLifecycleProcessorTests {
} }
this.running = false; this.running = false;
} }
} }