001/*
002 * Copyright 2002-2019 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.lang.reflect.Constructor;
021import java.util.concurrent.atomic.AtomicBoolean;
022import java.util.function.Supplier;
023
024import org.springframework.beans.BeanUtils;
025import org.springframework.beans.BeansException;
026import org.springframework.beans.factory.BeanDefinitionStoreException;
027import org.springframework.beans.factory.NoSuchBeanDefinitionException;
028import org.springframework.beans.factory.config.AutowireCapableBeanFactory;
029import org.springframework.beans.factory.config.BeanDefinition;
030import org.springframework.beans.factory.config.BeanDefinitionCustomizer;
031import org.springframework.beans.factory.config.ConfigurableListableBeanFactory;
032import org.springframework.beans.factory.support.BeanDefinitionRegistry;
033import org.springframework.beans.factory.support.DefaultListableBeanFactory;
034import org.springframework.beans.factory.support.RootBeanDefinition;
035import org.springframework.context.ApplicationContext;
036import org.springframework.core.io.Resource;
037import org.springframework.core.io.ResourceLoader;
038import org.springframework.core.io.support.ResourcePatternResolver;
039import org.springframework.lang.Nullable;
040import org.springframework.util.Assert;
041
042/**
043 * Generic ApplicationContext implementation that holds a single internal
044 * {@link org.springframework.beans.factory.support.DefaultListableBeanFactory}
045 * instance and does not assume a specific bean definition format. Implements
046 * the {@link org.springframework.beans.factory.support.BeanDefinitionRegistry}
047 * interface in order to allow for applying any bean definition readers to it.
048 *
049 * <p>Typical usage is to register a variety of bean definitions via the
050 * {@link org.springframework.beans.factory.support.BeanDefinitionRegistry}
051 * interface and then call {@link #refresh()} to initialize those beans
052 * with application context semantics (handling
053 * {@link org.springframework.context.ApplicationContextAware}, auto-detecting
054 * {@link org.springframework.beans.factory.config.BeanFactoryPostProcessor BeanFactoryPostProcessors},
055 * etc).
056 *
057 * <p>In contrast to other ApplicationContext implementations that create a new
058 * internal BeanFactory instance for each refresh, the internal BeanFactory of
059 * this context is available right from the start, to be able to register bean
060 * definitions on it. {@link #refresh()} may only be called once.
061 *
062 * <p>Usage example:
063 *
064 * <pre class="code">
065 * GenericApplicationContext ctx = new GenericApplicationContext();
066 * XmlBeanDefinitionReader xmlReader = new XmlBeanDefinitionReader(ctx);
067 * xmlReader.loadBeanDefinitions(new ClassPathResource("applicationContext.xml"));
068 * PropertiesBeanDefinitionReader propReader = new PropertiesBeanDefinitionReader(ctx);
069 * propReader.loadBeanDefinitions(new ClassPathResource("otherBeans.properties"));
070 * ctx.refresh();
071 *
072 * MyBean myBean = (MyBean) ctx.getBean("myBean");
073 * ...</pre>
074 *
075 * For the typical case of XML bean definitions, simply use
076 * {@link ClassPathXmlApplicationContext} or {@link FileSystemXmlApplicationContext},
077 * which are easier to set up - but less flexible, since you can just use standard
078 * resource locations for XML bean definitions, rather than mixing arbitrary bean
079 * definition formats. The equivalent in a web environment is
080 * {@link org.springframework.web.context.support.XmlWebApplicationContext}.
081 *
082 * <p>For custom application context implementations that are supposed to read
083 * special bean definition formats in a refreshable manner, consider deriving
084 * from the {@link AbstractRefreshableApplicationContext} base class.
085 *
086 * @author Juergen Hoeller
087 * @author Chris Beams
088 * @since 1.1.2
089 * @see #registerBeanDefinition
090 * @see #refresh()
091 * @see org.springframework.beans.factory.xml.XmlBeanDefinitionReader
092 * @see org.springframework.beans.factory.support.PropertiesBeanDefinitionReader
093 */
094public class GenericApplicationContext extends AbstractApplicationContext implements BeanDefinitionRegistry {
095
096        private final DefaultListableBeanFactory beanFactory;
097
098        @Nullable
099        private ResourceLoader resourceLoader;
100
101        private boolean customClassLoader = false;
102
103        private final AtomicBoolean refreshed = new AtomicBoolean();
104
105
106        /**
107         * Create a new GenericApplicationContext.
108         * @see #registerBeanDefinition
109         * @see #refresh
110         */
111        public GenericApplicationContext() {
112                this.beanFactory = new DefaultListableBeanFactory();
113        }
114
115        /**
116         * Create a new GenericApplicationContext with the given DefaultListableBeanFactory.
117         * @param beanFactory the DefaultListableBeanFactory instance to use for this context
118         * @see #registerBeanDefinition
119         * @see #refresh
120         */
121        public GenericApplicationContext(DefaultListableBeanFactory beanFactory) {
122                Assert.notNull(beanFactory, "BeanFactory must not be null");
123                this.beanFactory = beanFactory;
124        }
125
126        /**
127         * Create a new GenericApplicationContext with the given parent.
128         * @param parent the parent application context
129         * @see #registerBeanDefinition
130         * @see #refresh
131         */
132        public GenericApplicationContext(@Nullable ApplicationContext parent) {
133                this();
134                setParent(parent);
135        }
136
137        /**
138         * Create a new GenericApplicationContext with the given DefaultListableBeanFactory.
139         * @param beanFactory the DefaultListableBeanFactory instance to use for this context
140         * @param parent the parent application context
141         * @see #registerBeanDefinition
142         * @see #refresh
143         */
144        public GenericApplicationContext(DefaultListableBeanFactory beanFactory, ApplicationContext parent) {
145                this(beanFactory);
146                setParent(parent);
147        }
148
149
150        /**
151         * Set the parent of this application context, also setting
152         * the parent of the internal BeanFactory accordingly.
153         * @see org.springframework.beans.factory.config.ConfigurableBeanFactory#setParentBeanFactory
154         */
155        @Override
156        public void setParent(@Nullable ApplicationContext parent) {
157                super.setParent(parent);
158                this.beanFactory.setParentBeanFactory(getInternalParentBeanFactory());
159        }
160
161        /**
162         * Set whether it should be allowed to override bean definitions by registering
163         * a different definition with the same name, automatically replacing the former.
164         * If not, an exception will be thrown. Default is "true".
165         * @since 3.0
166         * @see org.springframework.beans.factory.support.DefaultListableBeanFactory#setAllowBeanDefinitionOverriding
167         */
168        public void setAllowBeanDefinitionOverriding(boolean allowBeanDefinitionOverriding) {
169                this.beanFactory.setAllowBeanDefinitionOverriding(allowBeanDefinitionOverriding);
170        }
171
172        /**
173         * Set whether to allow circular references between beans - and automatically
174         * try to resolve them.
175         * <p>Default is "true". Turn this off to throw an exception when encountering
176         * a circular reference, disallowing them completely.
177         * @since 3.0
178         * @see org.springframework.beans.factory.support.DefaultListableBeanFactory#setAllowCircularReferences
179         */
180        public void setAllowCircularReferences(boolean allowCircularReferences) {
181                this.beanFactory.setAllowCircularReferences(allowCircularReferences);
182        }
183
184        /**
185         * Set a ResourceLoader to use for this context. If set, the context will
186         * delegate all {@code getResource} calls to the given ResourceLoader.
187         * If not set, default resource loading will apply.
188         * <p>The main reason to specify a custom ResourceLoader is to resolve
189         * resource paths (without URL prefix) in a specific fashion.
190         * The default behavior is to resolve such paths as class path locations.
191         * To resolve resource paths as file system locations, specify a
192         * FileSystemResourceLoader here.
193         * <p>You can also pass in a full ResourcePatternResolver, which will
194         * be autodetected by the context and used for {@code getResources}
195         * calls as well. Else, default resource pattern matching will apply.
196         * @see #getResource
197         * @see org.springframework.core.io.DefaultResourceLoader
198         * @see org.springframework.core.io.FileSystemResourceLoader
199         * @see org.springframework.core.io.support.ResourcePatternResolver
200         * @see #getResources
201         */
202        public void setResourceLoader(ResourceLoader resourceLoader) {
203                this.resourceLoader = resourceLoader;
204        }
205
206
207        //---------------------------------------------------------------------
208        // ResourceLoader / ResourcePatternResolver override if necessary
209        //---------------------------------------------------------------------
210
211        /**
212         * This implementation delegates to this context's ResourceLoader if set,
213         * falling back to the default superclass behavior else.
214         * @see #setResourceLoader
215         */
216        @Override
217        public Resource getResource(String location) {
218                if (this.resourceLoader != null) {
219                        return this.resourceLoader.getResource(location);
220                }
221                return super.getResource(location);
222        }
223
224        /**
225         * This implementation delegates to this context's ResourceLoader if it
226         * implements the ResourcePatternResolver interface, falling back to the
227         * default superclass behavior else.
228         * @see #setResourceLoader
229         */
230        @Override
231        public Resource[] getResources(String locationPattern) throws IOException {
232                if (this.resourceLoader instanceof ResourcePatternResolver) {
233                        return ((ResourcePatternResolver) this.resourceLoader).getResources(locationPattern);
234                }
235                return super.getResources(locationPattern);
236        }
237
238        @Override
239        public void setClassLoader(@Nullable ClassLoader classLoader) {
240                super.setClassLoader(classLoader);
241                this.customClassLoader = true;
242        }
243
244        @Override
245        @Nullable
246        public ClassLoader getClassLoader() {
247                if (this.resourceLoader != null && !this.customClassLoader) {
248                        return this.resourceLoader.getClassLoader();
249                }
250                return super.getClassLoader();
251        }
252
253
254        //---------------------------------------------------------------------
255        // Implementations of AbstractApplicationContext's template methods
256        //---------------------------------------------------------------------
257
258        /**
259         * Do nothing: We hold a single internal BeanFactory and rely on callers
260         * to register beans through our public methods (or the BeanFactory's).
261         * @see #registerBeanDefinition
262         */
263        @Override
264        protected final void refreshBeanFactory() throws IllegalStateException {
265                if (!this.refreshed.compareAndSet(false, true)) {
266                        throw new IllegalStateException(
267                                        "GenericApplicationContext does not support multiple refresh attempts: just call 'refresh' once");
268                }
269                this.beanFactory.setSerializationId(getId());
270        }
271
272        @Override
273        protected void cancelRefresh(BeansException ex) {
274                this.beanFactory.setSerializationId(null);
275                super.cancelRefresh(ex);
276        }
277
278        /**
279         * Not much to do: We hold a single internal BeanFactory that will never
280         * get released.
281         */
282        @Override
283        protected final void closeBeanFactory() {
284                this.beanFactory.setSerializationId(null);
285        }
286
287        /**
288         * Return the single internal BeanFactory held by this context
289         * (as ConfigurableListableBeanFactory).
290         */
291        @Override
292        public final ConfigurableListableBeanFactory getBeanFactory() {
293                return this.beanFactory;
294        }
295
296        /**
297         * Return the underlying bean factory of this context,
298         * available for registering bean definitions.
299         * <p><b>NOTE:</b> You need to call {@link #refresh()} to initialize the
300         * bean factory and its contained beans with application context semantics
301         * (autodetecting BeanFactoryPostProcessors, etc).
302         * @return the internal bean factory (as DefaultListableBeanFactory)
303         */
304        public final DefaultListableBeanFactory getDefaultListableBeanFactory() {
305                return this.beanFactory;
306        }
307
308        @Override
309        public AutowireCapableBeanFactory getAutowireCapableBeanFactory() throws IllegalStateException {
310                assertBeanFactoryActive();
311                return this.beanFactory;
312        }
313
314
315        //---------------------------------------------------------------------
316        // Implementation of BeanDefinitionRegistry
317        //---------------------------------------------------------------------
318
319        @Override
320        public void registerBeanDefinition(String beanName, BeanDefinition beanDefinition)
321                        throws BeanDefinitionStoreException {
322
323                this.beanFactory.registerBeanDefinition(beanName, beanDefinition);
324        }
325
326        @Override
327        public void removeBeanDefinition(String beanName) throws NoSuchBeanDefinitionException {
328                this.beanFactory.removeBeanDefinition(beanName);
329        }
330
331        @Override
332        public BeanDefinition getBeanDefinition(String beanName) throws NoSuchBeanDefinitionException {
333                return this.beanFactory.getBeanDefinition(beanName);
334        }
335
336        @Override
337        public boolean isBeanNameInUse(String beanName) {
338                return this.beanFactory.isBeanNameInUse(beanName);
339        }
340
341        @Override
342        public void registerAlias(String beanName, String alias) {
343                this.beanFactory.registerAlias(beanName, alias);
344        }
345
346        @Override
347        public void removeAlias(String alias) {
348                this.beanFactory.removeAlias(alias);
349        }
350
351        @Override
352        public boolean isAlias(String beanName) {
353                return this.beanFactory.isAlias(beanName);
354        }
355
356
357        //---------------------------------------------------------------------
358        // Convenient methods for registering individual beans
359        //---------------------------------------------------------------------
360
361        /**
362         * Register a bean from the given bean class, optionally providing explicit
363         * constructor arguments for consideration in the autowiring process.
364         * @param beanClass the class of the bean
365         * @param constructorArgs custom argument values to be fed into Spring's
366         * constructor resolution algorithm, resolving either all arguments or just
367         * specific ones, with the rest to be resolved through regular autowiring
368         * (may be {@code null} or empty)
369         * @since 5.2 (since 5.0 on the AnnotationConfigApplicationContext subclass)
370         */
371        public <T> void registerBean(Class<T> beanClass, Object... constructorArgs) {
372                registerBean(null, beanClass, constructorArgs);
373        }
374
375        /**
376         * Register a bean from the given bean class, optionally providing explicit
377         * constructor arguments for consideration in the autowiring process.
378         * @param beanName the name of the bean (may be {@code null})
379         * @param beanClass the class of the bean
380         * @param constructorArgs custom argument values to be fed into Spring's
381         * constructor resolution algorithm, resolving either all arguments or just
382         * specific ones, with the rest to be resolved through regular autowiring
383         * (may be {@code null} or empty)
384         * @since 5.2 (since 5.0 on the AnnotationConfigApplicationContext subclass)
385         */
386        public <T> void registerBean(@Nullable String beanName, Class<T> beanClass, Object... constructorArgs) {
387                registerBean(beanName, beanClass, (Supplier<T>) null,
388                                bd -> {
389                                        for (Object arg : constructorArgs) {
390                                                bd.getConstructorArgumentValues().addGenericArgumentValue(arg);
391                                        }
392                                });
393        }
394
395        /**
396         * Register a bean from the given bean class, optionally customizing its
397         * bean definition metadata (typically declared as a lambda expression).
398         * @param beanClass the class of the bean (resolving a public constructor
399         * to be autowired, possibly simply the default constructor)
400         * @param customizers one or more callbacks for customizing the factory's
401         * {@link BeanDefinition}, e.g. setting a lazy-init or primary flag
402         * @since 5.0
403         * @see #registerBean(String, Class, Supplier, BeanDefinitionCustomizer...)
404         */
405        public final <T> void registerBean(Class<T> beanClass, BeanDefinitionCustomizer... customizers) {
406                registerBean(null, beanClass, null, customizers);
407        }
408
409        /**
410         * Register a bean from the given bean class, optionally customizing its
411         * bean definition metadata (typically declared as a lambda expression).
412         * @param beanName the name of the bean (may be {@code null})
413         * @param beanClass the class of the bean (resolving a public constructor
414         * to be autowired, possibly simply the default constructor)
415         * @param customizers one or more callbacks for customizing the factory's
416         * {@link BeanDefinition}, e.g. setting a lazy-init or primary flag
417         * @since 5.0
418         * @see #registerBean(String, Class, Supplier, BeanDefinitionCustomizer...)
419         */
420        public final <T> void registerBean(
421                        @Nullable String beanName, Class<T> beanClass, BeanDefinitionCustomizer... customizers) {
422
423                registerBean(beanName, beanClass, null, customizers);
424        }
425
426        /**
427         * Register a bean from the given bean class, using the given supplier for
428         * obtaining a new instance (typically declared as a lambda expression or
429         * method reference), optionally customizing its bean definition metadata
430         * (again typically declared as a lambda expression).
431         * @param beanClass the class of the bean
432         * @param supplier a callback for creating an instance of the bean
433         * @param customizers one or more callbacks for customizing the factory's
434         * {@link BeanDefinition}, e.g. setting a lazy-init or primary flag
435         * @since 5.0
436         * @see #registerBean(String, Class, Supplier, BeanDefinitionCustomizer...)
437         */
438        public final <T> void registerBean(
439                        Class<T> beanClass, Supplier<T> supplier, BeanDefinitionCustomizer... customizers) {
440
441                registerBean(null, beanClass, supplier, customizers);
442        }
443
444        /**
445         * Register a bean from the given bean class, using the given supplier for
446         * obtaining a new instance (typically declared as a lambda expression or
447         * method reference), optionally customizing its bean definition metadata
448         * (again typically declared as a lambda expression).
449         * <p>This method can be overridden to adapt the registration mechanism for
450         * all {@code registerBean} methods (since they all delegate to this one).
451         * @param beanName the name of the bean (may be {@code null})
452         * @param beanClass the class of the bean
453         * @param supplier a callback for creating an instance of the bean (in case
454         * of {@code null}, resolving a public constructor to be autowired instead)
455         * @param customizers one or more callbacks for customizing the factory's
456         * {@link BeanDefinition}, e.g. setting a lazy-init or primary flag
457         * @since 5.0
458         */
459        public <T> void registerBean(@Nullable String beanName, Class<T> beanClass,
460                        @Nullable Supplier<T> supplier, BeanDefinitionCustomizer... customizers) {
461
462                ClassDerivedBeanDefinition beanDefinition = new ClassDerivedBeanDefinition(beanClass);
463                if (supplier != null) {
464                        beanDefinition.setInstanceSupplier(supplier);
465                }
466                for (BeanDefinitionCustomizer customizer : customizers) {
467                        customizer.customize(beanDefinition);
468                }
469
470                String nameToUse = (beanName != null ? beanName : beanClass.getName());
471                registerBeanDefinition(nameToUse, beanDefinition);
472        }
473
474
475        /**
476         * {@link RootBeanDefinition} marker subclass for {@code #registerBean} based
477         * registrations with flexible autowiring for public constructors.
478         */
479        @SuppressWarnings("serial")
480        private static class ClassDerivedBeanDefinition extends RootBeanDefinition {
481
482                public ClassDerivedBeanDefinition(Class<?> beanClass) {
483                        super(beanClass);
484                }
485
486                public ClassDerivedBeanDefinition(ClassDerivedBeanDefinition original) {
487                        super(original);
488                }
489
490                @Override
491                @Nullable
492                public Constructor<?>[] getPreferredConstructors() {
493                        Class<?> clazz = getBeanClass();
494                        Constructor<?> primaryCtor = BeanUtils.findPrimaryConstructor(clazz);
495                        if (primaryCtor != null) {
496                                return new Constructor<?>[] {primaryCtor};
497                        }
498                        Constructor<?>[] publicCtors = clazz.getConstructors();
499                        if (publicCtors.length > 0) {
500                                return publicCtors;
501                        }
502                        return null;
503                }
504
505                @Override
506                public RootBeanDefinition cloneBeanDefinition() {
507                        return new ClassDerivedBeanDefinition(this);
508                }
509        }
510
511}