/* * Copyright 2002-2008 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.io.IOException; import org.springframework.beans.BeansException; import org.springframework.beans.factory.config.ConfigurableListableBeanFactory; import org.springframework.beans.factory.support.DefaultListableBeanFactory; import org.springframework.context.ApplicationContext; import org.springframework.context.ApplicationContextException; /** * Base class for {@link org.springframework.context.ApplicationContext} * implementations which are supposed to support multiple refreshs, * creating a new internal bean factory instance every time. * Typically (but not necessarily), such a context will be driven by * a set of config locations to load bean definitions from. * * <p>The only method to be implemented by subclasses is {@link #loadBeanDefinitions}, * which gets invoked on each refresh. A concrete implementation is supposed to load * bean definitions into the given * {@link org.springframework.beans.factory.support.DefaultListableBeanFactory}, * typically delegating to one or more specific bean definition readers. * * <p><b>Note that there is a similar base class for WebApplicationContexts.</b> * {@link org.springframework.web.context.support.AbstractRefreshableWebApplicationContext} * provides the same subclassing strategy, but additionally pre-implements * all context functionality for web environments. There is also a * pre-defined way to receive config locations for a web context. * * <p>Concrete standalone subclasses of this base class, reading in a * specific bean definition format, are {@link ClassPathXmlApplicationContext} * and {@link FileSystemXmlApplicationContext}, which both derive from the * common {@link AbstractXmlApplicationContext} base class. * * @author Juergen Hoeller * @since 1.1.3 * @see #loadBeanDefinitions * @see org.springframework.beans.factory.support.DefaultListableBeanFactory * @see org.springframework.web.context.support.AbstractRefreshableWebApplicationContext * @see AbstractXmlApplicationContext * @see ClassPathXmlApplicationContext * @see FileSystemXmlApplicationContext */ public abstract class AbstractRefreshableApplicationContext extends AbstractApplicationContext { private Boolean allowBeanDefinitionOverriding; private Boolean allowCircularReferences; /** Bean factory for this context */ private DefaultListableBeanFactory beanFactory; /** Synchronization monitor for the internal BeanFactory */ private final Object beanFactoryMonitor = new Object(); /** * Create a new AbstractRefreshableApplicationContext with no parent. */ public AbstractRefreshableApplicationContext() { } /** * Create a new AbstractRefreshableApplicationContext with the given parent context. * @param parent the parent context */ public AbstractRefreshableApplicationContext(ApplicationContext parent) { super(parent); } /** * Set whether it should be allowed to override bean definitions by registering * a different definition with the same name, automatically replacing the former. * If not, an exception will be thrown. Default is "true". * @see org.springframework.beans.factory.support.DefaultListableBeanFactory#setAllowBeanDefinitionOverriding */ public void setAllowBeanDefinitionOverriding(boolean allowBeanDefinitionOverriding) { this.allowBeanDefinitionOverriding = Boolean.valueOf(allowBeanDefinitionOverriding); } /** * Set whether to allow circular references between beans - and automatically * try to resolve them. * <p>Default is "true". Turn this off to throw an exception when encountering * a circular reference, disallowing them completely. * @see org.springframework.beans.factory.support.DefaultListableBeanFactory#setAllowCircularReferences */ public void setAllowCircularReferences(boolean allowCircularReferences) { this.allowCircularReferences = Boolean.valueOf(allowCircularReferences); } /** * This implementation performs an actual refresh of this context's underlying * bean factory, shutting down the previous bean factory (if any) and * initializing a fresh bean factory for the next phase of the context's lifecycle. */ protected final void refreshBeanFactory() throws BeansException { if (hasBeanFactory()) { destroyBeans(); closeBeanFactory(); } try { DefaultListableBeanFactory beanFactory = createBeanFactory(); customizeBeanFactory(beanFactory); loadBeanDefinitions(beanFactory); synchronized (this.beanFactoryMonitor) { this.beanFactory = beanFactory; } } catch (IOException ex) { throw new ApplicationContextException( "I/O error parsing XML document for application context [" + getDisplayName() + "]", ex); } } protected final void closeBeanFactory() { synchronized (this.beanFactoryMonitor) { this.beanFactory = null; } } /** * Determine whether this context currently holds a bean factory, * i.e. has been refreshed at least once and not been closed yet. */ protected final boolean hasBeanFactory() { synchronized (this.beanFactoryMonitor) { return (this.beanFactory != null); } } public final ConfigurableListableBeanFactory getBeanFactory() { synchronized (this.beanFactoryMonitor) { if (this.beanFactory == null) { throw new IllegalStateException("BeanFactory not initialized or already closed - " + "call 'refresh' before accessing beans via the ApplicationContext"); } return this.beanFactory; } } /** * Create an internal bean factory for this context. * Called for each {@link #refresh()} attempt. * <p>The default implementation creates a * {@link org.springframework.beans.factory.support.DefaultListableBeanFactory} * with the {@link #getInternalParentBeanFactory() internal bean factory} of this * context's parent as parent bean factory. Can be overridden in subclasses, * for example to customize DefaultListableBeanFactory's settings. * @return the bean factory for this context * @see org.springframework.beans.factory.support.DefaultListableBeanFactory#setAllowBeanDefinitionOverriding * @see org.springframework.beans.factory.support.DefaultListableBeanFactory#setAllowEagerClassLoading * @see org.springframework.beans.factory.support.DefaultListableBeanFactory#setAllowCircularReferences * @see org.springframework.beans.factory.support.DefaultListableBeanFactory#setAllowRawInjectionDespiteWrapping */ protected DefaultListableBeanFactory createBeanFactory() { return new DefaultListableBeanFactory(getInternalParentBeanFactory()); } /** * Customize the internal bean factory used by this context. * Called for each {@link #refresh()} attempt. * <p>The default implementation applies this context's * {@link #setAllowBeanDefinitionOverriding "allowBeanDefinitionOverriding"} * and {@link #setAllowCircularReferences "allowCircularReferences"} settings, * if specified. Can be overridden in subclasses to customize any of * {@link DefaultListableBeanFactory}'s settings. * @param beanFactory the newly created bean factory for this context * @see DefaultListableBeanFactory#setAllowBeanDefinitionOverriding * @see DefaultListableBeanFactory#setAllowCircularReferences * @see DefaultListableBeanFactory#setAllowRawInjectionDespiteWrapping * @see DefaultListableBeanFactory#setAllowEagerClassLoading */ protected void customizeBeanFactory(DefaultListableBeanFactory beanFactory) { if (this.allowBeanDefinitionOverriding != null) { beanFactory.setAllowBeanDefinitionOverriding(this.allowBeanDefinitionOverriding.booleanValue()); } if (this.allowCircularReferences != null) { beanFactory.setAllowCircularReferences(this.allowCircularReferences.booleanValue()); } } /** * Load bean definitions into the given bean factory, typically through * delegating to one or more bean definition readers. * @param beanFactory the bean factory to load bean definitions into * @throws IOException if loading of bean definition files failed * @throws BeansException if parsing of the bean definitions failed * @see org.springframework.beans.factory.support.PropertiesBeanDefinitionReader * @see org.springframework.beans.factory.xml.XmlBeanDefinitionReader */ protected abstract void loadBeanDefinitions(DefaultListableBeanFactory beanFactory) throws IOException, BeansException; }