/*
 * Copyright 2002-2018 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 java.lang.reflect.Constructor;
import java.util.concurrent.atomic.AtomicBoolean;
import java.util.function.Supplier;

import org.springframework.beans.BeanUtils;
import org.springframework.beans.BeansException;
import org.springframework.beans.factory.BeanDefinitionStoreException;
import org.springframework.beans.factory.NoSuchBeanDefinitionException;
import org.springframework.beans.factory.config.AutowireCapableBeanFactory;
import org.springframework.beans.factory.config.BeanDefinition;
import org.springframework.beans.factory.config.BeanDefinitionCustomizer;
import org.springframework.beans.factory.config.ConfigurableListableBeanFactory;
import org.springframework.beans.factory.support.BeanDefinitionRegistry;
import org.springframework.beans.factory.support.DefaultListableBeanFactory;
import org.springframework.beans.factory.support.RootBeanDefinition;
import org.springframework.context.ApplicationContext;
import org.springframework.core.io.Resource;
import org.springframework.core.io.ResourceLoader;
import org.springframework.core.io.support.ResourcePatternResolver;
import org.springframework.lang.Nullable;
import org.springframework.util.Assert;

Generic ApplicationContext implementation that holds a single internal DefaultListableBeanFactory instance and does not assume a specific bean definition format. Implements the BeanDefinitionRegistry interface in order to allow for applying any bean definition readers to it.

Typical usage is to register a variety of bean definitions via the BeanDefinitionRegistry interface and then call AbstractApplicationContext.refresh() to initialize those beans with application context semantics (handling ApplicationContextAware, auto-detecting BeanFactoryPostProcessors, etc).

In contrast to other ApplicationContext implementations that create a new internal BeanFactory instance for each refresh, the internal BeanFactory of this context is available right from the start, to be able to register bean definitions on it. AbstractApplicationContext.refresh() may only be called once.

Usage example:

GenericApplicationContext ctx = new GenericApplicationContext();
XmlBeanDefinitionReader xmlReader = new XmlBeanDefinitionReader(ctx);
xmlReader.loadBeanDefinitions(new ClassPathResource("applicationContext.xml"));
PropertiesBeanDefinitionReader propReader = new PropertiesBeanDefinitionReader(ctx);
propReader.loadBeanDefinitions(new ClassPathResource("otherBeans.properties"));
ctx.refresh();
MyBean myBean = (MyBean) ctx.getBean("myBean");
...
For the typical case of XML bean definitions, simply use ClassPathXmlApplicationContext or FileSystemXmlApplicationContext, which are easier to set up - but less flexible, since you can just use standard resource locations for XML bean definitions, rather than mixing arbitrary bean definition formats. The equivalent in a web environment is XmlWebApplicationContext.

For custom application context implementations that are supposed to read special bean definition formats in a refreshable manner, consider deriving from the AbstractRefreshableApplicationContext base class.

Author:Juergen Hoeller, Chris Beams
See Also:
Since:1.1.2
/** * Generic ApplicationContext implementation that holds a single internal * {@link org.springframework.beans.factory.support.DefaultListableBeanFactory} * instance and does not assume a specific bean definition format. Implements * the {@link org.springframework.beans.factory.support.BeanDefinitionRegistry} * interface in order to allow for applying any bean definition readers to it. * * <p>Typical usage is to register a variety of bean definitions via the * {@link org.springframework.beans.factory.support.BeanDefinitionRegistry} * interface and then call {@link #refresh()} to initialize those beans * with application context semantics (handling * {@link org.springframework.context.ApplicationContextAware}, auto-detecting * {@link org.springframework.beans.factory.config.BeanFactoryPostProcessor BeanFactoryPostProcessors}, * etc). * * <p>In contrast to other ApplicationContext implementations that create a new * internal BeanFactory instance for each refresh, the internal BeanFactory of * this context is available right from the start, to be able to register bean * definitions on it. {@link #refresh()} may only be called once. * * <p>Usage example: * * <pre class="code"> * GenericApplicationContext ctx = new GenericApplicationContext(); * XmlBeanDefinitionReader xmlReader = new XmlBeanDefinitionReader(ctx); * xmlReader.loadBeanDefinitions(new ClassPathResource("applicationContext.xml")); * PropertiesBeanDefinitionReader propReader = new PropertiesBeanDefinitionReader(ctx); * propReader.loadBeanDefinitions(new ClassPathResource("otherBeans.properties")); * ctx.refresh(); * * MyBean myBean = (MyBean) ctx.getBean("myBean"); * ...</pre> * * For the typical case of XML bean definitions, simply use * {@link ClassPathXmlApplicationContext} or {@link FileSystemXmlApplicationContext}, * which are easier to set up - but less flexible, since you can just use standard * resource locations for XML bean definitions, rather than mixing arbitrary bean * definition formats. The equivalent in a web environment is * {@link org.springframework.web.context.support.XmlWebApplicationContext}. * * <p>For custom application context implementations that are supposed to read * special bean definition formats in a refreshable manner, consider deriving * from the {@link AbstractRefreshableApplicationContext} base class. * * @author Juergen Hoeller * @author Chris Beams * @since 1.1.2 * @see #registerBeanDefinition * @see #refresh() * @see org.springframework.beans.factory.xml.XmlBeanDefinitionReader * @see org.springframework.beans.factory.support.PropertiesBeanDefinitionReader */
public class GenericApplicationContext extends AbstractApplicationContext implements BeanDefinitionRegistry { private final DefaultListableBeanFactory beanFactory; @Nullable private ResourceLoader resourceLoader; private boolean customClassLoader = false; private final AtomicBoolean refreshed = new AtomicBoolean();
Create a new GenericApplicationContext.
See Also:
/** * Create a new GenericApplicationContext. * @see #registerBeanDefinition * @see #refresh */
public GenericApplicationContext() { this.beanFactory = new DefaultListableBeanFactory(); }
Create a new GenericApplicationContext with the given DefaultListableBeanFactory.
Params:
  • beanFactory – the DefaultListableBeanFactory instance to use for this context
See Also:
/** * Create a new GenericApplicationContext with the given DefaultListableBeanFactory. * @param beanFactory the DefaultListableBeanFactory instance to use for this context * @see #registerBeanDefinition * @see #refresh */
public GenericApplicationContext(DefaultListableBeanFactory beanFactory) { Assert.notNull(beanFactory, "BeanFactory must not be null"); this.beanFactory = beanFactory; }
Create a new GenericApplicationContext with the given parent.
Params:
  • parent – the parent application context
See Also:
/** * Create a new GenericApplicationContext with the given parent. * @param parent the parent application context * @see #registerBeanDefinition * @see #refresh */
public GenericApplicationContext(@Nullable ApplicationContext parent) { this(); setParent(parent); }
Create a new GenericApplicationContext with the given DefaultListableBeanFactory.
Params:
  • beanFactory – the DefaultListableBeanFactory instance to use for this context
  • parent – the parent application context
See Also:
/** * Create a new GenericApplicationContext with the given DefaultListableBeanFactory. * @param beanFactory the DefaultListableBeanFactory instance to use for this context * @param parent the parent application context * @see #registerBeanDefinition * @see #refresh */
public GenericApplicationContext(DefaultListableBeanFactory beanFactory, ApplicationContext parent) { this(beanFactory); setParent(parent); }
Set the parent of this application context, also setting the parent of the internal BeanFactory accordingly.
See Also:
  • setParentBeanFactory.setParentBeanFactory
/** * Set the parent of this application context, also setting * the parent of the internal BeanFactory accordingly. * @see org.springframework.beans.factory.config.ConfigurableBeanFactory#setParentBeanFactory */
@Override public void setParent(@Nullable ApplicationContext parent) { super.setParent(parent); this.beanFactory.setParentBeanFactory(getInternalParentBeanFactory()); }
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 Also:
Since:3.0
/** * 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". * @since 3.0 * @see org.springframework.beans.factory.support.DefaultListableBeanFactory#setAllowBeanDefinitionOverriding */
public void setAllowBeanDefinitionOverriding(boolean allowBeanDefinitionOverriding) { this.beanFactory.setAllowBeanDefinitionOverriding(allowBeanDefinitionOverriding); }
Set whether to allow circular references between beans - and automatically try to resolve them.

Default is "true". Turn this off to throw an exception when encountering a circular reference, disallowing them completely.

See Also:
Since:3.0
/** * 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. * @since 3.0 * @see org.springframework.beans.factory.support.DefaultListableBeanFactory#setAllowCircularReferences */
public void setAllowCircularReferences(boolean allowCircularReferences) { this.beanFactory.setAllowCircularReferences(allowCircularReferences); }
Set a ResourceLoader to use for this context. If set, the context will delegate all getResource calls to the given ResourceLoader. If not set, default resource loading will apply.

The main reason to specify a custom ResourceLoader is to resolve resource paths (without URL prefix) in a specific fashion. The default behavior is to resolve such paths as class path locations. To resolve resource paths as file system locations, specify a FileSystemResourceLoader here.

You can also pass in a full ResourcePatternResolver, which will be autodetected by the context and used for getResources calls as well. Else, default resource pattern matching will apply.

See Also:
/** * Set a ResourceLoader to use for this context. If set, the context will * delegate all {@code getResource} calls to the given ResourceLoader. * If not set, default resource loading will apply. * <p>The main reason to specify a custom ResourceLoader is to resolve * resource paths (without URL prefix) in a specific fashion. * The default behavior is to resolve such paths as class path locations. * To resolve resource paths as file system locations, specify a * FileSystemResourceLoader here. * <p>You can also pass in a full ResourcePatternResolver, which will * be autodetected by the context and used for {@code getResources} * calls as well. Else, default resource pattern matching will apply. * @see #getResource * @see org.springframework.core.io.DefaultResourceLoader * @see org.springframework.core.io.FileSystemResourceLoader * @see org.springframework.core.io.support.ResourcePatternResolver * @see #getResources */
public void setResourceLoader(ResourceLoader resourceLoader) { this.resourceLoader = resourceLoader; } //--------------------------------------------------------------------- // ResourceLoader / ResourcePatternResolver override if necessary //---------------------------------------------------------------------
This implementation delegates to this context's ResourceLoader if set, falling back to the default superclass behavior else.
See Also:
  • setResourceLoader
/** * This implementation delegates to this context's ResourceLoader if set, * falling back to the default superclass behavior else. * @see #setResourceLoader */
@Override public Resource getResource(String location) { if (this.resourceLoader != null) { return this.resourceLoader.getResource(location); } return super.getResource(location); }
This implementation delegates to this context's ResourceLoader if it implements the ResourcePatternResolver interface, falling back to the default superclass behavior else.
See Also:
  • setResourceLoader
/** * This implementation delegates to this context's ResourceLoader if it * implements the ResourcePatternResolver interface, falling back to the * default superclass behavior else. * @see #setResourceLoader */
@Override public Resource[] getResources(String locationPattern) throws IOException { if (this.resourceLoader instanceof ResourcePatternResolver) { return ((ResourcePatternResolver) this.resourceLoader).getResources(locationPattern); } return super.getResources(locationPattern); } @Override public void setClassLoader(@Nullable ClassLoader classLoader) { super.setClassLoader(classLoader); this.customClassLoader = true; } @Override @Nullable public ClassLoader getClassLoader() { if (this.resourceLoader != null && !this.customClassLoader) { return this.resourceLoader.getClassLoader(); } return super.getClassLoader(); } //--------------------------------------------------------------------- // Implementations of AbstractApplicationContext's template methods //---------------------------------------------------------------------
Do nothing: We hold a single internal BeanFactory and rely on callers to register beans through our public methods (or the BeanFactory's).
See Also:
  • registerBeanDefinition
/** * Do nothing: We hold a single internal BeanFactory and rely on callers * to register beans through our public methods (or the BeanFactory's). * @see #registerBeanDefinition */
@Override protected final void refreshBeanFactory() throws IllegalStateException { if (!this.refreshed.compareAndSet(false, true)) { throw new IllegalStateException( "GenericApplicationContext does not support multiple refresh attempts: just call 'refresh' once"); } this.beanFactory.setSerializationId(getId()); } @Override protected void cancelRefresh(BeansException ex) { this.beanFactory.setSerializationId(null); super.cancelRefresh(ex); }
Not much to do: We hold a single internal BeanFactory that will never get released.
/** * Not much to do: We hold a single internal BeanFactory that will never * get released. */
@Override protected final void closeBeanFactory() { this.beanFactory.setSerializationId(null); }
Return the single internal BeanFactory held by this context (as ConfigurableListableBeanFactory).
/** * Return the single internal BeanFactory held by this context * (as ConfigurableListableBeanFactory). */
@Override public final ConfigurableListableBeanFactory getBeanFactory() { return this.beanFactory; }
Return the underlying bean factory of this context, available for registering bean definitions.

NOTE: You need to call AbstractApplicationContext.refresh() to initialize the bean factory and its contained beans with application context semantics (autodetecting BeanFactoryPostProcessors, etc).

Returns:the internal bean factory (as DefaultListableBeanFactory)
/** * Return the underlying bean factory of this context, * available for registering bean definitions. * <p><b>NOTE:</b> You need to call {@link #refresh()} to initialize the * bean factory and its contained beans with application context semantics * (autodetecting BeanFactoryPostProcessors, etc). * @return the internal bean factory (as DefaultListableBeanFactory) */
public final DefaultListableBeanFactory getDefaultListableBeanFactory() { return this.beanFactory; } @Override public AutowireCapableBeanFactory getAutowireCapableBeanFactory() throws IllegalStateException { assertBeanFactoryActive(); return this.beanFactory; } //--------------------------------------------------------------------- // Implementation of BeanDefinitionRegistry //--------------------------------------------------------------------- @Override public void registerBeanDefinition(String beanName, BeanDefinition beanDefinition) throws BeanDefinitionStoreException { this.beanFactory.registerBeanDefinition(beanName, beanDefinition); } @Override public void removeBeanDefinition(String beanName) throws NoSuchBeanDefinitionException { this.beanFactory.removeBeanDefinition(beanName); } @Override public BeanDefinition getBeanDefinition(String beanName) throws NoSuchBeanDefinitionException { return this.beanFactory.getBeanDefinition(beanName); } @Override public boolean isBeanNameInUse(String beanName) { return this.beanFactory.isBeanNameInUse(beanName); } @Override public void registerAlias(String beanName, String alias) { this.beanFactory.registerAlias(beanName, alias); } @Override public void removeAlias(String alias) { this.beanFactory.removeAlias(alias); } @Override public boolean isAlias(String beanName) { return this.beanFactory.isAlias(beanName); } //--------------------------------------------------------------------- // Convenient methods for registering individual beans //---------------------------------------------------------------------
Register a bean from the given bean class, optionally customizing its bean definition metadata (typically declared as a lambda expression or method reference).
Params:
  • beanClass – the class of the bean (resolving a public constructor to be autowired, possibly simply the default constructor)
  • customizers – one or more callbacks for customizing the factory's BeanDefinition, e.g. setting a lazy-init or primary flag
See Also:
Since:5.0
/** * Register a bean from the given bean class, optionally customizing its * bean definition metadata (typically declared as a lambda expression * or method reference). * @param beanClass the class of the bean (resolving a public constructor * to be autowired, possibly simply the default constructor) * @param customizers one or more callbacks for customizing the factory's * {@link BeanDefinition}, e.g. setting a lazy-init or primary flag * @since 5.0 * @see #registerBean(String, Class, Supplier, BeanDefinitionCustomizer...) */
public final <T> void registerBean(Class<T> beanClass, BeanDefinitionCustomizer... customizers) { registerBean(null, beanClass, null, customizers); }
Register a bean from the given bean class, using the given supplier for obtaining a new instance (typically declared as a lambda expression or method reference), optionally customizing its bean definition metadata (again typically declared as a lambda expression or method reference).
Params:
  • beanName – the name of the bean (may be null)
  • beanClass – the class of the bean (resolving a public constructor to be autowired, possibly simply the default constructor)
  • customizers – one or more callbacks for customizing the factory's BeanDefinition, e.g. setting a lazy-init or primary flag
See Also:
Since:5.0
/** * Register a bean from the given bean class, using the given supplier for * obtaining a new instance (typically declared as a lambda expression or * method reference), optionally customizing its bean definition metadata * (again typically declared as a lambda expression or method reference). * @param beanName the name of the bean (may be {@code null}) * @param beanClass the class of the bean (resolving a public constructor * to be autowired, possibly simply the default constructor) * @param customizers one or more callbacks for customizing the factory's * {@link BeanDefinition}, e.g. setting a lazy-init or primary flag * @since 5.0 * @see #registerBean(String, Class, Supplier, BeanDefinitionCustomizer...) */
public final <T> void registerBean( @Nullable String beanName, Class<T> beanClass, BeanDefinitionCustomizer... customizers) { registerBean(beanName, beanClass, null, customizers); }
Register a bean from the given bean class, using the given supplier for obtaining a new instance (typically declared as a lambda expression or method reference), optionally customizing its bean definition metadata (again typically declared as a lambda expression or method reference).
Params:
  • beanClass – the class of the bean
  • supplier – a callback for creating an instance of the bean
  • customizers – one or more callbacks for customizing the factory's BeanDefinition, e.g. setting a lazy-init or primary flag
See Also:
Since:5.0
/** * Register a bean from the given bean class, using the given supplier for * obtaining a new instance (typically declared as a lambda expression or * method reference), optionally customizing its bean definition metadata * (again typically declared as a lambda expression or method reference). * @param beanClass the class of the bean * @param supplier a callback for creating an instance of the bean * @param customizers one or more callbacks for customizing the factory's * {@link BeanDefinition}, e.g. setting a lazy-init or primary flag * @since 5.0 * @see #registerBean(String, Class, Supplier, BeanDefinitionCustomizer...) */
public final <T> void registerBean( Class<T> beanClass, Supplier<T> supplier, BeanDefinitionCustomizer... customizers) { registerBean(null, beanClass, supplier, customizers); }
Register a bean from the given bean class, using the given supplier for obtaining a new instance (typically declared as a lambda expression or method reference), optionally customizing its bean definition metadata (again typically declared as a lambda expression or method reference).

This method can be overridden to adapt the registration mechanism for all registerBean methods (since they all delegate to this one).

Params:
  • beanName – the name of the bean (may be null)
  • beanClass – the class of the bean
  • supplier – a callback for creating an instance of the bean (in case of null, resolving a public constructor to be autowired instead)
  • customizers – one or more callbacks for customizing the factory's BeanDefinition, e.g. setting a lazy-init or primary flag
Since:5.0
/** * Register a bean from the given bean class, using the given supplier for * obtaining a new instance (typically declared as a lambda expression or * method reference), optionally customizing its bean definition metadata * (again typically declared as a lambda expression or method reference). * <p>This method can be overridden to adapt the registration mechanism for * all {@code registerBean} methods (since they all delegate to this one). * @param beanName the name of the bean (may be {@code null}) * @param beanClass the class of the bean * @param supplier a callback for creating an instance of the bean (in case * of {@code null}, resolving a public constructor to be autowired instead) * @param customizers one or more callbacks for customizing the factory's * {@link BeanDefinition}, e.g. setting a lazy-init or primary flag * @since 5.0 */
public <T> void registerBean(@Nullable String beanName, Class<T> beanClass, @Nullable Supplier<T> supplier, BeanDefinitionCustomizer... customizers) { ClassDerivedBeanDefinition beanDefinition = new ClassDerivedBeanDefinition(beanClass); if (supplier != null) { beanDefinition.setInstanceSupplier(supplier); } for (BeanDefinitionCustomizer customizer : customizers) { customizer.customize(beanDefinition); } String nameToUse = (beanName != null ? beanName : beanClass.getName()); registerBeanDefinition(nameToUse, beanDefinition); }
RootBeanDefinition marker subclass for #registerBean based registrations with flexible autowiring for public constructors.
/** * {@link RootBeanDefinition} marker subclass for {@code #registerBean} based * registrations with flexible autowiring for public constructors. */
@SuppressWarnings("serial") private static class ClassDerivedBeanDefinition extends RootBeanDefinition { public ClassDerivedBeanDefinition(Class<?> beanClass) { super(beanClass); } public ClassDerivedBeanDefinition(ClassDerivedBeanDefinition original) { super(original); } @Override @Nullable public Constructor<?>[] getPreferredConstructors() { Class<?> clazz = getBeanClass(); Constructor<?> primaryCtor = BeanUtils.findPrimaryConstructor(clazz); if (primaryCtor != null) { return new Constructor<?>[] {primaryCtor}; } Constructor<?>[] publicCtors = clazz.getConstructors(); if (publicCtors.length > 0) { return publicCtors; } return null; } @Override public RootBeanDefinition cloneBeanDefinition() { return new ClassDerivedBeanDefinition(this); } } }