All Downloads are FREE. Search and download functionalities are using the official Maven repository.

org.springframework.context.support.AbstractApplicationContext Maven / Gradle / Ivy

/*
 * 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.annotation.Annotation;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Date;
import java.util.LinkedHashSet;
import java.util.List;
import java.util.Locale;
import java.util.Map;
import java.util.Set;
import java.util.concurrent.atomic.AtomicBoolean;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;

import org.springframework.beans.BeansException;
import org.springframework.beans.CachedIntrospectionResults;
import org.springframework.beans.factory.BeanFactory;
import org.springframework.beans.factory.NoSuchBeanDefinitionException;
import org.springframework.beans.factory.ObjectProvider;
import org.springframework.beans.factory.config.AutowireCapableBeanFactory;
import org.springframework.beans.factory.config.BeanFactoryPostProcessor;
import org.springframework.beans.factory.config.ConfigurableListableBeanFactory;
import org.springframework.beans.support.ResourceEditorRegistrar;
import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationContextAware;
import org.springframework.context.ApplicationEvent;
import org.springframework.context.ApplicationEventPublisher;
import org.springframework.context.ApplicationEventPublisherAware;
import org.springframework.context.ApplicationListener;
import org.springframework.context.ApplicationStartupAware;
import org.springframework.context.ConfigurableApplicationContext;
import org.springframework.context.EmbeddedValueResolverAware;
import org.springframework.context.EnvironmentAware;
import org.springframework.context.HierarchicalMessageSource;
import org.springframework.context.LifecycleProcessor;
import org.springframework.context.MessageSource;
import org.springframework.context.MessageSourceAware;
import org.springframework.context.MessageSourceResolvable;
import org.springframework.context.NoSuchMessageException;
import org.springframework.context.PayloadApplicationEvent;
import org.springframework.context.ResourceLoaderAware;
import org.springframework.context.event.ApplicationEventMulticaster;
import org.springframework.context.event.ContextClosedEvent;
import org.springframework.context.event.ContextRefreshedEvent;
import org.springframework.context.event.ContextStartedEvent;
import org.springframework.context.event.ContextStoppedEvent;
import org.springframework.context.event.SimpleApplicationEventMulticaster;
import org.springframework.context.expression.StandardBeanExpressionResolver;
import org.springframework.context.weaving.LoadTimeWeaverAware;
import org.springframework.context.weaving.LoadTimeWeaverAwareProcessor;
import org.springframework.core.NativeDetector;
import org.springframework.core.ResolvableType;
import org.springframework.core.annotation.AnnotationUtils;
import org.springframework.core.convert.ConversionService;
import org.springframework.core.env.ConfigurableEnvironment;
import org.springframework.core.env.Environment;
import org.springframework.core.env.StandardEnvironment;
import org.springframework.core.io.DefaultResourceLoader;
import org.springframework.core.io.Resource;
import org.springframework.core.io.ResourceLoader;
import org.springframework.core.io.support.PathMatchingResourcePatternResolver;
import org.springframework.core.io.support.ResourcePatternResolver;
import org.springframework.core.metrics.ApplicationStartup;
import org.springframework.core.metrics.StartupStep;
import org.springframework.lang.Nullable;
import org.springframework.util.Assert;
import org.springframework.util.CollectionUtils;
import org.springframework.util.ObjectUtils;
import org.springframework.util.ReflectionUtils;

/**
 * Abstract implementation of the {@link org.springframework.context.ApplicationContext}
 * interface. Doesn't mandate the type of storage used for configuration; simply
 * implements common context functionality. Uses the Template Method design pattern,
 * requiring concrete subclasses to implement abstract methods.
 *
 * 

In contrast to a plain BeanFactory, an ApplicationContext is supposed * to detect special beans defined in its internal bean factory: * Therefore, this class automatically registers * {@link org.springframework.beans.factory.config.BeanFactoryPostProcessor BeanFactoryPostProcessors}, * {@link org.springframework.beans.factory.config.BeanPostProcessor BeanPostProcessors}, * and {@link org.springframework.context.ApplicationListener ApplicationListeners} * which are defined as beans in the context. * *

A {@link org.springframework.context.MessageSource} may also be supplied * as a bean in the context, with the name "messageSource"; otherwise, message * resolution is delegated to the parent context. Furthermore, a multicaster * for application events can be supplied as an "applicationEventMulticaster" bean * of type {@link org.springframework.context.event.ApplicationEventMulticaster} * in the context; otherwise, a default multicaster of type * {@link org.springframework.context.event.SimpleApplicationEventMulticaster} will be used. * *

Implements resource loading by extending * {@link org.springframework.core.io.DefaultResourceLoader}. * Consequently treats non-URL resource paths as class path resources * (supporting full class path resource names that include the package path, * e.g. "mypackage/myresource.dat"), unless the {@link #getResourceByPath} * method is overridden in a subclass. * * @author Rod Johnson * @author Juergen Hoeller * @author Mark Fisher * @author Stephane Nicoll * @author Sam Brannen * @author Sebastien Deleuze * @author Brian Clozel * @since January 21, 2001 * @see #refreshBeanFactory * @see #getBeanFactory * @see org.springframework.beans.factory.config.BeanFactoryPostProcessor * @see org.springframework.beans.factory.config.BeanPostProcessor * @see org.springframework.context.event.ApplicationEventMulticaster * @see org.springframework.context.ApplicationListener * @see org.springframework.context.MessageSource */ public abstract class AbstractApplicationContext extends DefaultResourceLoader implements ConfigurableApplicationContext { /** * Name of the MessageSource bean in the factory. * If none is supplied, message resolution is delegated to the parent. * @see MessageSource */ public static final String MESSAGE_SOURCE_BEAN_NAME = "messageSource"; /** * Name of the LifecycleProcessor bean in the factory. * If none is supplied, a DefaultLifecycleProcessor is used. * @see org.springframework.context.LifecycleProcessor * @see org.springframework.context.support.DefaultLifecycleProcessor */ public static final String LIFECYCLE_PROCESSOR_BEAN_NAME = "lifecycleProcessor"; /** * Name of the ApplicationEventMulticaster bean in the factory. * If none is supplied, a default SimpleApplicationEventMulticaster is used. * @see org.springframework.context.event.ApplicationEventMulticaster * @see org.springframework.context.event.SimpleApplicationEventMulticaster */ public static final String APPLICATION_EVENT_MULTICASTER_BEAN_NAME = "applicationEventMulticaster"; static { // Eagerly load the ContextClosedEvent class to avoid weird classloader issues // on application shutdown in WebLogic 8.1. (Reported by Dustin Woods.) ContextClosedEvent.class.getName(); } /** Logger used by this class. Available to subclasses. */ protected final Log logger = LogFactory.getLog(getClass()); /** Unique id for this context, if any. */ private String id = ObjectUtils.identityToString(this); /** Display name. */ private String displayName = ObjectUtils.identityToString(this); /** Parent context. */ @Nullable private ApplicationContext parent; /** Environment used by this context. */ @Nullable private ConfigurableEnvironment environment; /** BeanFactoryPostProcessors to apply on refresh. */ private final List beanFactoryPostProcessors = new ArrayList<>(); /** System time in milliseconds when this context started. */ private long startupDate; /** Flag that indicates whether this context is currently active. */ private final AtomicBoolean active = new AtomicBoolean(); /** Flag that indicates whether this context has been closed already. */ private final AtomicBoolean closed = new AtomicBoolean(); /** Synchronization monitor for the "refresh" and "destroy". */ private final Object startupShutdownMonitor = new Object(); /** Reference to the JVM shutdown hook, if registered. */ @Nullable private Thread shutdownHook; /** ResourcePatternResolver used by this context. */ private final ResourcePatternResolver resourcePatternResolver; /** LifecycleProcessor for managing the lifecycle of beans within this context. */ @Nullable private LifecycleProcessor lifecycleProcessor; /** MessageSource we delegate our implementation of this interface to. */ @Nullable private MessageSource messageSource; /** Helper class used in event publishing. */ @Nullable private ApplicationEventMulticaster applicationEventMulticaster; /** Application startup metrics. **/ private ApplicationStartup applicationStartup = ApplicationStartup.DEFAULT; /** Statically specified listeners. */ private final Set> applicationListeners = new LinkedHashSet<>(); /** Local listeners registered before refresh. */ @Nullable private Set> earlyApplicationListeners; /** ApplicationEvents published before the multicaster setup. */ @Nullable private Set earlyApplicationEvents; /** * Create a new AbstractApplicationContext with no parent. */ public AbstractApplicationContext() { this.resourcePatternResolver = getResourcePatternResolver(); } /** * Create a new AbstractApplicationContext with the given parent context. * @param parent the parent context */ public AbstractApplicationContext(@Nullable ApplicationContext parent) { this(); setParent(parent); } //--------------------------------------------------------------------- // Implementation of ApplicationContext interface //--------------------------------------------------------------------- /** * Set the unique id of this application context. *

Default is the object id of the context instance, or the name * of the context bean if the context is itself defined as a bean. * @param id the unique id of the context */ @Override public void setId(String id) { this.id = id; } @Override public String getId() { return this.id; } @Override public String getApplicationName() { return ""; } /** * Set a friendly name for this context. * Typically done during initialization of concrete context implementations. *

Default is the object id of the context instance. */ public void setDisplayName(String displayName) { Assert.hasLength(displayName, "Display name must not be empty"); this.displayName = displayName; } /** * Return a friendly name for this context. * @return a display name for this context (never {@code null}) */ @Override public String getDisplayName() { return this.displayName; } /** * Return the parent context, or {@code null} if there is no parent * (that is, this context is the root of the context hierarchy). */ @Override @Nullable public ApplicationContext getParent() { return this.parent; } /** * Set the {@code Environment} for this application context. *

Default value is determined by {@link #createEnvironment()}. Replacing the * default with this method is one option but configuration through {@link * #getEnvironment()} should also be considered. In either case, such modifications * should be performed before {@link #refresh()}. * @see org.springframework.context.support.AbstractApplicationContext#createEnvironment */ @Override public void setEnvironment(ConfigurableEnvironment environment) { this.environment = environment; } /** * Return the {@code Environment} for this application context in configurable * form, allowing for further customization. *

If none specified, a default environment will be initialized via * {@link #createEnvironment()}. */ @Override public ConfigurableEnvironment getEnvironment() { if (this.environment == null) { this.environment = createEnvironment(); } return this.environment; } /** * Create and return a new {@link StandardEnvironment}. *

Subclasses may override this method in order to supply * a custom {@link ConfigurableEnvironment} implementation. */ protected ConfigurableEnvironment createEnvironment() { return new StandardEnvironment(); } /** * Return this context's internal bean factory as AutowireCapableBeanFactory, * if already available. * @see #getBeanFactory() */ @Override public AutowireCapableBeanFactory getAutowireCapableBeanFactory() throws IllegalStateException { return getBeanFactory(); } /** * Return the timestamp (ms) when this context was first loaded. */ @Override public long getStartupDate() { return this.startupDate; } /** * Publish the given event to all listeners. *

Note: Listeners get initialized after the MessageSource, to be able * to access it within listener implementations. Thus, MessageSource * implementations cannot publish events. * @param event the event to publish (may be application-specific or a * standard framework event) */ @Override public void publishEvent(ApplicationEvent event) { publishEvent(event, null); } /** * Publish the given event to all listeners. *

Note: Listeners get initialized after the MessageSource, to be able * to access it within listener implementations. Thus, MessageSource * implementations cannot publish events. * @param event the event to publish (may be an {@link ApplicationEvent} * or a payload object to be turned into a {@link PayloadApplicationEvent}) */ @Override public void publishEvent(Object event) { publishEvent(event, null); } /** * Publish the given event to all listeners. * @param event the event to publish (may be an {@link ApplicationEvent} * or a payload object to be turned into a {@link PayloadApplicationEvent}) * @param eventType the resolved event type, if known * @since 4.2 */ protected void publishEvent(Object event, @Nullable ResolvableType eventType) { Assert.notNull(event, "Event must not be null"); // Decorate event as an ApplicationEvent if necessary ApplicationEvent applicationEvent; if (event instanceof ApplicationEvent applEvent) { applicationEvent = applEvent; } else { applicationEvent = new PayloadApplicationEvent<>(this, event, eventType); if (eventType == null) { eventType = ((PayloadApplicationEvent) applicationEvent).getResolvableType(); } } // Multicast right now if possible - or lazily once the multicaster is initialized if (this.earlyApplicationEvents != null) { this.earlyApplicationEvents.add(applicationEvent); } else { getApplicationEventMulticaster().multicastEvent(applicationEvent, eventType); } // Publish event via parent context as well... if (this.parent != null) { if (this.parent instanceof AbstractApplicationContext abstractApplicationContext) { abstractApplicationContext.publishEvent(event, eventType); } else { this.parent.publishEvent(event); } } } /** * Return the internal ApplicationEventMulticaster used by the context. * @return the internal ApplicationEventMulticaster (never {@code null}) * @throws IllegalStateException if the context has not been initialized yet */ ApplicationEventMulticaster getApplicationEventMulticaster() throws IllegalStateException { if (this.applicationEventMulticaster == null) { throw new IllegalStateException("ApplicationEventMulticaster not initialized - " + "call 'refresh' before multicasting events via the context: " + this); } return this.applicationEventMulticaster; } @Override public void setApplicationStartup(ApplicationStartup applicationStartup) { Assert.notNull(applicationStartup, "applicationStartup must not be null"); this.applicationStartup = applicationStartup; } @Override public ApplicationStartup getApplicationStartup() { return this.applicationStartup; } /** * Return the internal LifecycleProcessor used by the context. * @return the internal LifecycleProcessor (never {@code null}) * @throws IllegalStateException if the context has not been initialized yet */ LifecycleProcessor getLifecycleProcessor() throws IllegalStateException { if (this.lifecycleProcessor == null) { throw new IllegalStateException("LifecycleProcessor not initialized - " + "call 'refresh' before invoking lifecycle methods via the context: " + this); } return this.lifecycleProcessor; } /** * Return the ResourcePatternResolver to use for resolving location patterns * into Resource instances. Default is a * {@link org.springframework.core.io.support.PathMatchingResourcePatternResolver}, * supporting Ant-style location patterns. *

Can be overridden in subclasses, for extended resolution strategies, * for example in a web environment. *

Do not call this when needing to resolve a location pattern. * Call the context's {@code getResources} method instead, which * will delegate to the ResourcePatternResolver. * @return the ResourcePatternResolver for this context * @see #getResources * @see org.springframework.core.io.support.PathMatchingResourcePatternResolver */ protected ResourcePatternResolver getResourcePatternResolver() { return new PathMatchingResourcePatternResolver(this); } //--------------------------------------------------------------------- // Implementation of ConfigurableApplicationContext interface //--------------------------------------------------------------------- /** * Set the parent of this application context. *

The parent {@linkplain ApplicationContext#getEnvironment() environment} is * {@linkplain ConfigurableEnvironment#merge(ConfigurableEnvironment) merged} with * this (child) application context environment if the parent is non-{@code null} and * its environment is an instance of {@link ConfigurableEnvironment}. * @see ConfigurableEnvironment#merge(ConfigurableEnvironment) */ @Override public void setParent(@Nullable ApplicationContext parent) { this.parent = parent; if (parent != null) { Environment parentEnvironment = parent.getEnvironment(); if (parentEnvironment instanceof ConfigurableEnvironment configurableEnvironment) { getEnvironment().merge(configurableEnvironment); } } } @Override public void addBeanFactoryPostProcessor(BeanFactoryPostProcessor postProcessor) { Assert.notNull(postProcessor, "BeanFactoryPostProcessor must not be null"); this.beanFactoryPostProcessors.add(postProcessor); } /** * Return the list of BeanFactoryPostProcessors that will get applied * to the internal BeanFactory. */ public List getBeanFactoryPostProcessors() { return this.beanFactoryPostProcessors; } @Override public void addApplicationListener(ApplicationListener listener) { Assert.notNull(listener, "ApplicationListener must not be null"); if (this.applicationEventMulticaster != null) { this.applicationEventMulticaster.addApplicationListener(listener); } this.applicationListeners.add(listener); } @Override public void removeApplicationListener(ApplicationListener listener) { Assert.notNull(listener, "ApplicationListener must not be null"); if (this.applicationEventMulticaster != null) { this.applicationEventMulticaster.removeApplicationListener(listener); } this.applicationListeners.remove(listener); } /** * Return the list of statically specified ApplicationListeners. */ public Collection> getApplicationListeners() { return this.applicationListeners; } @Override public void refresh() throws BeansException, IllegalStateException { synchronized (this.startupShutdownMonitor) { StartupStep contextRefresh = this.applicationStartup.start("spring.context.refresh"); // Prepare this context for refreshing. prepareRefresh(); // Tell the subclass to refresh the internal bean factory. ConfigurableListableBeanFactory beanFactory = obtainFreshBeanFactory(); // Prepare the bean factory for use in this context. prepareBeanFactory(beanFactory); try { // Allows post-processing of the bean factory in context subclasses. postProcessBeanFactory(beanFactory); StartupStep beanPostProcess = this.applicationStartup.start("spring.context.beans.post-process"); // Invoke factory processors registered as beans in the context. invokeBeanFactoryPostProcessors(beanFactory); // Register bean processors that intercept bean creation. registerBeanPostProcessors(beanFactory); beanPostProcess.end(); // Initialize message source for this context. initMessageSource(); // Initialize event multicaster for this context. initApplicationEventMulticaster(); // Initialize other special beans in specific context subclasses. onRefresh(); // Check for listener beans and register them. registerListeners(); // Instantiate all remaining (non-lazy-init) singletons. finishBeanFactoryInitialization(beanFactory); // Last step: publish corresponding event. finishRefresh(); } catch (BeansException ex) { if (logger.isWarnEnabled()) { logger.warn("Exception encountered during context initialization - " + "cancelling refresh attempt: " + ex); } // Destroy already created singletons to avoid dangling resources. destroyBeans(); // Reset 'active' flag. cancelRefresh(ex); // Propagate exception to caller. throw ex; } finally { // Reset common introspection caches in Spring's core, since we // might not ever need metadata for singleton beans anymore... resetCommonCaches(); contextRefresh.end(); } } } /** * Prepare this context for refreshing, setting its startup date and * active flag as well as performing any initialization of property sources. */ protected void prepareRefresh() { // Switch to active. this.startupDate = System.currentTimeMillis(); this.closed.set(false); this.active.set(true); if (logger.isDebugEnabled()) { if (logger.isTraceEnabled()) { logger.trace("Refreshing " + this); } else { logger.debug("Refreshing " + getDisplayName()); } } // Initialize any placeholder property sources in the context environment. initPropertySources(); // Validate that all properties marked as required are resolvable: // see ConfigurablePropertyResolver#setRequiredProperties getEnvironment().validateRequiredProperties(); // Store pre-refresh ApplicationListeners... if (this.earlyApplicationListeners == null) { this.earlyApplicationListeners = new LinkedHashSet<>(this.applicationListeners); } else { // Reset local application listeners to pre-refresh state. this.applicationListeners.clear(); this.applicationListeners.addAll(this.earlyApplicationListeners); } // Allow for the collection of early ApplicationEvents, // to be published once the multicaster is available... this.earlyApplicationEvents = new LinkedHashSet<>(); } /** *

Replace any stub property sources with actual instances. * @see org.springframework.core.env.PropertySource.StubPropertySource * @see org.springframework.web.context.support.WebApplicationContextUtils#initServletPropertySources */ protected void initPropertySources() { // For subclasses: do nothing by default. } /** * Tell the subclass to refresh the internal bean factory. * @return the fresh BeanFactory instance * @see #refreshBeanFactory() * @see #getBeanFactory() */ protected ConfigurableListableBeanFactory obtainFreshBeanFactory() { refreshBeanFactory(); return getBeanFactory(); } /** * Configure the factory's standard context characteristics, * such as the context's ClassLoader and post-processors. * @param beanFactory the BeanFactory to configure */ protected void prepareBeanFactory(ConfigurableListableBeanFactory beanFactory) { // Tell the internal bean factory to use the context's class loader etc. beanFactory.setBeanClassLoader(getClassLoader()); beanFactory.setBeanExpressionResolver(new StandardBeanExpressionResolver(beanFactory.getBeanClassLoader())); beanFactory.addPropertyEditorRegistrar(new ResourceEditorRegistrar(this, getEnvironment())); // Configure the bean factory with context callbacks. beanFactory.addBeanPostProcessor(new ApplicationContextAwareProcessor(this)); beanFactory.ignoreDependencyInterface(EnvironmentAware.class); beanFactory.ignoreDependencyInterface(EmbeddedValueResolverAware.class); beanFactory.ignoreDependencyInterface(ResourceLoaderAware.class); beanFactory.ignoreDependencyInterface(ApplicationEventPublisherAware.class); beanFactory.ignoreDependencyInterface(MessageSourceAware.class); beanFactory.ignoreDependencyInterface(ApplicationContextAware.class); beanFactory.ignoreDependencyInterface(ApplicationStartupAware.class); // BeanFactory interface not registered as resolvable type in a plain factory. // MessageSource registered (and found for autowiring) as a bean. beanFactory.registerResolvableDependency(BeanFactory.class, beanFactory); beanFactory.registerResolvableDependency(ResourceLoader.class, this); beanFactory.registerResolvableDependency(ApplicationEventPublisher.class, this); beanFactory.registerResolvableDependency(ApplicationContext.class, this); // Register early post-processor for detecting inner beans as ApplicationListeners. beanFactory.addBeanPostProcessor(new ApplicationListenerDetector(this)); // Detect a LoadTimeWeaver and prepare for weaving, if found. if (!NativeDetector.inNativeImage() && beanFactory.containsBean(LOAD_TIME_WEAVER_BEAN_NAME)) { beanFactory.addBeanPostProcessor(new LoadTimeWeaverAwareProcessor(beanFactory)); // Set a temporary ClassLoader for type matching. beanFactory.setTempClassLoader(new ContextTypeMatchClassLoader(beanFactory.getBeanClassLoader())); } // Register default environment beans. if (!beanFactory.containsLocalBean(ENVIRONMENT_BEAN_NAME)) { beanFactory.registerSingleton(ENVIRONMENT_BEAN_NAME, getEnvironment()); } if (!beanFactory.containsLocalBean(SYSTEM_PROPERTIES_BEAN_NAME)) { beanFactory.registerSingleton(SYSTEM_PROPERTIES_BEAN_NAME, getEnvironment().getSystemProperties()); } if (!beanFactory.containsLocalBean(SYSTEM_ENVIRONMENT_BEAN_NAME)) { beanFactory.registerSingleton(SYSTEM_ENVIRONMENT_BEAN_NAME, getEnvironment().getSystemEnvironment()); } if (!beanFactory.containsLocalBean(APPLICATION_STARTUP_BEAN_NAME)) { beanFactory.registerSingleton(APPLICATION_STARTUP_BEAN_NAME, getApplicationStartup()); } } /** * Modify the application context's internal bean factory after its standard * initialization. All bean definitions will have been loaded, but no beans * will have been instantiated yet. This allows for registering special * BeanPostProcessors etc in certain ApplicationContext implementations. * @param beanFactory the bean factory used by the application context */ protected void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) { } /** * Instantiate and invoke all registered BeanFactoryPostProcessor beans, * respecting explicit order if given. *

Must be called before singleton instantiation. */ protected void invokeBeanFactoryPostProcessors(ConfigurableListableBeanFactory beanFactory) { PostProcessorRegistrationDelegate.invokeBeanFactoryPostProcessors(beanFactory, getBeanFactoryPostProcessors()); // Detect a LoadTimeWeaver and prepare for weaving, if found in the meantime // (e.g. through an @Bean method registered by ConfigurationClassPostProcessor) if (!NativeDetector.inNativeImage() && beanFactory.getTempClassLoader() == null && beanFactory.containsBean(LOAD_TIME_WEAVER_BEAN_NAME)) { beanFactory.addBeanPostProcessor(new LoadTimeWeaverAwareProcessor(beanFactory)); beanFactory.setTempClassLoader(new ContextTypeMatchClassLoader(beanFactory.getBeanClassLoader())); } } /** * Instantiate and register all BeanPostProcessor beans, * respecting explicit order if given. *

Must be called before any instantiation of application beans. */ protected void registerBeanPostProcessors(ConfigurableListableBeanFactory beanFactory) { PostProcessorRegistrationDelegate.registerBeanPostProcessors(beanFactory, this); } /** * Initialize the MessageSource. * Use parent's if none defined in this context. */ protected void initMessageSource() { ConfigurableListableBeanFactory beanFactory = getBeanFactory(); if (beanFactory.containsLocalBean(MESSAGE_SOURCE_BEAN_NAME)) { this.messageSource = beanFactory.getBean(MESSAGE_SOURCE_BEAN_NAME, MessageSource.class); // Make MessageSource aware of parent MessageSource. if (this.parent != null && this.messageSource instanceof HierarchicalMessageSource hms && hms.getParentMessageSource() == null) { // Only set parent context as parent MessageSource if no parent MessageSource // registered already. hms.setParentMessageSource(getInternalParentMessageSource()); } if (logger.isTraceEnabled()) { logger.trace("Using MessageSource [" + this.messageSource + "]"); } } else { // Use empty MessageSource to be able to accept getMessage calls. DelegatingMessageSource dms = new DelegatingMessageSource(); dms.setParentMessageSource(getInternalParentMessageSource()); this.messageSource = dms; beanFactory.registerSingleton(MESSAGE_SOURCE_BEAN_NAME, this.messageSource); if (logger.isTraceEnabled()) { logger.trace("No '" + MESSAGE_SOURCE_BEAN_NAME + "' bean, using [" + this.messageSource + "]"); } } } /** * Initialize the ApplicationEventMulticaster. * Uses SimpleApplicationEventMulticaster if none defined in the context. * @see org.springframework.context.event.SimpleApplicationEventMulticaster */ protected void initApplicationEventMulticaster() { ConfigurableListableBeanFactory beanFactory = getBeanFactory(); if (beanFactory.containsLocalBean(APPLICATION_EVENT_MULTICASTER_BEAN_NAME)) { this.applicationEventMulticaster = beanFactory.getBean(APPLICATION_EVENT_MULTICASTER_BEAN_NAME, ApplicationEventMulticaster.class); if (logger.isTraceEnabled()) { logger.trace("Using ApplicationEventMulticaster [" + this.applicationEventMulticaster + "]"); } } else { this.applicationEventMulticaster = new SimpleApplicationEventMulticaster(beanFactory); beanFactory.registerSingleton(APPLICATION_EVENT_MULTICASTER_BEAN_NAME, this.applicationEventMulticaster); if (logger.isTraceEnabled()) { logger.trace("No '" + APPLICATION_EVENT_MULTICASTER_BEAN_NAME + "' bean, using " + "[" + this.applicationEventMulticaster.getClass().getSimpleName() + "]"); } } } /** * Initialize the LifecycleProcessor. * Uses DefaultLifecycleProcessor if none defined in the context. * @see org.springframework.context.support.DefaultLifecycleProcessor */ protected void initLifecycleProcessor() { ConfigurableListableBeanFactory beanFactory = getBeanFactory(); if (beanFactory.containsLocalBean(LIFECYCLE_PROCESSOR_BEAN_NAME)) { this.lifecycleProcessor = beanFactory.getBean(LIFECYCLE_PROCESSOR_BEAN_NAME, LifecycleProcessor.class); if (logger.isTraceEnabled()) { logger.trace("Using LifecycleProcessor [" + this.lifecycleProcessor + "]"); } } else { DefaultLifecycleProcessor defaultProcessor = new DefaultLifecycleProcessor(); defaultProcessor.setBeanFactory(beanFactory); this.lifecycleProcessor = defaultProcessor; beanFactory.registerSingleton(LIFECYCLE_PROCESSOR_BEAN_NAME, this.lifecycleProcessor); if (logger.isTraceEnabled()) { logger.trace("No '" + LIFECYCLE_PROCESSOR_BEAN_NAME + "' bean, using " + "[" + this.lifecycleProcessor.getClass().getSimpleName() + "]"); } } } /** * Template method which can be overridden to add context-specific refresh work. * Called on initialization of special beans, before instantiation of singletons. *

This implementation is empty. * @throws BeansException in case of errors * @see #refresh() */ protected void onRefresh() throws BeansException { // For subclasses: do nothing by default. } /** * Add beans that implement ApplicationListener as listeners. * Doesn't affect other listeners, which can be added without being beans. */ protected void registerListeners() { // Register statically specified listeners first. for (ApplicationListener listener : getApplicationListeners()) { getApplicationEventMulticaster().addApplicationListener(listener); } // Do not initialize FactoryBeans here: We need to leave all regular beans // uninitialized to let post-processors apply to them! String[] listenerBeanNames = getBeanNamesForType(ApplicationListener.class, true, false); for (String listenerBeanName : listenerBeanNames) { getApplicationEventMulticaster().addApplicationListenerBean(listenerBeanName); } // Publish early application events now that we finally have a multicaster... Set earlyEventsToProcess = this.earlyApplicationEvents; this.earlyApplicationEvents = null; if (!CollectionUtils.isEmpty(earlyEventsToProcess)) { for (ApplicationEvent earlyEvent : earlyEventsToProcess) { getApplicationEventMulticaster().multicastEvent(earlyEvent); } } } /** * Finish the initialization of this context's bean factory, * initializing all remaining singleton beans. */ protected void finishBeanFactoryInitialization(ConfigurableListableBeanFactory beanFactory) { // Initialize conversion service for this context. if (beanFactory.containsBean(CONVERSION_SERVICE_BEAN_NAME) && beanFactory.isTypeMatch(CONVERSION_SERVICE_BEAN_NAME, ConversionService.class)) { beanFactory.setConversionService( beanFactory.getBean(CONVERSION_SERVICE_BEAN_NAME, ConversionService.class)); } // Register a default embedded value resolver if no BeanFactoryPostProcessor // (such as a PropertySourcesPlaceholderConfigurer bean) registered any before: // at this point, primarily for resolution in annotation attribute values. if (!beanFactory.hasEmbeddedValueResolver()) { beanFactory.addEmbeddedValueResolver(strVal -> getEnvironment().resolvePlaceholders(strVal)); } // Initialize LoadTimeWeaverAware beans early to allow for registering their transformers early. String[] weaverAwareNames = beanFactory.getBeanNamesForType(LoadTimeWeaverAware.class, false, false); for (String weaverAwareName : weaverAwareNames) { getBean(weaverAwareName); } // Stop using the temporary ClassLoader for type matching. beanFactory.setTempClassLoader(null); // Allow for caching all bean definition metadata, not expecting further changes. beanFactory.freezeConfiguration(); // Instantiate all remaining (non-lazy-init) singletons. beanFactory.preInstantiateSingletons(); } /** * Finish the refresh of this context, invoking the LifecycleProcessor's * onRefresh() method and publishing the * {@link org.springframework.context.event.ContextRefreshedEvent}. */ @SuppressWarnings("deprecation") protected void finishRefresh() { // Clear context-level resource caches (such as ASM metadata from scanning). clearResourceCaches(); // Initialize lifecycle processor for this context. initLifecycleProcessor(); // Propagate refresh to lifecycle processor first. getLifecycleProcessor().onRefresh(); // Publish the final event. publishEvent(new ContextRefreshedEvent(this)); } /** * Cancel this context's refresh attempt, resetting the {@code active} flag * after an exception got thrown. * @param ex the exception that led to the cancellation */ protected void cancelRefresh(BeansException ex) { this.active.set(false); } /** * Reset Spring's common reflection metadata caches, in particular the * {@link ReflectionUtils}, {@link AnnotationUtils}, {@link ResolvableType} * and {@link CachedIntrospectionResults} caches. * @since 4.2 * @see ReflectionUtils#clearCache() * @see AnnotationUtils#clearCache() * @see ResolvableType#clearCache() * @see CachedIntrospectionResults#clearClassLoader(ClassLoader) */ protected void resetCommonCaches() { ReflectionUtils.clearCache(); AnnotationUtils.clearCache(); ResolvableType.clearCache(); CachedIntrospectionResults.clearClassLoader(getClassLoader()); } /** * Register a shutdown hook {@linkplain Thread#getName() named} * {@code SpringContextShutdownHook} with the JVM runtime, closing this * context on JVM shutdown unless it has already been closed at that time. *

Delegates to {@code doClose()} for the actual closing procedure. * @see Runtime#addShutdownHook * @see ConfigurableApplicationContext#SHUTDOWN_HOOK_THREAD_NAME * @see #close() * @see #doClose() */ @Override public void registerShutdownHook() { if (this.shutdownHook == null) { // No shutdown hook registered yet. this.shutdownHook = new Thread(SHUTDOWN_HOOK_THREAD_NAME) { @Override public void run() { synchronized (startupShutdownMonitor) { doClose(); } } }; Runtime.getRuntime().addShutdownHook(this.shutdownHook); } } /** * Close this application context, destroying all beans in its bean factory. *

Delegates to {@code doClose()} for the actual closing procedure. * Also removes a JVM shutdown hook, if registered, as it's not needed anymore. * @see #doClose() * @see #registerShutdownHook() */ @Override public void close() { synchronized (this.startupShutdownMonitor) { doClose(); // If we registered a JVM shutdown hook, we don't need it anymore now: // We've already explicitly closed the context. if (this.shutdownHook != null) { try { Runtime.getRuntime().removeShutdownHook(this.shutdownHook); } catch (IllegalStateException ex) { // ignore - VM is already shutting down } } } } /** * Actually performs context closing: publishes a ContextClosedEvent and * destroys the singletons in the bean factory of this application context. *

Called by both {@code close()} and a JVM shutdown hook, if any. * @see org.springframework.context.event.ContextClosedEvent * @see #destroyBeans() * @see #close() * @see #registerShutdownHook() */ @SuppressWarnings("deprecation") protected void doClose() { // Check whether an actual close attempt is necessary... if (this.active.get() && this.closed.compareAndSet(false, true)) { if (logger.isDebugEnabled()) { logger.debug("Closing " + this); } try { // Publish shutdown event. publishEvent(new ContextClosedEvent(this)); } catch (Throwable ex) { logger.warn("Exception thrown from ApplicationListener handling ContextClosedEvent", ex); } // Stop all Lifecycle beans, to avoid delays during individual destruction. if (this.lifecycleProcessor != null) { try { this.lifecycleProcessor.onClose(); } catch (Throwable ex) { logger.warn("Exception thrown from LifecycleProcessor on context close", ex); } } // Destroy all cached singletons in the context's BeanFactory. destroyBeans(); // Close the state of this context itself. closeBeanFactory(); // Let subclasses do some final clean-up if they wish... onClose(); // Reset local application listeners to pre-refresh state. if (this.earlyApplicationListeners != null) { this.applicationListeners.clear(); this.applicationListeners.addAll(this.earlyApplicationListeners); } // Switch to inactive. this.active.set(false); } } /** * Template method for destroying all beans that this context manages. * The default implementation destroy all cached singletons in this context, * invoking {@code DisposableBean.destroy()} and/or the specified * "destroy-method". *

Can be overridden to add context-specific bean destruction steps * right before or right after standard singleton destruction, * while the context's BeanFactory is still active. * @see #getBeanFactory() * @see org.springframework.beans.factory.config.ConfigurableBeanFactory#destroySingletons() */ protected void destroyBeans() { getBeanFactory().destroySingletons(); } /** * Template method which can be overridden to add context-specific shutdown work. * The default implementation is empty. *

Called at the end of {@link #doClose}'s shutdown procedure, after * this context's BeanFactory has been closed. If custom shutdown logic * needs to execute while the BeanFactory is still active, override * the {@link #destroyBeans()} method instead. */ protected void onClose() { // For subclasses: do nothing by default. } @Override public boolean isActive() { return this.active.get(); } /** * Assert that this context's BeanFactory is currently active, * throwing an {@link IllegalStateException} if it isn't. *

Invoked by all {@link BeanFactory} delegation methods that depend * on an active context, i.e. in particular all bean accessor methods. *

The default implementation checks the {@link #isActive() 'active'} status * of this context overall. May be overridden for more specific checks, or for a * no-op if {@link #getBeanFactory()} itself throws an exception in such a case. */ protected void assertBeanFactoryActive() { if (!this.active.get()) { if (this.closed.get()) { throw new IllegalStateException(getDisplayName() + " has been closed already"); } else { throw new IllegalStateException(getDisplayName() + " has not been refreshed yet"); } } } //--------------------------------------------------------------------- // Implementation of BeanFactory interface //--------------------------------------------------------------------- @Override public Object getBean(String name) throws BeansException { assertBeanFactoryActive(); return getBeanFactory().getBean(name); } @Override public T getBean(String name, Class requiredType) throws BeansException { assertBeanFactoryActive(); return getBeanFactory().getBean(name, requiredType); } @Override public Object getBean(String name, Object... args) throws BeansException { assertBeanFactoryActive(); return getBeanFactory().getBean(name, args); } @Override public T getBean(Class requiredType) throws BeansException { assertBeanFactoryActive(); return getBeanFactory().getBean(requiredType); } @Override public T getBean(Class requiredType, Object... args) throws BeansException { assertBeanFactoryActive(); return getBeanFactory().getBean(requiredType, args); } @Override public ObjectProvider getBeanProvider(Class requiredType) { assertBeanFactoryActive(); return getBeanFactory().getBeanProvider(requiredType); } @Override public ObjectProvider getBeanProvider(ResolvableType requiredType) { assertBeanFactoryActive(); return getBeanFactory().getBeanProvider(requiredType); } @Override public boolean containsBean(String name) { return getBeanFactory().containsBean(name); } @Override public boolean isSingleton(String name) throws NoSuchBeanDefinitionException { assertBeanFactoryActive(); return getBeanFactory().isSingleton(name); } @Override public boolean isPrototype(String name) throws NoSuchBeanDefinitionException { assertBeanFactoryActive(); return getBeanFactory().isPrototype(name); } @Override public boolean isTypeMatch(String name, ResolvableType typeToMatch) throws NoSuchBeanDefinitionException { assertBeanFactoryActive(); return getBeanFactory().isTypeMatch(name, typeToMatch); } @Override public boolean isTypeMatch(String name, Class typeToMatch) throws NoSuchBeanDefinitionException { assertBeanFactoryActive(); return getBeanFactory().isTypeMatch(name, typeToMatch); } @Override @Nullable public Class getType(String name) throws NoSuchBeanDefinitionException { assertBeanFactoryActive(); return getBeanFactory().getType(name); } @Override @Nullable public Class getType(String name, boolean allowFactoryBeanInit) throws NoSuchBeanDefinitionException { assertBeanFactoryActive(); return getBeanFactory().getType(name, allowFactoryBeanInit); } @Override public String[] getAliases(String name) { return getBeanFactory().getAliases(name); } //--------------------------------------------------------------------- // Implementation of ListableBeanFactory interface //--------------------------------------------------------------------- @Override public boolean containsBeanDefinition(String beanName) { return getBeanFactory().containsBeanDefinition(beanName); } @Override public int getBeanDefinitionCount() { return getBeanFactory().getBeanDefinitionCount(); } @Override public String[] getBeanDefinitionNames() { return getBeanFactory().getBeanDefinitionNames(); } @Override public ObjectProvider getBeanProvider(Class requiredType, boolean allowEagerInit) { assertBeanFactoryActive(); return getBeanFactory().getBeanProvider(requiredType, allowEagerInit); } @Override public ObjectProvider getBeanProvider(ResolvableType requiredType, boolean allowEagerInit) { assertBeanFactoryActive(); return getBeanFactory().getBeanProvider(requiredType, allowEagerInit); } @Override public String[] getBeanNamesForType(ResolvableType type) { assertBeanFactoryActive(); return getBeanFactory().getBeanNamesForType(type); } @Override public String[] getBeanNamesForType(ResolvableType type, boolean includeNonSingletons, boolean allowEagerInit) { assertBeanFactoryActive(); return getBeanFactory().getBeanNamesForType(type, includeNonSingletons, allowEagerInit); } @Override public String[] getBeanNamesForType(@Nullable Class type) { assertBeanFactoryActive(); return getBeanFactory().getBeanNamesForType(type); } @Override public String[] getBeanNamesForType(@Nullable Class type, boolean includeNonSingletons, boolean allowEagerInit) { assertBeanFactoryActive(); return getBeanFactory().getBeanNamesForType(type, includeNonSingletons, allowEagerInit); } @Override public Map getBeansOfType(@Nullable Class type) throws BeansException { assertBeanFactoryActive(); return getBeanFactory().getBeansOfType(type); } @Override public Map getBeansOfType(@Nullable Class type, boolean includeNonSingletons, boolean allowEagerInit) throws BeansException { assertBeanFactoryActive(); return getBeanFactory().getBeansOfType(type, includeNonSingletons, allowEagerInit); } @Override public String[] getBeanNamesForAnnotation(Class annotationType) { assertBeanFactoryActive(); return getBeanFactory().getBeanNamesForAnnotation(annotationType); } @Override public Map getBeansWithAnnotation(Class annotationType) throws BeansException { assertBeanFactoryActive(); return getBeanFactory().getBeansWithAnnotation(annotationType); } @Override @Nullable public A findAnnotationOnBean(String beanName, Class annotationType) throws NoSuchBeanDefinitionException { assertBeanFactoryActive(); return getBeanFactory().findAnnotationOnBean(beanName, annotationType); } @Override @Nullable public A findAnnotationOnBean( String beanName, Class annotationType, boolean allowFactoryBeanInit) throws NoSuchBeanDefinitionException { assertBeanFactoryActive(); return getBeanFactory().findAnnotationOnBean(beanName, annotationType, allowFactoryBeanInit); } @Override public Set findAllAnnotationsOnBean( String beanName, Class annotationType, boolean allowFactoryBeanInit) throws NoSuchBeanDefinitionException { assertBeanFactoryActive(); return getBeanFactory().findAllAnnotationsOnBean(beanName, annotationType, allowFactoryBeanInit); } //--------------------------------------------------------------------- // Implementation of HierarchicalBeanFactory interface //--------------------------------------------------------------------- @Override @Nullable public BeanFactory getParentBeanFactory() { return getParent(); } @Override public boolean containsLocalBean(String name) { return getBeanFactory().containsLocalBean(name); } /** * Return the internal bean factory of the parent context if it implements * ConfigurableApplicationContext; else, return the parent context itself. * @see org.springframework.context.ConfigurableApplicationContext#getBeanFactory */ @Nullable protected BeanFactory getInternalParentBeanFactory() { return (getParent() instanceof ConfigurableApplicationContext cac ? cac.getBeanFactory() : getParent()); } //--------------------------------------------------------------------- // Implementation of MessageSource interface //--------------------------------------------------------------------- @Override public String getMessage(String code, @Nullable Object[] args, @Nullable String defaultMessage, Locale locale) { return getMessageSource().getMessage(code, args, defaultMessage, locale); } @Override public String getMessage(String code, @Nullable Object[] args, Locale locale) throws NoSuchMessageException { return getMessageSource().getMessage(code, args, locale); } @Override public String getMessage(MessageSourceResolvable resolvable, Locale locale) throws NoSuchMessageException { return getMessageSource().getMessage(resolvable, locale); } /** * Return the internal MessageSource used by the context. * @return the internal MessageSource (never {@code null}) * @throws IllegalStateException if the context has not been initialized yet */ private MessageSource getMessageSource() throws IllegalStateException { if (this.messageSource == null) { throw new IllegalStateException("MessageSource not initialized - " + "call 'refresh' before accessing messages via the context: " + this); } return this.messageSource; } /** * Return the internal message source of the parent context if it is an * AbstractApplicationContext too; else, return the parent context itself. */ @Nullable protected MessageSource getInternalParentMessageSource() { return (getParent() instanceof AbstractApplicationContext abstractApplicationContext ? abstractApplicationContext.messageSource : getParent()); } //--------------------------------------------------------------------- // Implementation of ResourcePatternResolver interface //--------------------------------------------------------------------- @Override public Resource[] getResources(String locationPattern) throws IOException { return this.resourcePatternResolver.getResources(locationPattern); } //--------------------------------------------------------------------- // Implementation of Lifecycle interface //--------------------------------------------------------------------- @Override public void start() { getLifecycleProcessor().start(); publishEvent(new ContextStartedEvent(this)); } @Override public void stop() { getLifecycleProcessor().stop(); publishEvent(new ContextStoppedEvent(this)); } @Override public boolean isRunning() { return (this.lifecycleProcessor != null && this.lifecycleProcessor.isRunning()); } //--------------------------------------------------------------------- // Abstract methods that must be implemented by subclasses //--------------------------------------------------------------------- /** * Subclasses must implement this method to perform the actual configuration load. * The method is invoked by {@link #refresh()} before any other initialization work. *

A subclass will either create a new bean factory and hold a reference to it, * or return a single BeanFactory instance that it holds. In the latter case, it will * usually throw an IllegalStateException if refreshing the context more than once. * @throws BeansException if initialization of the bean factory failed * @throws IllegalStateException if already initialized and multiple refresh * attempts are not supported */ protected abstract void refreshBeanFactory() throws BeansException, IllegalStateException; /** * Subclasses must implement this method to release their internal bean factory. * This method gets invoked by {@link #close()} after all other shutdown work. *

Should never throw an exception but rather log shutdown failures. */ protected abstract void closeBeanFactory(); /** * Subclasses must return their internal bean factory here. They should implement the * lookup efficiently, so that it can be called repeatedly without a performance penalty. *

Note: Subclasses should check whether the context is still active before * returning the internal bean factory. The internal factory should generally be * considered unavailable once the context has been closed. * @return this application context's internal bean factory (never {@code null}) * @throws IllegalStateException if the context does not hold an internal bean factory yet * (usually if {@link #refresh()} has never been called) or if the context has been * closed already * @see #refreshBeanFactory() * @see #closeBeanFactory() */ @Override public abstract ConfigurableListableBeanFactory getBeanFactory() throws IllegalStateException; /** * Return information about this context. */ @Override public String toString() { StringBuilder sb = new StringBuilder(getDisplayName()); sb.append(", started on ").append(new Date(getStartupDate())); ApplicationContext parent = getParent(); if (parent != null) { sb.append(", parent: ").append(parent.getDisplayName()); } return sb.toString(); } }





© 2015 - 2024 Weber Informatics LLC | Privacy Policy