SmartLifecycle beans will get auto-started on demand even if marked as lazy-init (SPR-6515)
This commit is contained in:
@@ -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
|
||||
|
||||
@@ -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.
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
|
||||
|
||||
Reference in New Issue
Block a user