001: /*
002: * Copyright 2002-2007 the original author or authors.
003: *
004: * Licensed under the Apache License, Version 2.0 (the "License");
005: * you may not use this file except in compliance with the License.
006: * You may obtain a copy of the License at
007: *
008: * http://www.apache.org/licenses/LICENSE-2.0
009: *
010: * Unless required by applicable law or agreed to in writing, software
011: * distributed under the License is distributed on an "AS IS" BASIS,
012: * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
013: * See the License for the specific language governing permissions and
014: * limitations under the License.
015: */
016:
017: package org.springframework.context.support;
018:
019: import java.io.IOException;
020:
021: import org.springframework.beans.BeansException;
022: import org.springframework.beans.factory.config.ConfigurableListableBeanFactory;
023: import org.springframework.beans.factory.support.DefaultListableBeanFactory;
024: import org.springframework.context.ApplicationContext;
025: import org.springframework.context.ApplicationContextException;
026:
027: /**
028: * Base class for {@link org.springframework.context.ApplicationContext}
029: * implementations which are supposed to support multiple refreshs,
030: * creating a new internal bean factory instance every time.
031: * Typically (but not necessarily), such a context will be driven by
032: * a set of config locations to load bean definitions from.
033: *
034: * <p>The only method to be implemented by subclasses is {@link #loadBeanDefinitions},
035: * which gets invoked on each refresh. A concrete implementation is supposed to load
036: * bean definitions into the given
037: * {@link org.springframework.beans.factory.support.DefaultListableBeanFactory},
038: * typically delegating to one or more specific bean definition readers.
039: *
040: * <p><b>Note that there is a similar base class for WebApplicationContexts.</b>
041: * {@link org.springframework.web.context.support.AbstractRefreshableWebApplicationContext}
042: * provides the same subclassing strategy, but additionally pre-implements
043: * all context functionality for web environments. There is also a
044: * pre-defined way to receive config locations for a web context.
045: *
046: * <p>Concrete standalone subclasses of this base class, reading in a
047: * specific bean definition format, are {@link ClassPathXmlApplicationContext}
048: * and {@link FileSystemXmlApplicationContext}, which both derive from the
049: * common {@link AbstractXmlApplicationContext} base class.
050: *
051: * @author Juergen Hoeller
052: * @since 1.1.3
053: * @see #loadBeanDefinitions
054: * @see org.springframework.beans.factory.support.DefaultListableBeanFactory
055: * @see org.springframework.web.context.support.AbstractRefreshableWebApplicationContext
056: * @see AbstractXmlApplicationContext
057: * @see ClassPathXmlApplicationContext
058: * @see FileSystemXmlApplicationContext
059: */
060: public abstract class AbstractRefreshableApplicationContext extends
061: AbstractApplicationContext {
062:
063: /** Bean factory for this context */
064: private DefaultListableBeanFactory beanFactory;
065:
066: /** Synchronization monitor for the internal BeanFactory */
067: private final Object beanFactoryMonitor = new Object();
068:
069: /**
070: * Create a new AbstractRefreshableApplicationContext with no parent.
071: */
072: public AbstractRefreshableApplicationContext() {
073: }
074:
075: /**
076: * Create a new AbstractRefreshableApplicationContext with the given parent context.
077: * @param parent the parent context
078: */
079: public AbstractRefreshableApplicationContext(
080: ApplicationContext parent) {
081: super (parent);
082: }
083:
084: /**
085: * This implementation performs an actual refresh of this context's underlying
086: * bean factory, shutting down the previous bean factory (if any) and
087: * initializing a fresh bean factory for the next phase of the context's lifecycle.
088: */
089: protected final void refreshBeanFactory() throws BeansException {
090: if (hasBeanFactory()) {
091: destroyBeans();
092: closeBeanFactory();
093: }
094: try {
095: DefaultListableBeanFactory beanFactory = createBeanFactory();
096: customizeBeanFactory(beanFactory);
097: loadBeanDefinitions(beanFactory);
098: synchronized (this .beanFactoryMonitor) {
099: this .beanFactory = beanFactory;
100: }
101: } catch (IOException ex) {
102: throw new ApplicationContextException(
103: "I/O error parsing XML document for application context ["
104: + getDisplayName() + "]", ex);
105: }
106: }
107:
108: protected final void closeBeanFactory() {
109: synchronized (this .beanFactoryMonitor) {
110: this .beanFactory = null;
111: }
112: }
113:
114: /**
115: * Determine whether this context currently holds a bean factory,
116: * i.e. has been refreshed at least once and not been closed yet.
117: */
118: protected final boolean hasBeanFactory() {
119: synchronized (this .beanFactoryMonitor) {
120: return (this .beanFactory != null);
121: }
122: }
123:
124: public final ConfigurableListableBeanFactory getBeanFactory() {
125: synchronized (this .beanFactoryMonitor) {
126: if (this .beanFactory == null) {
127: throw new IllegalStateException(
128: "BeanFactory not initialized or already closed - "
129: + "call 'refresh' before accessing beans via the ApplicationContext");
130: }
131: return this .beanFactory;
132: }
133: }
134:
135: /**
136: * Create an internal bean factory for this context.
137: * Called for each {@link #refresh()} attempt.
138: * <p>The default implementation creates a
139: * {@link org.springframework.beans.factory.support.DefaultListableBeanFactory}
140: * with the {@link #getInternalParentBeanFactory() internal bean factory} of this
141: * context's parent as parent bean factory. Can be overridden in subclasses,
142: * for example to customize DefaultListableBeanFactory's settings.
143: * @return the bean factory for this context
144: * @see org.springframework.beans.factory.support.DefaultListableBeanFactory#setAllowBeanDefinitionOverriding
145: * @see org.springframework.beans.factory.support.DefaultListableBeanFactory#setAllowEagerClassLoading
146: * @see org.springframework.beans.factory.support.DefaultListableBeanFactory#setAllowCircularReferences
147: * @see org.springframework.beans.factory.support.DefaultListableBeanFactory#setAllowRawInjectionDespiteWrapping
148: */
149: protected DefaultListableBeanFactory createBeanFactory() {
150: return new DefaultListableBeanFactory(
151: getInternalParentBeanFactory());
152: }
153:
154: /**
155: * Customize the internal bean factory used by this context.
156: * Called for each {@link #refresh()} attempt.
157: * <p>The default implementation is empty. Can be overridden in subclasses
158: * to customize DefaultListableBeanFactory's standard settings.
159: * @param beanFactory the newly created bean factory for this context
160: * @see org.springframework.beans.factory.support.DefaultListableBeanFactory#setAllowBeanDefinitionOverriding
161: * @see org.springframework.beans.factory.support.DefaultListableBeanFactory#setAllowEagerClassLoading
162: * @see org.springframework.beans.factory.support.DefaultListableBeanFactory#setAllowCircularReferences
163: * @see org.springframework.beans.factory.support.DefaultListableBeanFactory#setAllowRawInjectionDespiteWrapping
164: */
165: protected void customizeBeanFactory(
166: DefaultListableBeanFactory beanFactory) {
167: }
168:
169: /**
170: * Load bean definitions into the given bean factory, typically through
171: * delegating to one or more bean definition readers.
172: * @param beanFactory the bean factory to load bean definitions into
173: * @throws IOException if loading of bean definition files failed
174: * @throws BeansException if parsing of the bean definitions failed
175: * @see org.springframework.beans.factory.support.PropertiesBeanDefinitionReader
176: * @see org.springframework.beans.factory.xml.XmlBeanDefinitionReader
177: */
178: protected abstract void loadBeanDefinitions(
179: DefaultListableBeanFactory beanFactory) throws IOException,
180: BeansException;
181:
182: }
|