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: protected final void refreshBeanFactory() throws BeansException {
085: // Shut down previous bean factory, if any.
086: ConfigurableListableBeanFactory oldBeanFactory = null;
087: synchronized (this .beanFactoryMonitor) {
088: oldBeanFactory = this .beanFactory;
089: }
090: if (oldBeanFactory != null) {
091: oldBeanFactory.destroySingletons();
092: synchronized (this .beanFactoryMonitor) {
093: this .beanFactory = null;
094: }
095: }
096:
097: // Initialize fresh bean factory.
098: try {
099: DefaultListableBeanFactory beanFactory = createBeanFactory();
100: customizeBeanFactory(beanFactory);
101: loadBeanDefinitions(beanFactory);
102: synchronized (this .beanFactoryMonitor) {
103: this .beanFactory = beanFactory;
104: }
105: } catch (IOException ex) {
106: throw new ApplicationContextException(
107: "I/O error parsing XML document for application context ["
108: + getDisplayName() + "]", ex);
109: }
110: }
111:
112: protected final void closeBeanFactory() {
113: synchronized (this .beanFactoryMonitor) {
114: this .beanFactory = null;
115: }
116: }
117:
118: public final ConfigurableListableBeanFactory getBeanFactory() {
119: synchronized (this .beanFactoryMonitor) {
120: if (this .beanFactory == null) {
121: throw new IllegalStateException(
122: "BeanFactory not initialized or already closed - "
123: + "call 'refresh' before accessing beans via the ApplicationContext");
124: }
125: return this .beanFactory;
126: }
127: }
128:
129: /**
130: * Create an internal bean factory for this context.
131: * Called for each {@link #refresh()} attempt.
132: * <p>The default implementation creates a
133: * {@link org.springframework.beans.factory.support.DefaultListableBeanFactory}
134: * with the {@link #getInternalParentBeanFactory() internal bean factory} of this
135: * context's parent as parent bean factory. Can be overridden in subclasses,
136: * for example to customize DefaultListableBeanFactory's settings.
137: * @return the bean factory for this context
138: * @see org.springframework.beans.factory.support.DefaultListableBeanFactory#setAllowBeanDefinitionOverriding
139: * @see org.springframework.beans.factory.support.DefaultListableBeanFactory#setAllowEagerClassLoading
140: * @see org.springframework.beans.factory.support.DefaultListableBeanFactory#setAllowCircularReferences
141: * @see org.springframework.beans.factory.support.DefaultListableBeanFactory#setAllowRawInjectionDespiteWrapping
142: */
143: protected DefaultListableBeanFactory createBeanFactory() {
144: return new DefaultListableBeanFactory(
145: getInternalParentBeanFactory());
146: }
147:
148: /**
149: * Customize the internal bean factory used by this context.
150: * Called for each {@link #refresh()} attempt.
151: * <p>The default implementation is empty. Can be overridden in subclasses
152: * to customize DefaultListableBeanFactory's standard settings.
153: * @param beanFactory the newly created bean factory for this context
154: * @see org.springframework.beans.factory.support.DefaultListableBeanFactory#setAllowBeanDefinitionOverriding
155: * @see org.springframework.beans.factory.support.DefaultListableBeanFactory#setAllowEagerClassLoading
156: * @see org.springframework.beans.factory.support.DefaultListableBeanFactory#setAllowCircularReferences
157: * @see org.springframework.beans.factory.support.DefaultListableBeanFactory#setAllowRawInjectionDespiteWrapping
158: */
159: protected void customizeBeanFactory(
160: DefaultListableBeanFactory beanFactory) {
161: }
162:
163: /**
164: * Load bean definitions into the given bean factory, typically through
165: * delegating to one or more bean definition readers.
166: * @param beanFactory the bean factory to load bean definitions into
167: * @throws IOException if loading of bean definition files failed
168: * @throws BeansException if parsing of the bean definitions failed
169: * @see org.springframework.beans.factory.support.PropertiesBeanDefinitionReader
170: * @see org.springframework.beans.factory.xml.XmlBeanDefinitionReader
171: */
172: protected abstract void loadBeanDefinitions(
173: DefaultListableBeanFactory beanFactory) throws IOException,
174: BeansException;
175:
176: }
|