diff --git a/org.springframework.context/src/main/java/org/springframework/context/LifecycleProcessor.java b/org.springframework.context/src/main/java/org/springframework/context/LifecycleProcessor.java
new file mode 100644
index 00000000000..8d39eab60aa
--- /dev/null
+++ b/org.springframework.context/src/main/java/org/springframework/context/LifecycleProcessor.java
@@ -0,0 +1,25 @@
+/*
+ * 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.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.springframework.context;
+
+/**
+ * @author Mark Fisher
+ * @since 3.0
+ */
+public interface LifecycleProcessor extends Lifecycle {
+
+}
diff --git a/org.springframework.context/src/main/java/org/springframework/context/support/AbstractApplicationContext.java b/org.springframework.context/src/main/java/org/springframework/context/support/AbstractApplicationContext.java
index 93db7d25595..d0db5de9037 100644
--- a/org.springframework.context/src/main/java/org/springframework/context/support/AbstractApplicationContext.java
+++ b/org.springframework.context/src/main/java/org/springframework/context/support/AbstractApplicationContext.java
@@ -23,7 +23,6 @@ import java.util.ArrayList;
import java.util.Collections;
import java.util.Date;
import java.util.LinkedHashMap;
-import java.util.LinkedHashSet;
import java.util.List;
import java.util.Locale;
import java.util.Map;
@@ -50,6 +49,7 @@ import org.springframework.context.ApplicationListener;
import org.springframework.context.ConfigurableApplicationContext;
import org.springframework.context.HierarchicalMessageSource;
import org.springframework.context.Lifecycle;
+import org.springframework.context.LifecycleProcessor;
import org.springframework.context.MessageSource;
import org.springframework.context.MessageSourceAware;
import org.springframework.context.MessageSourceResolvable;
@@ -126,6 +126,14 @@ public abstract class AbstractApplicationContext extends DefaultResourceLoader
*/
public static final String MESSAGE_SOURCE_BEAN_NAME = "messageSource";
+ /**
+ * Name of the LifecycleProcessor bean in the factory.
+ * If none is supplied, a DefaultLifecycleProcessor is used.
+ * @see org.springframework.context.LifecycleProcessor
+ * @see org.springframework.context.support.DefaultLifecycleProcessor
+ */
+ public static final String LIFECYCLE_PROCESSOR_BEAN_NAME = "lifecycleProcessor";
+
/**
* Name of the ApplicationEventMulticaster bean in the factory.
* If none is supplied, a default SimpleApplicationEventMulticaster is used.
@@ -179,6 +187,9 @@ public abstract class AbstractApplicationContext extends DefaultResourceLoader
/** MessageSource we delegate our implementation of this interface to */
private MessageSource messageSource;
+ /** LifecycleProcessor for managing the lifecycle of beans within this context */
+ private LifecycleProcessor lifecycleProcessor;
+
/** Helper class used in event publishing */
private ApplicationEventMulticaster applicationEventMulticaster;
@@ -287,8 +298,21 @@ public abstract class AbstractApplicationContext extends DefaultResourceLoader
}
/**
- * Return the internal MessageSource used by the context.
- * @return the internal MessageSource (never null)
+ * Return the internal LifecycleProcessor used by the context.
+ * @return the internal LifecycleProcessor (never null)
+ * @throws IllegalStateException if the context has not been initialized yet
+ */
+ private LifecycleProcessor getLifecycleProcessor() {
+ if (this.lifecycleProcessor == null) {
+ throw new IllegalStateException("LifecycleProcessor not initialized - " +
+ "call 'refresh' before invoking lifecycle methods via the context: " + this);
+ }
+ return this.lifecycleProcessor;
+ }
+
+ /**
+ * Return the internal ApplicationEventMulticaster used by the context.
+ * @return the internal ApplicationEventMulticaster (never null)
* @throws IllegalStateException if the context has not been initialized yet
*/
private ApplicationEventMulticaster getApplicationEventMulticaster() throws IllegalStateException {
@@ -377,6 +401,9 @@ public abstract class AbstractApplicationContext extends DefaultResourceLoader
// Initialize message source for this context.
initMessageSource();
+ // Initialize lifecycle processor for this context.
+ initLifecycleProcessor();
+
// Initialize event multicaster for this context.
initApplicationEventMulticaster();
@@ -676,6 +703,33 @@ public abstract class AbstractApplicationContext extends DefaultResourceLoader
}
}
+ /**
+ * Initialize the LifecycleProcessor.
+ * Uses DefaultLifecycleProcessor if none defined in the context.
+ * @see org.springframework.context.support.DefaultLifecycleProcessor
+ */
+ protected void initLifecycleProcessor() {
+ ConfigurableListableBeanFactory beanFactory = getBeanFactory();
+ if (beanFactory.containsLocalBean(LIFECYCLE_PROCESSOR_BEAN_NAME)) {
+ this.lifecycleProcessor =
+ beanFactory.getBean(LIFECYCLE_PROCESSOR_BEAN_NAME, LifecycleProcessor.class);
+ if (logger.isDebugEnabled()) {
+ logger.debug("Using LifecycleProcessor [" + this.lifecycleProcessor + "]");
+ }
+ }
+ else {
+ DefaultLifecycleProcessor defaultProcessor = new DefaultLifecycleProcessor();
+ defaultProcessor.setBeanFactory(beanFactory);
+ this.lifecycleProcessor = defaultProcessor;
+ beanFactory.registerSingleton(LIFECYCLE_PROCESSOR_BEAN_NAME, this.lifecycleProcessor);
+ if (logger.isDebugEnabled()) {
+ logger.debug("Unable to locate LifecycleProcessor with name '" +
+ LIFECYCLE_PROCESSOR_BEAN_NAME +
+ "': using default [" + this.lifecycleProcessor + "]");
+ }
+ }
+ }
+
/**
* Initialize the ApplicationEventMulticaster.
* Uses SimpleApplicationEventMulticaster if none defined in the context.
@@ -851,10 +905,7 @@ public abstract class AbstractApplicationContext extends DefaultResourceLoader
}
// Stop all Lifecycle beans, to avoid delays during individual destruction.
- Map lifecycleBeans = getLifecycleBeans();
- for (String beanName : new LinkedHashSet(lifecycleBeans.keySet())) {
- doStop(lifecycleBeans, beanName);
- }
+ this.getLifecycleProcessor().stop();
// Destroy all cached singletons in the context's BeanFactory.
destroyBeans();
@@ -1076,18 +1127,12 @@ public abstract class AbstractApplicationContext extends DefaultResourceLoader
//---------------------------------------------------------------------
public void start() {
- Map lifecycleBeans = getLifecycleBeans();
- for (String beanName : new LinkedHashSet(lifecycleBeans.keySet())) {
- doStart(lifecycleBeans, beanName);
- }
+ this.getLifecycleProcessor().start();
publishEvent(new ContextStartedEvent(this));
}
public void stop() {
- Map lifecycleBeans = getLifecycleBeans();
- for (String beanName : new LinkedHashSet(lifecycleBeans.keySet())) {
- doStop(lifecycleBeans, beanName);
- }
+ this.getLifecycleProcessor().stop();
publishEvent(new ContextStoppedEvent(this));
}
@@ -1118,46 +1163,6 @@ public abstract class AbstractApplicationContext extends DefaultResourceLoader
return beans;
}
- /**
- * Start the specified bean as part of the given set of Lifecycle beans,
- * making sure that any beans that it depends on are started first.
- * @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) {
- Lifecycle bean = lifecycleBeans.get(beanName);
- if (bean != null) {
- String[] dependenciesForBean = getBeanFactory().getDependenciesForBean(beanName);
- for (String dependency : dependenciesForBean) {
- doStart(lifecycleBeans, dependency);
- }
- if (!bean.isRunning()) {
- bean.start();
- }
- lifecycleBeans.remove(beanName);
- }
- }
-
- /**
- * 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.
- * @param lifecycleBeans Map with bean name as key and Lifecycle instance as value
- * @param beanName the name of the bean to stop
- */
- private void doStop(Map lifecycleBeans, String beanName) {
- Lifecycle bean = (Lifecycle) lifecycleBeans.get(beanName);
- if (bean != null) {
- String[] dependentBeans = getBeanFactory().getDependentBeans(beanName);
- for (String dependentBean : dependentBeans) {
- doStop(lifecycleBeans, dependentBean);
- }
- if (bean.isRunning()) {
- bean.stop();
- }
- lifecycleBeans.remove(beanName);
- }
- }
-
//---------------------------------------------------------------------
// Abstract methods that must be implemented by subclasses
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
new file mode 100644
index 00000000000..5dc249479b9
--- /dev/null
+++ b/org.springframework.context/src/main/java/org/springframework/context/support/DefaultLifecycleProcessor.java
@@ -0,0 +1,123 @@
+/*
+ * 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.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.springframework.context.support;
+
+import java.util.LinkedHashMap;
+import java.util.LinkedHashSet;
+import java.util.Map;
+
+import org.springframework.beans.factory.BeanFactory;
+import org.springframework.beans.factory.BeanFactoryAware;
+import org.springframework.beans.factory.config.ConfigurableListableBeanFactory;
+import org.springframework.context.Lifecycle;
+import org.springframework.context.LifecycleProcessor;
+import org.springframework.util.Assert;
+
+/**
+ * @author Mark Fisher
+ * @since 3.0
+ */
+public class DefaultLifecycleProcessor implements LifecycleProcessor, BeanFactoryAware {
+
+ private volatile boolean running;
+
+ private volatile ConfigurableListableBeanFactory beanFactory;
+
+
+ public void setBeanFactory(BeanFactory beanFactory) {
+ Assert.isTrue(beanFactory instanceof ConfigurableListableBeanFactory,
+ "A ConfigurableListableBeanFactory is required.");
+ this.beanFactory = (ConfigurableListableBeanFactory) beanFactory;
+ }
+
+ /*
+ * Lifecycle implementation
+ */
+
+ public boolean isRunning() {
+ return this.running;
+ }
+
+ public void start() {
+ Map lifecycleBeans = getLifecycleBeans();
+ for (String beanName : new LinkedHashSet(lifecycleBeans.keySet())) {
+ doStart(lifecycleBeans, beanName);
+ }
+ this.running = true;
+ }
+
+ public void stop() {
+ Map lifecycleBeans = getLifecycleBeans();
+ for (String beanName : new LinkedHashSet(lifecycleBeans.keySet())) {
+ doStop(lifecycleBeans, beanName);
+ }
+ this.running = false;
+ }
+
+ /**
+ * Start the specified bean as part of the given set of Lifecycle beans,
+ * making sure that any beans that it depends on are started first.
+ * @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) {
+ Lifecycle bean = lifecycleBeans.get(beanName);
+ if (bean != null && !this.equals(bean)) {
+ String[] dependenciesForBean = this.beanFactory.getDependenciesForBean(beanName);
+ for (String dependency : dependenciesForBean) {
+ doStart(lifecycleBeans, dependency);
+ }
+ if (!bean.isRunning()) {
+ bean.start();
+ }
+ lifecycleBeans.remove(beanName);
+ }
+ }
+
+ /**
+ * 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.
+ * @param lifecycleBeans Map with bean name as key and Lifecycle instance as value
+ * @param beanName the name of the bean to stop
+ */
+ private void doStop(Map lifecycleBeans, String beanName) {
+ Lifecycle bean = lifecycleBeans.get(beanName);
+ if (bean != null && !this.equals(bean)) {
+ String[] dependentBeans = this.beanFactory.getDependentBeans(beanName);
+ for (String dependentBean : dependentBeans) {
+ doStop(lifecycleBeans, dependentBean);
+ }
+ if (bean.isRunning()) {
+ bean.stop();
+ }
+ lifecycleBeans.remove(beanName);
+ }
+ }
+
+ private Map getLifecycleBeans() {
+ String[] beanNames = beanFactory.getSingletonNames();
+ Map beans = new LinkedHashMap();
+ for (String beanName : beanNames) {
+ Object bean = beanFactory.getSingleton(beanName);
+ if (bean instanceof Lifecycle) {
+ beans.put(beanName, (Lifecycle) bean);
+ }
+ }
+ return beans;
+ }
+
+}