001/*
002 * Copyright 2002-2016 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;
020import java.util.concurrent.atomic.AtomicBoolean;
021
022import org.springframework.beans.BeansException;
023import org.springframework.beans.factory.BeanDefinitionStoreException;
024import org.springframework.beans.factory.NoSuchBeanDefinitionException;
025import org.springframework.beans.factory.config.AutowireCapableBeanFactory;
026import org.springframework.beans.factory.config.BeanDefinition;
027import org.springframework.beans.factory.config.ConfigurableListableBeanFactory;
028import org.springframework.beans.factory.support.BeanDefinitionRegistry;
029import org.springframework.beans.factory.support.DefaultListableBeanFactory;
030import org.springframework.context.ApplicationContext;
031import org.springframework.core.io.Resource;
032import org.springframework.core.io.ResourceLoader;
033import org.springframework.core.io.support.ResourcePatternResolver;
034import org.springframework.util.Assert;
035
036/**
037 * Generic ApplicationContext implementation that holds a single internal
038 * {@link org.springframework.beans.factory.support.DefaultListableBeanFactory}
039 * instance and does not assume a specific bean definition format. Implements
040 * the {@link org.springframework.beans.factory.support.BeanDefinitionRegistry}
041 * interface in order to allow for applying any bean definition readers to it.
042 *
043 * <p>Typical usage is to register a variety of bean definitions via the
044 * {@link org.springframework.beans.factory.support.BeanDefinitionRegistry}
045 * interface and then call {@link #refresh()} to initialize those beans
046 * with application context semantics (handling
047 * {@link org.springframework.context.ApplicationContextAware}, auto-detecting
048 * {@link org.springframework.beans.factory.config.BeanFactoryPostProcessor BeanFactoryPostProcessors},
049 * etc).
050 *
051 * <p>In contrast to other ApplicationContext implementations that create a new
052 * internal BeanFactory instance for each refresh, the internal BeanFactory of
053 * this context is available right from the start, to be able to register bean
054 * definitions on it. {@link #refresh()} may only be called once.
055 *
056 * <p>Usage example:
057 *
058 * <pre class="code">
059 * GenericApplicationContext ctx = new GenericApplicationContext();
060 * XmlBeanDefinitionReader xmlReader = new XmlBeanDefinitionReader(ctx);
061 * xmlReader.loadBeanDefinitions(new ClassPathResource("applicationContext.xml"));
062 * PropertiesBeanDefinitionReader propReader = new PropertiesBeanDefinitionReader(ctx);
063 * propReader.loadBeanDefinitions(new ClassPathResource("otherBeans.properties"));
064 * ctx.refresh();
065 *
066 * MyBean myBean = (MyBean) ctx.getBean("myBean");
067 * ...</pre>
068 *
069 * For the typical case of XML bean definitions, simply use
070 * {@link ClassPathXmlApplicationContext} or {@link FileSystemXmlApplicationContext},
071 * which are easier to set up - but less flexible, since you can just use standard
072 * resource locations for XML bean definitions, rather than mixing arbitrary bean
073 * definition formats. The equivalent in a web environment is
074 * {@link org.springframework.web.context.support.XmlWebApplicationContext}.
075 *
076 * <p>For custom application context implementations that are supposed to read
077 * special bean definition formats in a refreshable manner, consider deriving
078 * from the {@link AbstractRefreshableApplicationContext} base class.
079 *
080 * @author Juergen Hoeller
081 * @author Chris Beams
082 * @since 1.1.2
083 * @see #registerBeanDefinition
084 * @see #refresh()
085 * @see org.springframework.beans.factory.xml.XmlBeanDefinitionReader
086 * @see org.springframework.beans.factory.support.PropertiesBeanDefinitionReader
087 */
088public class GenericApplicationContext extends AbstractApplicationContext implements BeanDefinitionRegistry {
089
090        private final DefaultListableBeanFactory beanFactory;
091
092        private ResourceLoader resourceLoader;
093
094        private boolean customClassLoader = false;
095
096        private final AtomicBoolean refreshed = new AtomicBoolean();
097
098
099        /**
100         * Create a new GenericApplicationContext.
101         * @see #registerBeanDefinition
102         * @see #refresh
103         */
104        public GenericApplicationContext() {
105                this.beanFactory = new DefaultListableBeanFactory();
106        }
107
108        /**
109         * Create a new GenericApplicationContext with the given DefaultListableBeanFactory.
110         * @param beanFactory the DefaultListableBeanFactory instance to use for this context
111         * @see #registerBeanDefinition
112         * @see #refresh
113         */
114        public GenericApplicationContext(DefaultListableBeanFactory beanFactory) {
115                Assert.notNull(beanFactory, "BeanFactory must not be null");
116                this.beanFactory = beanFactory;
117        }
118
119        /**
120         * Create a new GenericApplicationContext with the given parent.
121         * @param parent the parent application context
122         * @see #registerBeanDefinition
123         * @see #refresh
124         */
125        public GenericApplicationContext(ApplicationContext parent) {
126                this();
127                setParent(parent);
128        }
129
130        /**
131         * Create a new GenericApplicationContext with the given DefaultListableBeanFactory.
132         * @param beanFactory the DefaultListableBeanFactory instance to use for this context
133         * @param parent the parent application context
134         * @see #registerBeanDefinition
135         * @see #refresh
136         */
137        public GenericApplicationContext(DefaultListableBeanFactory beanFactory, ApplicationContext parent) {
138                this(beanFactory);
139                setParent(parent);
140        }
141
142
143        /**
144         * Set the parent of this application context, also setting
145         * the parent of the internal BeanFactory accordingly.
146         * @see org.springframework.beans.factory.config.ConfigurableBeanFactory#setParentBeanFactory
147         */
148        @Override
149        public void setParent(ApplicationContext parent) {
150                super.setParent(parent);
151                this.beanFactory.setParentBeanFactory(getInternalParentBeanFactory());
152        }
153
154        /**
155         * Set whether it should be allowed to override bean definitions by registering
156         * a different definition with the same name, automatically replacing the former.
157         * If not, an exception will be thrown. Default is "true".
158         * @since 3.0
159         * @see org.springframework.beans.factory.support.DefaultListableBeanFactory#setAllowBeanDefinitionOverriding
160         */
161        public void setAllowBeanDefinitionOverriding(boolean allowBeanDefinitionOverriding) {
162                this.beanFactory.setAllowBeanDefinitionOverriding(allowBeanDefinitionOverriding);
163        }
164
165        /**
166         * Set whether to allow circular references between beans - and automatically
167         * try to resolve them.
168         * <p>Default is "true". Turn this off to throw an exception when encountering
169         * a circular reference, disallowing them completely.
170         * @since 3.0
171         * @see org.springframework.beans.factory.support.DefaultListableBeanFactory#setAllowCircularReferences
172         */
173        public void setAllowCircularReferences(boolean allowCircularReferences) {
174                this.beanFactory.setAllowCircularReferences(allowCircularReferences);
175        }
176
177        /**
178         * Set a ResourceLoader to use for this context. If set, the context will
179         * delegate all {@code getResource} calls to the given ResourceLoader.
180         * If not set, default resource loading will apply.
181         * <p>The main reason to specify a custom ResourceLoader is to resolve
182         * resource paths (without URL prefix) in a specific fashion.
183         * The default behavior is to resolve such paths as class path locations.
184         * To resolve resource paths as file system locations, specify a
185         * FileSystemResourceLoader here.
186         * <p>You can also pass in a full ResourcePatternResolver, which will
187         * be autodetected by the context and used for {@code getResources}
188         * calls as well. Else, default resource pattern matching will apply.
189         * @see #getResource
190         * @see org.springframework.core.io.DefaultResourceLoader
191         * @see org.springframework.core.io.FileSystemResourceLoader
192         * @see org.springframework.core.io.support.ResourcePatternResolver
193         * @see #getResources
194         */
195        public void setResourceLoader(ResourceLoader resourceLoader) {
196                this.resourceLoader = resourceLoader;
197        }
198
199
200        //---------------------------------------------------------------------
201        // ResourceLoader / ResourcePatternResolver override if necessary
202        //---------------------------------------------------------------------
203
204        /**
205         * This implementation delegates to this context's ResourceLoader if set,
206         * falling back to the default superclass behavior else.
207         * @see #setResourceLoader
208         */
209        @Override
210        public Resource getResource(String location) {
211                if (this.resourceLoader != null) {
212                        return this.resourceLoader.getResource(location);
213                }
214                return super.getResource(location);
215        }
216
217        /**
218         * This implementation delegates to this context's ResourceLoader if it
219         * implements the ResourcePatternResolver interface, falling back to the
220         * default superclass behavior else.
221         * @see #setResourceLoader
222         */
223        @Override
224        public Resource[] getResources(String locationPattern) throws IOException {
225                if (this.resourceLoader instanceof ResourcePatternResolver) {
226                        return ((ResourcePatternResolver) this.resourceLoader).getResources(locationPattern);
227                }
228                return super.getResources(locationPattern);
229        }
230
231        @Override
232        public void setClassLoader(ClassLoader classLoader) {
233                super.setClassLoader(classLoader);
234                this.customClassLoader = true;
235        }
236
237        @Override
238        public ClassLoader getClassLoader() {
239                if (this.resourceLoader != null && !this.customClassLoader) {
240                        return this.resourceLoader.getClassLoader();
241                }
242                return super.getClassLoader();
243        }
244
245
246        //---------------------------------------------------------------------
247        // Implementations of AbstractApplicationContext's template methods
248        //---------------------------------------------------------------------
249
250        /**
251         * Do nothing: We hold a single internal BeanFactory and rely on callers
252         * to register beans through our public methods (or the BeanFactory's).
253         * @see #registerBeanDefinition
254         */
255        @Override
256        protected final void refreshBeanFactory() throws IllegalStateException {
257                if (!this.refreshed.compareAndSet(false, true)) {
258                        throw new IllegalStateException(
259                                        "GenericApplicationContext does not support multiple refresh attempts: just call 'refresh' once");
260                }
261                this.beanFactory.setSerializationId(getId());
262        }
263
264        @Override
265        protected void cancelRefresh(BeansException ex) {
266                this.beanFactory.setSerializationId(null);
267                super.cancelRefresh(ex);
268        }
269
270        /**
271         * Not much to do: We hold a single internal BeanFactory that will never
272         * get released.
273         */
274        @Override
275        protected final void closeBeanFactory() {
276                this.beanFactory.setSerializationId(null);
277        }
278
279        /**
280         * Return the single internal BeanFactory held by this context
281         * (as ConfigurableListableBeanFactory).
282         */
283        @Override
284        public final ConfigurableListableBeanFactory getBeanFactory() {
285                return this.beanFactory;
286        }
287
288        /**
289         * Return the underlying bean factory of this context,
290         * available for registering bean definitions.
291         * <p><b>NOTE:</b> You need to call {@link #refresh()} to initialize the
292         * bean factory and its contained beans with application context semantics
293         * (autodetecting BeanFactoryPostProcessors, etc).
294         * @return the internal bean factory (as DefaultListableBeanFactory)
295         */
296        public final DefaultListableBeanFactory getDefaultListableBeanFactory() {
297                return this.beanFactory;
298        }
299
300        @Override
301        public AutowireCapableBeanFactory getAutowireCapableBeanFactory() throws IllegalStateException {
302                assertBeanFactoryActive();
303                return this.beanFactory;
304        }
305
306
307        //---------------------------------------------------------------------
308        // Implementation of BeanDefinitionRegistry
309        //---------------------------------------------------------------------
310
311        @Override
312        public void registerBeanDefinition(String beanName, BeanDefinition beanDefinition)
313                        throws BeanDefinitionStoreException {
314
315                this.beanFactory.registerBeanDefinition(beanName, beanDefinition);
316        }
317
318        @Override
319        public void removeBeanDefinition(String beanName) throws NoSuchBeanDefinitionException {
320                this.beanFactory.removeBeanDefinition(beanName);
321        }
322
323        @Override
324        public BeanDefinition getBeanDefinition(String beanName) throws NoSuchBeanDefinitionException {
325                return this.beanFactory.getBeanDefinition(beanName);
326        }
327
328        @Override
329        public boolean isBeanNameInUse(String beanName) {
330                return this.beanFactory.isBeanNameInUse(beanName);
331        }
332
333        @Override
334        public void registerAlias(String beanName, String alias) {
335                this.beanFactory.registerAlias(beanName, alias);
336        }
337
338        @Override
339        public void removeAlias(String alias) {
340                this.beanFactory.removeAlias(alias);
341        }
342
343        @Override
344        public boolean isAlias(String beanName) {
345                return this.beanFactory.isAlias(beanName);
346        }
347
348}