001/*
002 * Copyright 2002-2020 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 *      https://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
017package org.springframework.context.support;
018
019import java.io.IOException;
020
021import org.springframework.beans.BeansException;
022import org.springframework.beans.factory.config.ConfigurableListableBeanFactory;
023import org.springframework.beans.factory.support.DefaultListableBeanFactory;
024import org.springframework.context.ApplicationContext;
025import org.springframework.context.ApplicationContextException;
026
027/**
028 * Base class for {@link org.springframework.context.ApplicationContext}
029 * implementations which are supposed to support multiple calls to {@link #refresh()},
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 * {@link org.springframework.context.annotation.AnnotationConfigApplicationContext}
051 * supports {@code @Configuration}-annotated classes as a source of bean definitions.
052 *
053 * @author Juergen Hoeller
054 * @author Chris Beams
055 * @since 1.1.3
056 * @see #loadBeanDefinitions
057 * @see org.springframework.beans.factory.support.DefaultListableBeanFactory
058 * @see org.springframework.web.context.support.AbstractRefreshableWebApplicationContext
059 * @see AbstractXmlApplicationContext
060 * @see ClassPathXmlApplicationContext
061 * @see FileSystemXmlApplicationContext
062 * @see org.springframework.context.annotation.AnnotationConfigApplicationContext
063 */
064public abstract class AbstractRefreshableApplicationContext extends AbstractApplicationContext {
065
066        private Boolean allowBeanDefinitionOverriding;
067
068        private Boolean allowCircularReferences;
069
070        /** Bean factory for this context */
071        private volatile DefaultListableBeanFactory beanFactory;
072
073
074        /**
075         * Create a new AbstractRefreshableApplicationContext with no parent.
076         */
077        public AbstractRefreshableApplicationContext() {
078        }
079
080        /**
081         * Create a new AbstractRefreshableApplicationContext with the given parent context.
082         * @param parent the parent context
083         */
084        public AbstractRefreshableApplicationContext(ApplicationContext parent) {
085                super(parent);
086        }
087
088
089        /**
090         * Set whether it should be allowed to override bean definitions by registering
091         * a different definition with the same name, automatically replacing the former.
092         * If not, an exception will be thrown. Default is "true".
093         * @see org.springframework.beans.factory.support.DefaultListableBeanFactory#setAllowBeanDefinitionOverriding
094         */
095        public void setAllowBeanDefinitionOverriding(boolean allowBeanDefinitionOverriding) {
096                this.allowBeanDefinitionOverriding = allowBeanDefinitionOverriding;
097        }
098
099        /**
100         * Set whether to allow circular references between beans - and automatically
101         * try to resolve them.
102         * <p>Default is "true". Turn this off to throw an exception when encountering
103         * a circular reference, disallowing them completely.
104         * @see org.springframework.beans.factory.support.DefaultListableBeanFactory#setAllowCircularReferences
105         */
106        public void setAllowCircularReferences(boolean allowCircularReferences) {
107                this.allowCircularReferences = allowCircularReferences;
108        }
109
110
111        /**
112         * This implementation performs an actual refresh of this context's underlying
113         * bean factory, shutting down the previous bean factory (if any) and
114         * initializing a fresh bean factory for the next phase of the context's lifecycle.
115         */
116        @Override
117        protected final void refreshBeanFactory() throws BeansException {
118                if (hasBeanFactory()) {
119                        destroyBeans();
120                        closeBeanFactory();
121                }
122                try {
123                        DefaultListableBeanFactory beanFactory = createBeanFactory();
124                        beanFactory.setSerializationId(getId());
125                        customizeBeanFactory(beanFactory);
126                        loadBeanDefinitions(beanFactory);
127                        this.beanFactory = beanFactory;
128                }
129                catch (IOException ex) {
130                        throw new ApplicationContextException("I/O error parsing bean definition source for " + getDisplayName(), ex);
131                }
132        }
133
134        @Override
135        protected void cancelRefresh(BeansException ex) {
136                DefaultListableBeanFactory beanFactory = this.beanFactory;
137                if (beanFactory != null) {
138                        beanFactory.setSerializationId(null);
139                }
140                super.cancelRefresh(ex);
141        }
142
143        @Override
144        protected final void closeBeanFactory() {
145                DefaultListableBeanFactory beanFactory = this.beanFactory;
146                if (beanFactory != null) {
147                        beanFactory.setSerializationId(null);
148                        this.beanFactory = null;
149                }
150        }
151
152        /**
153         * Determine whether this context currently holds a bean factory,
154         * i.e. has been refreshed at least once and not been closed yet.
155         */
156        protected final boolean hasBeanFactory() {
157                return (this.beanFactory != null);
158        }
159
160        @Override
161        public final ConfigurableListableBeanFactory getBeanFactory() {
162                DefaultListableBeanFactory beanFactory = this.beanFactory;
163                if (beanFactory == null) {
164                        throw new IllegalStateException("BeanFactory not initialized or already closed - " +
165                                        "call 'refresh' before accessing beans via the ApplicationContext");
166                }
167                return beanFactory;
168        }
169
170        /**
171         * Overridden to turn it into a no-op: With AbstractRefreshableApplicationContext,
172         * {@link #getBeanFactory()} serves a strong assertion for an active context anyway.
173         */
174        @Override
175        protected void assertBeanFactoryActive() {
176        }
177
178        /**
179         * Create an internal bean factory for this context.
180         * Called for each {@link #refresh()} attempt.
181         * <p>The default implementation creates a
182         * {@link org.springframework.beans.factory.support.DefaultListableBeanFactory}
183         * with the {@linkplain #getInternalParentBeanFactory() internal bean factory} of this
184         * context's parent as parent bean factory. Can be overridden in subclasses,
185         * for example to customize DefaultListableBeanFactory's settings.
186         * @return the bean factory for this context
187         * @see org.springframework.beans.factory.support.DefaultListableBeanFactory#setAllowBeanDefinitionOverriding
188         * @see org.springframework.beans.factory.support.DefaultListableBeanFactory#setAllowEagerClassLoading
189         * @see org.springframework.beans.factory.support.DefaultListableBeanFactory#setAllowCircularReferences
190         * @see org.springframework.beans.factory.support.DefaultListableBeanFactory#setAllowRawInjectionDespiteWrapping
191         */
192        protected DefaultListableBeanFactory createBeanFactory() {
193                return new DefaultListableBeanFactory(getInternalParentBeanFactory());
194        }
195
196        /**
197         * Customize the internal bean factory used by this context.
198         * Called for each {@link #refresh()} attempt.
199         * <p>The default implementation applies this context's
200         * {@linkplain #setAllowBeanDefinitionOverriding "allowBeanDefinitionOverriding"}
201         * and {@linkplain #setAllowCircularReferences "allowCircularReferences"} settings,
202         * if specified. Can be overridden in subclasses to customize any of
203         * {@link DefaultListableBeanFactory}'s settings.
204         * @param beanFactory the newly created bean factory for this context
205         * @see DefaultListableBeanFactory#setAllowBeanDefinitionOverriding
206         * @see DefaultListableBeanFactory#setAllowCircularReferences
207         * @see DefaultListableBeanFactory#setAllowRawInjectionDespiteWrapping
208         * @see DefaultListableBeanFactory#setAllowEagerClassLoading
209         */
210        protected void customizeBeanFactory(DefaultListableBeanFactory beanFactory) {
211                if (this.allowBeanDefinitionOverriding != null) {
212                        beanFactory.setAllowBeanDefinitionOverriding(this.allowBeanDefinitionOverriding);
213                }
214                if (this.allowCircularReferences != null) {
215                        beanFactory.setAllowCircularReferences(this.allowCircularReferences);
216                }
217        }
218
219        /**
220         * Load bean definitions into the given bean factory, typically through
221         * delegating to one or more bean definition readers.
222         * @param beanFactory the bean factory to load bean definitions into
223         * @throws BeansException if parsing of the bean definitions failed
224         * @throws IOException if loading of bean definition files failed
225         * @see org.springframework.beans.factory.support.PropertiesBeanDefinitionReader
226         * @see org.springframework.beans.factory.xml.XmlBeanDefinitionReader
227         */
228        protected abstract void loadBeanDefinitions(DefaultListableBeanFactory beanFactory)
229                        throws BeansException, IOException;
230
231}