SmartLifecycle beans will get auto-started on demand even if marked as lazy-init (SPR-6515)

This commit is contained in:
Juergen Hoeller
2009-12-08 12:17:01 +00:00
parent e65ba99e23
commit 93b17042a2
4 changed files with 117 additions and 57 deletions

View File

@@ -1,5 +1,5 @@
/*
* Copyright 2002-2007 the original author or authors.
* Copyright 2002-2009 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.
@@ -32,8 +32,14 @@ package org.springframework.context;
* restricting the visibility of activity-controlled components to the Lifecycle
* interface.
*
* <p>Note that the Lifecycle interface is only supported on <b>top-level singleton beans</b>.
* On any other component, the Lifecycle interface will remain undetected and hence ignored.
* Also, note that the extended {@link SmartLifecycle} interface provides more sophisticated
* integration with the container's startup and shutdown phases.
*
* @author Juergen Hoeller
* @since 2.0
* @see SmartLifecycle
* @see ConfigurableApplicationContext
* @see org.springframework.jms.listener.AbstractMessageListenerContainer
* @see org.springframework.scheduling.quartz.SchedulerFactoryBean

View File

@@ -24,30 +24,35 @@ package org.springframework.context;
* {@link #stop(Runnable)} method is useful for objects that have an asynchronous
* shutdown process. Any implementation of this interface <i>must</i> invoke the
* callback's run() method upon shutdown completion to avoid unnecessary delays
* in the overall ApplicationContext shutdown.
* <p>
* This interface extends {@link Phased}, and the {@link #getPhase()} method's
* in the overall ApplicationContext shutdown.
*
* <p>This interface extends {@link Phased}, and the {@link #getPhase()} method's
* return value indicates the phase within which this Lifecycle component should
* be started and stopped. The startup process begins with the <i>lowest</i>
* phase value and ends with the <i>highest</i> phase value (Integer.MIN_VALUE
* is the lowest possible, and Integer.MAX_VALUE is the highest possible). The
* shutdown process will apply the reverse order. Any components with the
* same value will be arbitrarily ordered within the same phase.
* <p>
* Example: if component B depends on component A having already started, then
*
* <p>Example: if component B depends on component A having already started, then
* component A should have a lower phase value than component B. During the
* shutdown process, component B would be stopped before component A.
* <p>
* Any explicit "depends-on" relationship will take precedence over
*
* <p>Any explicit "depends-on" relationship will take precedence over
* the phase order such that the dependent bean always starts after its
* dependency and always stops before its dependency.
* <p>
* Any Lifecycle components within the context that do not also implement
*
* <p>Any Lifecycle components within the context that do not also implement
* SmartLifecycle will be treated as if they have a phase value of 0. That
* way a SmartLifecycle implementation may start before those Lifecycle
* components if it has a negative phase value, or it may start after
* those components if it has a positive phase value.
*
*
* <p>Note that, due to the auto-startup support in SmartLifecycle,
* a SmartLifecycle bean instance will get initialized on startup of the
* application context in any case. As a consequence, the bean definition
* lazy-init flag has very limited actual effect on SmartLifecycle beans.
*
* @author Mark Fisher
* @since 3.0
*/
@@ -62,7 +67,7 @@ public interface SmartLifecycle extends Lifecycle, Phased {
/**
* Indicates that a Lifecycle component must stop if it is currently running.
* The provided callback is used by the LifecycleProcessor to support an
* <p>The provided callback is used by the LifecycleProcessor to support an
* ordered, and potentially concurrent, shutdown of all components having a
* common shutdown order value. The callback <b>must</b> be executed after
* the SmartLifecycle component does indeed stop.

View File

@@ -39,8 +39,9 @@ import org.springframework.util.Assert;
/**
* Default implementation of the {@link LifecycleProcessor} strategy.
*
*
* @author Mark Fisher
* @author Juergen Hoeller
* @since 3.0
*/
public class DefaultLifecycleProcessor implements LifecycleProcessor, BeanFactoryAware {
@@ -64,18 +65,12 @@ public class DefaultLifecycleProcessor implements LifecycleProcessor, BeanFactor
}
public void setBeanFactory(BeanFactory beanFactory) {
Assert.isTrue(beanFactory instanceof ConfigurableListableBeanFactory,
"A ConfigurableListableBeanFactory is required.");
Assert.isInstanceOf(ConfigurableListableBeanFactory.class, beanFactory);
this.beanFactory = (ConfigurableListableBeanFactory) beanFactory;
}
/*
* Lifecycle implementation
*/
public boolean isRunning() {
return this.running;
}
// Lifecycle implementation
/**
* Start all registered beans that implement Lifecycle and are
@@ -87,7 +82,8 @@ public class DefaultLifecycleProcessor implements LifecycleProcessor, BeanFactor
* the dependent bean regardless of the declared phase.
*/
public void start() {
this.startBeans(false);
startBeans(false);
this.running = true;
}
/**
@@ -100,36 +96,27 @@ public class DefaultLifecycleProcessor implements LifecycleProcessor, BeanFactor
* the dependency bean regardless of the declared phase.
*/
public void stop() {
Map<String, Lifecycle> lifecycleBeans = getLifecycleBeans();
Map<Integer, LifecycleGroup> phases = new HashMap<Integer, LifecycleGroup>();
for (Map.Entry<String, Lifecycle> entry : lifecycleBeans.entrySet()) {
Lifecycle lifecycle = entry.getValue();
int shutdownOrder = getPhase(lifecycle);
LifecycleGroup group = phases.get(shutdownOrder);
if (group == null) {
group = new LifecycleGroup(shutdownOrder, this.timeoutPerShutdownPhase, lifecycleBeans);
phases.put(shutdownOrder, group);
}
group.add(entry.getKey(), lifecycle);
}
if (phases.size() > 0) {
List<Integer> keys = new ArrayList<Integer>(phases.keySet());
Collections.sort(keys, Collections.reverseOrder());
for (Integer key : keys) {
phases.get(key).stop();
}
}
stopBeans();
this.running = false;
}
public void onRefresh() {
this.startBeans(true);
startBeans(true);
this.running = true;
}
public void onClose() {
stop();
stopBeans();
this.running = false;
}
public boolean isRunning() {
return this.running;
}
// internal helpers
private void startBeans(boolean autoStartupOnly) {
Map<String, Lifecycle> lifecycleBeans = getLifecycleBeans();
Map<Integer, LifecycleGroup> phases = new HashMap<Integer, LifecycleGroup>();
@@ -152,7 +139,6 @@ public class DefaultLifecycleProcessor implements LifecycleProcessor, BeanFactor
phases.get(key).start();
}
}
this.running = true;
}
/**
@@ -175,6 +161,28 @@ public class DefaultLifecycleProcessor implements LifecycleProcessor, BeanFactor
}
}
private void stopBeans() {
Map<String, Lifecycle> lifecycleBeans = getLifecycleBeans();
Map<Integer, LifecycleGroup> phases = new HashMap<Integer, LifecycleGroup>();
for (Map.Entry<String, Lifecycle> entry : lifecycleBeans.entrySet()) {
Lifecycle lifecycle = entry.getValue();
int shutdownOrder = getPhase(lifecycle);
LifecycleGroup group = phases.get(shutdownOrder);
if (group == null) {
group = new LifecycleGroup(shutdownOrder, this.timeoutPerShutdownPhase, lifecycleBeans);
phases.put(shutdownOrder, group);
}
group.add(entry.getKey(), lifecycle);
}
if (phases.size() > 0) {
List<Integer> keys = new ArrayList<Integer>(phases.keySet());
Collections.sort(keys, Collections.reverseOrder());
for (Integer key : keys) {
phases.get(key).stop();
}
}
}
/**
* Stop the specified bean as part of the given set of Lifecycle beans,
* making sure that any beans that depends on it are stopped first.
@@ -209,20 +217,22 @@ public class DefaultLifecycleProcessor implements LifecycleProcessor, BeanFactor
}
private Map<String, Lifecycle> getLifecycleBeans() {
String[] beanNames = beanFactory.getSingletonNames();
String[] beanNames = this.beanFactory.getBeanNamesForType(Lifecycle.class, false, false);
Map<String, Lifecycle> beans = new LinkedHashMap<String, Lifecycle>();
for (String beanName : beanNames) {
Object bean = beanFactory.getSingleton(beanName);
if (bean instanceof Lifecycle && !this.equals(bean)) {
beans.put(beanName, (Lifecycle) bean);
if (this.beanFactory.containsSingleton(beanName) ||
SmartLifecycle.class.isAssignableFrom(this.beanFactory.getType(beanName))) {
Object bean = this.beanFactory.getBean(beanName);
if (!this.equals(bean)) {
beans.put(beanName, (Lifecycle) bean);
}
}
}
return beans;
}
private static int getPhase(Lifecycle bean) {
return (bean instanceof Phased) ?
((Phased) bean).getPhase() : 0;
return (bean instanceof Phased) ? ((Phased) bean).getPhase() : 0;
}