spring GenericApplicationContext 源码
spring GenericApplicationContext 代码
文件路径:/spring-context/src/main/java/org/springframework/context/support/GenericApplicationContext.java
/*
* Copyright 2002-2022 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
*
* https://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.BeanDefinitionRegistryPostProcessor;
import org.springframework.beans.factory.support.DefaultListableBeanFactory;
import org.springframework.beans.factory.support.MergedBeanDefinitionPostProcessor;
import org.springframework.beans.factory.support.RootBeanDefinition;
import org.springframework.context.ApplicationContext;
import org.springframework.core.io.ProtocolResolver;
import org.springframework.core.io.Resource;
import org.springframework.core.io.ResourceLoader;
import org.springframework.core.io.support.ResourcePatternResolver;
import org.springframework.core.metrics.ApplicationStartup;
import org.springframework.lang.Nullable;
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.
*
* <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>This ApplicationContext implementation is suitable for Ahead of Time
* processing, using {@link #refreshForAotProcessing()} as an alternative to the
* regular {@link #refresh()}.
*
* <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
* @author Stephane Nicoll
* @author Sam Brannen
* @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 #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(@Nullable 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(@Nullable ApplicationContext parent) {
super.setParent(parent);
this.beanFactory.setParentBeanFactory(getInternalParentBeanFactory());
}
@Override
public void setApplicationStartup(ApplicationStartup applicationStartup) {
super.setApplicationStartup(applicationStartup);
this.beanFactory.setApplicationStartup(applicationStartup);
}
/**
* 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.
* <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 {@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 {@code ResourceLoader} if set,
* falling back to the default superclass behavior otherwise.
* <p>As of Spring Framework 5.3.22, this method also honors registered
* {@linkplain #getProtocolResolvers() protocol resolvers} when a custom
* {@code ResourceLoader} has been set.
* @see #setResourceLoader(ResourceLoader)
* @see #addProtocolResolver(ProtocolResolver)
*/
@Override
public Resource getResource(String location) {
if (this.resourceLoader != null) {
for (ProtocolResolver protocolResolver : getProtocolResolvers()) {
Resource resource = protocolResolver.resolve(location, this);
if (resource != null) {
return resource;
}
}
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 otherwise.
* @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 #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.
*/
@Override
protected final void closeBeanFactory() {
this.beanFactory.setSerializationId(null);
}
/**
* 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.
* <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);
}
//---------------------------------------------------------------------
// AOT processing
//---------------------------------------------------------------------
/**
* Load or refresh the persistent representation of the configuration up to
* a point where the underlying bean factory is ready to create bean
* instances.
* <p>This variant of {@link #refresh()} is used by Ahead of Time (AOT)
* processing that optimizes the application context, typically at build time.
* <p>In this mode, only {@link BeanDefinitionRegistryPostProcessor} and
* {@link MergedBeanDefinitionPostProcessor} are invoked.
* @throws BeansException if the bean factory could not be initialized
* @throws IllegalStateException if already initialized and multiple refresh
* attempts are not supported
* @since 6.0
*/
public void refreshForAotProcessing() {
if (logger.isDebugEnabled()) {
logger.debug("Preparing bean factory for AOT processing");
}
prepareRefresh();
obtainFreshBeanFactory();
prepareBeanFactory(this.beanFactory);
postProcessBeanFactory(this.beanFactory);
invokeBeanFactoryPostProcessors(this.beanFactory);
PostProcessorRegistrationDelegate.invokeMergedBeanDefinitionPostProcessors(this.beanFactory);
}
//---------------------------------------------------------------------
// Convenient methods for registering individual beans
//---------------------------------------------------------------------
/**
* Register a bean from the given bean class, optionally providing explicit
* constructor arguments for consideration in the autowiring process.
* @param beanClass the class of the bean
* @param constructorArgs custom argument values to be fed into Spring's
* constructor resolution algorithm, resolving either all arguments or just
* specific ones, with the rest to be resolved through regular autowiring
* (may be {@code null} or empty)
* @since 5.2 (since 5.0 on the AnnotationConfigApplicationContext subclass)
*/
public <T> void registerBean(Class<T> beanClass, Object... constructorArgs) {
registerBean(null, beanClass, constructorArgs);
}
/**
* Register a bean from the given bean class, optionally providing explicit
* constructor arguments for consideration in the autowiring process.
* @param beanName the name of the bean (may be {@code null})
* @param beanClass the class of the bean
* @param constructorArgs custom argument values to be fed into Spring's
* constructor resolution algorithm, resolving either all arguments or just
* specific ones, with the rest to be resolved through regular autowiring
* (may be {@code null} or empty)
* @since 5.2 (since 5.0 on the AnnotationConfigApplicationContext subclass)
*/
public <T> void registerBean(@Nullable String beanName, Class<T> beanClass, Object... constructorArgs) {
registerBean(beanName, beanClass, (Supplier<T>) null,
bd -> {
for (Object arg : constructorArgs) {
bd.getConstructorArgumentValues().addGenericArgumentValue(arg);
}
});
}
/**
* Register a bean from the given bean class, optionally customizing its
* bean definition metadata (typically declared as a lambda expression).
* @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, optionally customizing its
* bean definition metadata (typically declared as a lambda expression).
* @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).
* @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).
* <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);
}
/**
* {@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);
}
}
}
相关信息
相关文章
spring AbstractApplicationContext 源码
spring AbstractMessageSource 源码
spring AbstractRefreshableApplicationContext 源码
spring AbstractRefreshableConfigApplicationContext 源码
spring AbstractResourceBasedMessageSource 源码
spring AbstractXmlApplicationContext 源码
spring ApplicationContextAwareProcessor 源码
spring ApplicationListenerDetector 源码
0
赞
热门推荐
-
2、 - 优质文章
-
3、 gate.io
-
8、 golang
-
9、 openharmony
-
10、 Vue中input框自动聚焦