Spring 啓動記錄(2)

Spring MVC 啓動記錄(2)java

一、XmlWebApplicationContextweb

繼承圖看出最頂層的依次之下 DefaultResouceLoaderspring

AbstractApplicationContextexpress

AbstractRefreshableApplicationContextapache

AbstractRefreshableConfigApplicationContextapp

AbstractRefreshableWebApplicationContextless

最後是XmlWebApplicationContextide

二、DefaultResourceLoader是一個單純的資源加載的默認實現類post

 

 

public class DefaultResourceLoader implements ResourceLoader {

	private ClassLoader classLoader;


	/**
	 * Create a new DefaultResourceLoader.
	 * <p>ClassLoader access will happen using the thread context class loader
	 * at the time of this ResourceLoader's initialization.
	 * @see java.lang.Thread#getContextClassLoader()
	 */
	public DefaultResourceLoader() {
		this.classLoader = ClassUtils.getDefaultClassLoader();
	}

	/**
	 * Create a new DefaultResourceLoader.
	 * @param classLoader the ClassLoader to load class path resources with, or {@code null}
	 * for using the thread context class loader at the time of actual resource access
	 */
	public DefaultResourceLoader(ClassLoader classLoader) {
		this.classLoader = classLoader;
	}


	/**
	 * Specify the ClassLoader to load class path resources with, or {@code null}
	 * for using the thread context class loader at the time of actual resource access.
	 * <p>The default is that ClassLoader access will happen using the thread context
	 * class loader at the time of this ResourceLoader's initialization.
	 */
	public void setClassLoader(ClassLoader classLoader) {
		this.classLoader = classLoader;
	}

	/**
	 * Return the ClassLoader to load class path resources with.
	 * <p>Will get passed to ClassPathResource's constructor for all
	 * ClassPathResource objects created by this resource loader.
	 * @see ClassPathResource
	 */
	@Override
	public ClassLoader getClassLoader() {
		return (this.classLoader != null ? this.classLoader : ClassUtils.getDefaultClassLoader());
	}


	@Override
	public Resource getResource(String location) {
		Assert.notNull(location, "Location must not be null");
       //若是路徑是/開始的則new ClassPathContextResource(path, getClassLoader())
		if (location.startsWith("/")) {
			return getResourceByPath(location);
		}
       //以classpath:開始把classpath:去掉後new ClassPathContextResource
		else if (location.startsWith(CLASSPATH_URL_PREFIX)) {
			return new ClassPathResource(location.substring(CLASSPATH_URL_PREFIX.length()), getClassLoader());
		}
//看來/開始的跟classpath:開始的處理都是ClassPathResource資源
		else {
			try {
				// Try to parse the location as a URL..
               //以url形勢獲取加載的資源.
				URL url = new URL(location);
				return new UrlResource(url);
			}
			catch (MalformedURLException ex) {
				// No URL -> resolve as resource path.
				return getResourceByPath(location);
			}
		}
	}

	/**
	 * Return a Resource handle for the resource at the given path.
	 * <p>The default implementation supports class path locations. This should
	 * be appropriate for standalone implementations but can be overridden,
	 * e.g. for implementations targeted at a Servlet container.
	 * @param path the path to the resource
	 * @return the corresponding Resource handle
	 * @see ClassPathResource
	 * @see org.springframework.context.support.FileSystemXmlApplicationContext#getResourceByPath
	 * @see org.springframework.web.context.support.XmlWebApplicationContext#getResourceByPath
	 */
	protected Resource getResourceByPath(String path) {
		return new ClassPathContextResource(path, getClassLoader());
	}


	/**
	 * ClassPathResource that explicitly expresses a context-relative path
	 * through implementing the ContextResource interface.
	 */
	protected static class ClassPathContextResource extends ClassPathResource implements ContextResource {

		public ClassPathContextResource(String path, ClassLoader classLoader) {
			super(path, classLoader);
		}

		@Override
		public String getPathWithinContext() {
			return getPath();
		}

		@Override
		public Resource createRelative(String relativePath) {
			String pathToUse = StringUtils.applyRelativePath(getPath(), relativePath);
			return new ClassPathContextResource(pathToUse, getClassLoader());
		}
	}

該類只是負責默認資源的處理web.xml中的ui

spring xml的路徑,生成Resource類

 

三、AbstractApplicationContext 類

這個類的接口,DefaultResourceLoader(默認資源加載),

ConfigurableApplicationContext(他實現了ApplicationContext, Lifecycle, Closeable )

就是spring xml文件獲取類生命週期,資源銷燬,應用上下文的複合接口,此乃核心接口哦;

ApplicationContext:spring的應用上下文實現,

Lifecycle:聲明週期接口

Closeable :銷燬web 應用的接口,怎麼取消各類資源

s

//獲取資源正則表達對象

/*
 * Copyright 2002-2015 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;


/**
 * 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.
 *
 * <p>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.
 *
 * <p>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 "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.
 *
 * <p>Implements resource loading through 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 overwritten in a subclass.
 *
 * @author Rod Johnson
 * @author Juergen Hoeller
 * @author Mark Fisher
 * @author Stephane Nicoll
 * @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

 *該類負責整個spring的工廠類的方法是實現,基於模版方法
 */
public abstract class AbstractApplicationContext extends DefaultResourceLoader
      implements ConfigurableApplicationContext, DisposableBean {

   /**
    * 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 */
   private ApplicationContext parent;

   /** Environment used by this context */
   private ConfigurableEnvironment environment;

   /** BeanFactoryPostProcessors to apply on refresh */
   private final List<BeanFactoryPostProcessor> beanFactoryPostProcessors =
         new ArrayList<BeanFactoryPostProcessor>();

   /** 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 */
   private Thread shutdownHook;

   /** ResourcePatternResolver used by this context */
   private ResourcePatternResolver resourcePatternResolver;

   /** LifecycleProcessor for managing the lifecycle of beans within this context */
   private LifecycleProcessor lifecycleProcessor;

   /** MessageSource we delegate our implementation of this interface to */
   private MessageSource messageSource;

   /** Helper class used in event publishing */
   private ApplicationEventMulticaster applicationEventMulticaster;

   /** Statically specified listeners */
   private final Set<ApplicationListener<?>> applicationListeners = new LinkedHashSet<ApplicationListener<?>>();

   /** ApplicationEvents published early */
   private Set<ApplicationEvent> 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(ApplicationContext parent) {
      this();
      setParent(parent);
   }


   //---------------------------------------------------------------------
   // Implementation of ApplicationContext interface
   //---------------------------------------------------------------------

   /**
    * Set the unique id of this application context.
    * <p>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.
    * <p>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
   public ApplicationContext getParent() {
      return this.parent;
   }

   /**
    * {@inheritDoc}
    * <p>If {@code null}, a new environment will be initialized via
    * {@link #createEnvironment()}.
    */
   @Override
   public ConfigurableEnvironment getEnvironment() {
      if (this.environment == null) {
         this.environment = createEnvironment();
      }
      return this.environment;
   }

   /**
    * {@inheritDoc}
    * <p>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 <em>before</em> {@link #refresh()}.
    * @see org.springframework.context.support.AbstractApplicationContext#createEnvironment
    */
   @Override
   public void setEnvironment(ConfigurableEnvironment environment) {
      this.environment = environment;
   }

   /**
    * 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.
    * <p>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.
    * <p>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, ResolvableType eventType) {
      Assert.notNull(event, "Event must not be null");
      if (logger.isTraceEnabled()) {
         logger.trace("Publishing event in " + getDisplayName() + ": " + event);
      }

      // Decorate event as an ApplicationEvent if necessary
      ApplicationEvent applicationEvent;
      if (event instanceof ApplicationEvent) {
         applicationEvent = (ApplicationEvent) event;
      }
      else {
         applicationEvent = new PayloadApplicationEvent<Object>(this, event);
         if (eventType == null) {
            eventType = ResolvableType.forClassWithGenerics(PayloadApplicationEvent.class, event.getClass());
         }
      }

      // 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) this.parent).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;
   }

   /**
    * 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.
    * <p>Can be overridden in subclasses, for extended resolution strategies,
    * for example in a web environment.
    * <p><b>Do not call this when needing to resolve a location pattern.</b>
    * 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
   //---------------------------------------------------------------------

   /**
    * {@inheritDoc}
    * <p>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(ApplicationContext parent) {
      this.parent = parent;
      if (parent != null) {
         Environment parentEnvironment = parent.getEnvironment();
         if (parentEnvironment instanceof ConfigurableEnvironment) {
            getEnvironment().merge((ConfigurableEnvironment) parentEnvironment);
         }
      }
   }

   @Override
   public void addBeanFactoryPostProcessor(BeanFactoryPostProcessor beanFactoryPostProcessor) {
      this.beanFactoryPostProcessors.add(beanFactoryPostProcessor);
   }


   /**
    * Return the list of BeanFactoryPostProcessors that will get applied
    * to the internal BeanFactory.
    */
   public List<BeanFactoryPostProcessor> getBeanFactoryPostProcessors() {
      return this.beanFactoryPostProcessors;
   }

   @Override
   public void addApplicationListener(ApplicationListener<?> listener) {
      if (this.applicationEventMulticaster != null) {
         this.applicationEventMulticaster.addApplicationListener(listener);
      }
      else {
         this.applicationListeners.add(listener);
      }
   }

   /**
    * Return the list of statically specified ApplicationListeners.
    */
   public Collection<ApplicationListener<?>> getApplicationListeners() {
      return this.applicationListeners;
   }

   /**
    * Create and return a new {@link StandardEnvironment}.
    * <p>Subclasses may override this method in order to supply
    * a custom {@link ConfigurableEnvironment} implementation.
    * 建立一個標準的環境環境變量
    */
   protected ConfigurableEnvironment createEnvironment() {
      return new StandardEnvironment();
   }
   //設置比spring的工程刷新功能,用於初始化用
   @Override
   public void refresh() throws BeansException, IllegalStateException {
      synchronized (this.startupShutdownMonitor) {
         // 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);

            // Invoke factory processors registered as beans in the context.
            invokeBeanFactoryPostProcessors(beanFactory);

            // Register bean processors that intercept bean creation.
            registerBeanPostProcessors(beanFactory);

            // 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();
         }
      }
   }

   /**
    * Prepare this context for refreshing, setting its startup date and
    * active flag as well as performing any initialization of property sources.
    */
   protected void prepareRefresh() {
      this.startupDate = System.currentTimeMillis();
      this.closed.set(false);
      this.active.set(true);

      if (logger.isInfoEnabled()) {
         logger.info("Refreshing " + this);
      }

      // Initialize any placeholder property sources in the context environment
      initPropertySources();

      // Validate that all properties marked as required are resolvable
      // see ConfigurablePropertyResolver#setRequiredProperties
      getEnvironment().validateRequiredProperties();

      // Allow for the collection of early ApplicationEvents,
      // to be published once the multicaster is available...
      this.earlyApplicationEvents = new LinkedHashSet<ApplicationEvent>();
   }

   /**
    * <p>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();
      ConfigurableListableBeanFactory beanFactory = getBeanFactory();
      if (logger.isDebugEnabled()) {
         logger.debug("Bean factory for " + getDisplayName() + ": " + beanFactory);
      }
      return beanFactory;
   }

   /**
    * 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(ResourceLoaderAware.class);
      beanFactory.ignoreDependencyInterface(ApplicationEventPublisherAware.class);
      beanFactory.ignoreDependencyInterface(MessageSourceAware.class);
      beanFactory.ignoreDependencyInterface(ApplicationContextAware.class);
      beanFactory.ignoreDependencyInterface(EnvironmentAware.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);

      // Detect a LoadTimeWeaver and prepare for weaving, if found.
      if (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());
      }
   }

   /**
    * 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.
    * <p>Must be called before singleton instantiation.
    */
   protected void invokeBeanFactoryPostProcessors(ConfigurableListableBeanFactory beanFactory) {
      PostProcessorRegistrationDelegate.invokeBeanFactoryPostProcessors(beanFactory, getBeanFactoryPostProcessors());
   }

   /**
    * Instantiate and invoke all registered BeanPostProcessor beans,
    * respecting explicit order if given.
    * <p>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) {
            HierarchicalMessageSource hms = (HierarchicalMessageSource) this.messageSource;
            if (hms.getParentMessageSource() == null) {
               // Only set parent context as parent MessageSource if no parent MessageSource
               // registered already.
               hms.setParentMessageSource(getInternalParentMessageSource());
            }
         }
         if (logger.isDebugEnabled()) {
            logger.debug("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.isDebugEnabled()) {
            logger.debug("Unable to locate MessageSource with name '" + MESSAGE_SOURCE_BEAN_NAME +
                  "': using default [" + 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.isDebugEnabled()) {
            logger.debug("Using ApplicationEventMulticaster [" + this.applicationEventMulticaster + "]");
         }
      }
      else {
         this.applicationEventMulticaster = new SimpleApplicationEventMulticaster(beanFactory);
         beanFactory.registerSingleton(APPLICATION_EVENT_MULTICASTER_BEAN_NAME, this.applicationEventMulticaster);
         if (logger.isDebugEnabled()) {
            logger.debug("Unable to locate ApplicationEventMulticaster with name '" +
                  APPLICATION_EVENT_MULTICASTER_BEAN_NAME +
                  "': using default [" + this.applicationEventMulticaster + "]");
         }
      }
   }

   /**
    * 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.isDebugEnabled()) {
            logger.debug("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.isDebugEnabled()) {
            logger.debug("Unable to locate LifecycleProcessor with name '" +
                  LIFECYCLE_PROCESSOR_BEAN_NAME +
                  "': using default [" + this.lifecycleProcessor + "]");
         }
      }
   }

   /**
    * Template method which can be overridden to add context-specific refresh work.
    * Called on initialization of special beans, before instantiation of singletons.
    * <p>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<ApplicationEvent> earlyEventsToProcess = this.earlyApplicationEvents;
      this.earlyApplicationEvents = null;
      if (earlyEventsToProcess != null) {
         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));
      }

      // 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}.
    */
   protected void finishRefresh() {
      // Initialize lifecycle processor for this context.
      initLifecycleProcessor();

      // Propagate refresh to lifecycle processor first.
      getLifecycleProcessor().onRefresh();

      // Publish the final event.
      publishEvent(new ContextRefreshedEvent(this));

      // Participate in LiveBeansView MBean, if active.
      LiveBeansView.registerApplicationContext(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 core caches, in particular the {@link ReflectionUtils},
    * {@link ResolvableType} and {@link CachedIntrospectionResults} caches.
    * @since 4.2
    * @see ReflectionUtils#clearCache()
    * @see ResolvableType#clearCache()
    * @see CachedIntrospectionResults#clearClassLoader(ClassLoader)
    */
   protected void resetCommonCaches() {
      ReflectionUtils.clearCache();
      ResolvableType.clearCache();
      CachedIntrospectionResults.clearClassLoader(getClassLoader());
   }


   /**
    * Register a shutdown hook with the JVM runtime, closing this context
    * on JVM shutdown unless it has already been closed at that time.
    * <p>Delegates to {@code doClose()} for the actual closing procedure.
    * @see Runtime#addShutdownHook
    * @see #close()
    * @see #doClose()
    */
   @Override
   public void registerShutdownHook() {
      if (this.shutdownHook == null) {
         // No shutdown hook registered yet.
         this.shutdownHook = new Thread() {
            @Override
            public void run() {
               synchronized (startupShutdownMonitor) {
                  doClose();
               }
            }
         };
         Runtime.getRuntime().addShutdownHook(this.shutdownHook);
      }
   }

   /**
    * DisposableBean callback for destruction of this instance.
    * Only called when the ApplicationContext itself is running
    * as a bean in another BeanFactory or ApplicationContext,
    * which is rather unusual.
    * <p>The {@code close} method is the native way to
    * shut down an ApplicationContext.
    * @see #close()
    * @see org.springframework.beans.factory.access.SingletonBeanFactoryLocator
    */
   @Override
   public void destroy() {
      close();
   }

   /**
    * Close this application context, destroying all beans in its bean factory.
    * <p>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.
    * <p>Called by both {@code close()} and a JVM shutdown hook, if any.
    * @see org.springframework.context.event.ContextClosedEvent
    * @see #destroyBeans()
    * @see #close()
    * @see #registerShutdownHook()
    */
   protected void doClose() {
      if (this.active.get() && this.closed.compareAndSet(false, true)) {
         if (logger.isInfoEnabled()) {
            logger.info("Closing " + this);
         }

         LiveBeansView.unregisterApplicationContext(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.
         try {
            getLifecycleProcessor().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();

         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".
    * <p>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.
    * <p>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.
    * <p>Invoked by all {@link BeanFactory} delegation methods that depend
    * on an active context, i.e. in particular all bean accessor methods.
    * <p>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> T getBean(String name, Class<T> requiredType) throws BeansException {
      assertBeanFactoryActive();
      return getBeanFactory().getBean(name, requiredType);
   }

   @Override
   public <T> T getBean(Class<T> requiredType) throws BeansException {
      assertBeanFactoryActive();
      return getBeanFactory().getBean(requiredType);
   }

   @Override
   public Object getBean(String name, Object... args) throws BeansException {
      assertBeanFactoryActive();
      return getBeanFactory().getBean(name, args);
   }

   @Override
   public <T> T getBean(Class<T> requiredType, Object... args) throws BeansException {
      assertBeanFactoryActive();
      return getBeanFactory().getBean(requiredType, args);
   }

   @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
   public Class<?> getType(String name) throws NoSuchBeanDefinitionException {
      assertBeanFactoryActive();
      return getBeanFactory().getType(name);
   }

   @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 String[] getBeanNamesForType(ResolvableType type) {
      assertBeanFactoryActive();
      return getBeanFactory().getBeanNamesForType(type);
   }

   @Override
   public String[] getBeanNamesForType(Class<?> type) {
      assertBeanFactoryActive();
      return getBeanFactory().getBeanNamesForType(type);
   }

   @Override
   public String[] getBeanNamesForType(Class<?> type, boolean includeNonSingletons, boolean allowEagerInit) {
      assertBeanFactoryActive();
      return getBeanFactory().getBeanNamesForType(type, includeNonSingletons, allowEagerInit);
   }

   @Override
   public <T> Map<String, T> getBeansOfType(Class<T> type) throws BeansException {
      assertBeanFactoryActive();
      return getBeanFactory().getBeansOfType(type);
   }

   @Override
   public <T> Map<String, T> getBeansOfType(Class<T> type, boolean includeNonSingletons, boolean allowEagerInit)
         throws BeansException {

      assertBeanFactoryActive();
      return getBeanFactory().getBeansOfType(type, includeNonSingletons, allowEagerInit);
   }

   @Override
   public String[] getBeanNamesForAnnotation(Class<? extends Annotation> annotationType) {
      assertBeanFactoryActive();
      return getBeanFactory().getBeanNamesForAnnotation(annotationType);
   }

   @Override
   public Map<String, Object> getBeansWithAnnotation(Class<? extends Annotation> annotationType)
         throws BeansException {

      assertBeanFactoryActive();
      return getBeanFactory().getBeansWithAnnotation(annotationType);
   }

   @Override
   public <A extends Annotation> A findAnnotationOnBean(String beanName, Class<A> annotationType)
         throws NoSuchBeanDefinitionException{

      assertBeanFactoryActive();
      return getBeanFactory().findAnnotationOnBean(beanName, annotationType);
   }


   //---------------------------------------------------------------------
   // Implementation of HierarchicalBeanFactory interface
   //---------------------------------------------------------------------

   @Override
   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
    */
   protected BeanFactory getInternalParentBeanFactory() {
      return (getParent() instanceof ConfigurableApplicationContext) ?
            ((ConfigurableApplicationContext) getParent()).getBeanFactory() : getParent();
   }


   //---------------------------------------------------------------------
   // Implementation of MessageSource interface
   //---------------------------------------------------------------------

   @Override
   public String getMessage(String code, Object args[], String defaultMessage, Locale locale) {
      return getMessageSource().getMessage(code, args, defaultMessage, locale);
   }

   @Override
   public String getMessage(String code, 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.
    */
   protected MessageSource getInternalParentMessageSource() {
      return (getParent() instanceof AbstractApplicationContext) ?
         ((AbstractApplicationContext) getParent()).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.
    * <p>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.
    * <p>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.
    * <p>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(": startup date [").append(new Date(getStartupDate()));
      sb.append("]; ");
      ApplicationContext parent = getParent();
      if (parent == null) {
         sb.append("root of context hierarchy");
      }
      else {
         sb.append("parent: ").append(parent.getDisplayName());
      }
      return sb.toString();
   }

}
相關文章
相關標籤/搜索