/* * 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.factory.BeanDefinitionStoreException; import org.springframework.beans.factory.NoSuchBeanDefinitionException; import org.springframework.beans.factory.config.BeanDefinition; import org.springframework.beans.factory.config.ConfigurableListableBeanFactory; import org.springframework.beans.factory.support.BeanDefinitionRegistry; import org.springframework.beans.factory.support.DefaultListableBeanFactory; 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.util.Assert; /** * 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. * *
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). * *
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. * *
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 * {@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}. * *
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
* @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;
private ResourceLoader resourceLoader;
private boolean refreshed = false;
/**
* Create a new GenericApplicationContext.
* @see #registerBeanDefinition
* @see #refresh
*/
public GenericApplicationContext() {
this.beanFactory = new DefaultListableBeanFactory();
}
/**
* 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.
* @param parent the parent application context
* @see #registerBeanDefinition
* @see #refresh
*/
public GenericApplicationContext(ApplicationContext parent) {
this();
setParent(parent);
}
/**
* 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 org.springframework.beans.factory.config.ConfigurableBeanFactory#setParentBeanFactory
*/
@Override
public void setParent(ApplicationContext parent) {
super.setParent(parent);
this.beanFactory.setParentBeanFactory(getInternalParentBeanFactory());
}
/**
* 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 (withour 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 #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;
}
/**
* 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 #setResourceLoader
*/
@Override
public Resource[] getResources(String locationPattern) throws IOException {
if (this.resourceLoader instanceof ResourcePatternResolver) {
return ((ResourcePatternResolver) this.resourceLoader).getResources(locationPattern);
}
return super.getResources(locationPattern);
}
//---------------------------------------------------------------------
// 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 #registerBeanDefinition
*/
@Override
protected final void refreshBeanFactory() throws IllegalStateException {
if (this.refreshed) {
throw new IllegalStateException(
"GenericApplicationContext does not support multiple refresh attempts: just call 'refresh' once");
}
this.refreshed = true;
}
/**
* Do nothing: We hold a single internal BeanFactory that will never
* get released.
*/
@Override
protected final void closeBeanFactory() {
}
/**
* 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 {@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; } //--------------------------------------------------------------------- // Implementation of BeanDefinitionRegistry //--------------------------------------------------------------------- public void registerBeanDefinition(String beanName, BeanDefinition beanDefinition) throws BeanDefinitionStoreException { this.beanFactory.registerBeanDefinition(beanName, beanDefinition); } public void removeBeanDefinition(String beanName) throws NoSuchBeanDefinitionException { this.beanFactory.removeBeanDefinition(beanName); } public BeanDefinition getBeanDefinition(String beanName) throws NoSuchBeanDefinitionException { return this.beanFactory.getBeanDefinition(beanName); } public boolean isBeanNameInUse(String beanName) { return this.beanFactory.isBeanNameInUse(beanName); } public void registerAlias(String beanName, String alias) { this.beanFactory.registerAlias(beanName, alias); } public void removeAlias(String alias) { this.beanFactory.removeAlias(alias); } public boolean isAlias(String beanName) { return this.beanFactory.isAlias(beanName); } }