Spring容器初始化

因为WebApplicationContext 需要ServletContext 实例,也就是说它必须在拥有Web 容器的前提下才能完成启动的工作。有过Web 开发经验的读者都知道可以在web.xml 中配置自启动的Servlet 或定义Web 容器监听器(ServletContextListener),借助这两者中的任何一个,我们就可以完成启动Spring Web 应用上下文的工作。


    Spring 分别提供了用于启动WebApplicationContext 的Servlet 和Web 容器监听器:
   org.springframework.web.context.ContextLoaderServlet;
   org.springframework.web.context.ContextLoaderListener。
两者的内部都实现了启动WebApplicationContext 实例的逻辑,我们只要根据Web 容器的具体情况选择两者之一,并在web.xml 中完成配置就可以了。

以下以ContextLoaderListener为例子说明


ContextLoaderListener相关配置的注意事项看Spring笔记1——控制反转容器


那通过ContextLoaderListener,Spring是怎么怎么初始化和配置Spring容器(WebApplicationContext)的呢?

Spring容器的初始化过程:


接下来再详细从代码上介绍吧

ContextLoaderListener的体系结构


部署spring例子到tomcat,运行tomcat



这里开始了ContextLoaderListener的工作了,首先是Spring容器(这里是WebApplicationContext)的初始化
[java]  view plain copy print ? 在CODE上查看代码片 派生到我的代码片
  1. <span style="font-size:18px;"> ContextLoader         
  2.        /** 
  3.      * Initialize the root web application context. 
  4.      */  
  5.     @Override  
  6.     public void contextInitialized(ServletContextEvent event) {  
  7.         initWebApplicationContext(event.getServletContext());  
  8.     }</span>  

再看一下ContextLoader的initWebApplicationContext()
[java]  view plain copy print ? 在CODE上查看代码片 派生到我的代码片
  1. <span style="font-size:18px;">ContextLoader  
  2. public WebApplicationContext initWebApplicationContext(ServletContext servletContext) {  
  3.         if (servletContext.getAttribute(WebApplicationContext.ROOT_WEB_APPLICATION_CONTEXT_ATTRIBUTE) != null) {  
  4.             throw new IllegalStateException(  
  5.                     "Cannot initialize context because there is already a root application context present - " +  
  6.                     "check whether you have multiple ContextLoader* definitions in your web.xml!");  
  7.         }  
  8.   
  9.         Log logger = LogFactory.getLog(ContextLoader.class);  
  10.         servletContext.log("Initializing Spring root WebApplicationContext");  
  11.         if (logger.isInfoEnabled()) {  
  12.             logger.info("Root WebApplicationContext: initialization started");  
  13.         }  
  14.         long startTime = System.currentTimeMillis();  
  15.   
  16.         try {  
  17.             // Store context in local instance variable, to guarantee that  
  18.             // it is available on ServletContext shutdown.  
  19.             if (this.context == null) {  
  20.                 this.context = createWebApplicationContext(servletContext);      //这里根据ServletContext创建Spring容器(在这里创建的是XmlWebApplicationContext)  
  21.             }  
  22.             if (this.context instanceof ConfigurableWebApplicationContext) {  
  23.                 ConfigurableWebApplicationContext cwac = (ConfigurableWebApplicationContext) this.context;  
  24.                 if (!cwac.isActive()) {  
  25.                     // The context has not yet been refreshed -> provide services such as  
  26.                     // setting the parent context, setting the application context id, etc  
  27.                     if (cwac.getParent() == null) {  
  28.                         // The context instance was injected without an explicit parent ->  
  29.                         // determine parent for root web application context, if any.  
  30.                         ApplicationContext parent = loadParentContext(servletContext);  
  31.                         cwac.setParent(parent);  
  32.                     }  
  33.                     configureAndRefreshWebApplicationContext(cwac, servletContext);  //这里进行WebApplicationContext的配置工作,其中包括把servletContext和Spring容器关联起来,以及将配置文件(applicationContext.xml)加入到容器中  
  34.                 }  
  35.             }  
  36.             servletContext.setAttribute(WebApplicationContext.ROOT_WEB_APPLICATION_CONTEXT_ATTRIBUTE, this.context);  
  37.   
  38.             ClassLoader ccl = Thread.currentThread().getContextClassLoader();  
  39.             if (ccl == ContextLoader.class.getClassLoader()) {  
  40.                 currentContext = this.context;  
  41.             }  
  42.             else if (ccl != null) {  
  43.                 currentContextPerThread.put(ccl, this.context);  
  44.             }  
  45.   
  46.             if (logger.isDebugEnabled()) {  
  47.                 logger.debug("Published root WebApplicationContext as ServletContext attribute with name [" +  
  48.                         WebApplicationContext.ROOT_WEB_APPLICATION_CONTEXT_ATTRIBUTE + "]");  
  49.             }  
  50.             if (logger.isInfoEnabled()) {  
  51.                 long elapsedTime = System.currentTimeMillis() - startTime;  
  52.                 logger.info("Root WebApplicationContext: initialization completed in " + elapsedTime + " ms");  
  53.             }  
  54.   
  55.             return this.context;  
  56.         }  
  57.         catch (RuntimeException ex) {  
  58.             logger.error("Context initialization failed", ex);  
  59.             servletContext.setAttribute(WebApplicationContext.ROOT_WEB_APPLICATION_CONTEXT_ATTRIBUTE, ex);  
  60.             throw ex;  
  61.         }  
  62.         catch (Error err) {  
  63.             logger.error("Context initialization failed", err);  
  64.             servletContext.setAttribute(WebApplicationContext.ROOT_WEB_APPLICATION_CONTEXT_ATTRIBUTE, err);  
  65.             throw err;  
  66.         }  
  67.     }</span>  

再进入createWebApplicationContext()
[java]  view plain copy print ? 在CODE上查看代码片 派生到我的代码片
  1. <span style="font-size:18px;">//ContextLoader  
  2. protected WebApplicationContext createWebApplicationContext(ServletContext sc) {  
  3.         Class<?> contextClass = determineContextClass(sc); //返回WebApplicationContext实现类使用,默认XmlWebApplicationContext或如果指定一个自定义上下文类。  
  4.         if (!ConfigurableWebApplicationContext.class.isAssignableFrom(contextClass)) {  
  5.             throw new ApplicationContextException("Custom context class [" + contextClass.getName() +  
  6.                     "] is not of type [" + ConfigurableWebApplicationContext.class.getName() + "]");  
  7.         }  
  8.         return (ConfigurableWebApplicationContext) BeanUtils.instantiateClass(contextClass);  
  9.     }</span>  


再看determineConetxt()


可以看到在这里其实就是根据Parameter CONTEXT_CLASSPARAM去实例化一个WebApplicatoinContext,而该参数其实在web.xml已经配置为XmlWebApplicationContext(WebApplicationContext实现类) ,看web.xml
[java]  view plain copy print ? 在CODE上查看代码片 派生到我的代码片
  1. <span style="font-size:18px;">//web.xml  
  2. <!-- 如果配置了contextClass上下文参数,就会用参数所指定的WebApplicationContext实现类初始话容器 -->  
  3.   <context-param>  
  4.     <param-name>contextClass</param-name>  
  5.     <param-value>  
  6.     org.springframework.web.context.support.XmlWebApplicationContext  
  7.     </param-value>  
  8.   </context-param></span>  

接着,我们回到initWebApplicationContext(),其中调用的configureAndRefreshWebApplicationContext(cwac, servletContext);我们看一下他的实现
[java]  view plain copy print ? 在CODE上查看代码片 派生到我的代码片
  1. <span style="font-size:18px;">protected void configureAndRefreshWebApplicationContext(ConfigurableWebApplicationContext wac, ServletContext sc) {  
  2.         if (ObjectUtils.identityToString(wac).equals(wac.getId())) {  
  3.             // The application context id is still set to its original default value  
  4.             // -> assign a more useful id based on available information  
  5.             String idParam = sc.getInitParameter(CONTEXT_ID_PARAM);      
  6.             if (idParam != null) {  
  7.                 wac.setId(idParam);    //这里设置WebApplicationContext的id值为contextId也就是我们浏览器访问的localhost:8080/01/中的01  
  8.             }  
  9.             else {  
  10.                 // Generate default id...  
  11.                 wac.setId(ConfigurableWebApplicationContext.APPLICATION_CONTEXT_ID_PREFIX +  
  12.                         ObjectUtils.getDisplayString(sc.getContextPath()));  
  13.             }  
  14.         }  
  15.   
  16.         wac.setServletContext(sc);  
  17.         String initParameter = sc.getInitParameter(CONFIG_LOCATION_PARAM);//这里设置Web.xml中配置的contextConfigLocation参数,也就是配置文件applicationContext.xml了  
  18.         if (initParameter != null) {  
  19.             wac.setConfigLocation(initParameter);  
  20.         }  
  21.         customizeContext(sc, wac);  
  22.         wac.refresh();   //加载刚才的配置文件applicationContext.xml,以及bean的实例化  
  23.     }</span>  
看一下web.xml中的contextConfigLocation设置吧


再看一下
[java]  view plain copy print ? 在CODE上查看代码片 派生到我的代码片
  1. <span style="font-size:18px;">//XmlWebApplicationContext  
  2. @Override  
  3.     public void refresh() throws BeansException, IllegalStateException {  
  4.         synchronized (this.startupShutdownMonitor) {  
  5.             // Prepare this context for refreshing.  
  6.             prepareRefresh();  
  7.   
  8.             // Tell the subclass to refresh the internal bean factory.  
  9.             ConfigurableListableBeanFactory beanFactory = obtainFreshBeanFactory();  
  10.   
  11.             // Prepare the bean factory for use in this context.  
  12.             prepareBeanFactory(beanFactory);  
  13.   
  14.             try {  
  15.                 // Allows post-processing of the bean factory in context subclasses.  
  16.                 postProcessBeanFactory(beanFactory);  
  17.   
  18.                 // Invoke factory processors registered as beans in the context.  
  19.                 invokeBeanFactoryPostProcessors(beanFactory);  
  20.   
  21.                 // Register bean processors that intercept bean creation.  
  22.                 registerBeanPostProcessors(beanFactory);  
  23.   
  24.                 // Initialize message source for this context.  
  25.                 initMessageSource();  
  26.   
  27.                 // Initialize event multicaster for this context.  
  28.                 initApplicationEventMulticaster();  
  29.   
  30.                 // Initialize other special beans in specific context subclasses.  
  31.                 onRefresh();  
  32.   
  33.                 // Check for listener beans and register them.  
  34.                 registerListeners();  
  35.   
  36.                 // Instantiate all remaining (non-lazy-init) singletons.  
  37.                 finishBeanFactoryInitialization(beanFactory);  
  38.   
  39.                 // Last step: publish corresponding event.  
  40.                 finishRefresh();  
  41.             }  
  42.   
  43.             catch (BeansException ex) {  
  44.                 // Destroy already created singletons to avoid dangling resources.  
  45.                 destroyBeans();  
  46.   
  47.                 // Reset 'active' flag.  
  48.                 cancelRefresh(ex);  
  49.   
  50.                 // Propagate exception to caller.  
  51.                 throw ex;  
  52.             }  
  53.         }  
  54.     }</span>  

这个方法就是配置Spirng Web容器,根据applicationContext.xml实例化类的重中之重

接着我们继续看WebApplicationContext的refresh()方法

先看一下他的顺序图





[java]  view plain copy print ? 在CODE上查看代码片 派生到我的代码片
  1. //AbstractApplicationContext XmlWebApplicationContext的父类  
  2. @Override  
  3.     public void refresh() throws BeansException, IllegalStateException {  
  4.         synchronized (this.startupShutdownMonitor) {  
  5.             // 准备容器的更新  
  6.             prepareRefresh();  
  7.   
  8.             // 告诉子类刷新内部bean工厂  
  9.             ConfigurableListableBeanFactory beanFactory = obtainFreshBeanFactory();  
  10.   
  11.             // 配置factory的标准容器特征,包括classloader和postprocessor等  
  12.             prepareBeanFactory(beanFactory);  
  13.   
  14.             try {  
  15.                 // 修改应用程序上下文的内部bean工厂标准后初始化。所有bean定义将被加载,但没有实例化bean。这允许在某些ApplicationContext实现类注册特殊BeanPostProcessors  
  16.                 postProcessBeanFactory(beanFactory);  
  17.   
  18.                 // 实例化<span style="font-family: Arial, Helvetica, sans-serif;">所有注册到</span><span style="font-family: Arial, Helvetica, sans-serif;">BeanFactoryPostProcessor的bean,如果有次序,就按照次序实例化,必须在单例实例化之前</span>  
  19.                 invokeBeanFactoryPostProcessors(beanFactory);  
  20.   
  21.                 // 实例化并调用所有注册BeanPostProcessor的bean<span style="font-family: Arial, Helvetica, sans-serif;">,如果有次序,就按照次序实例化。</span> 必须在 application bean的实例化之前调用。  
  22.                 registerBeanPostProcessors(beanFactory);  
  23.   
  24.                 // 实例化MessageSource()  
  25.                 initMessageSource();  
  26.   
  27.                 // 实例化ApplicationEventMulticaster  
  28.                 initApplicationEventMulticaster();  
  29.   
  30.                 // 实例化容器中特殊的类  
  31.                 onRefresh();  
  32.   
  33.                 // 注册实现ApplicationListener的listener  
  34.                 registerListeners();  
  35.   
  36.                 // 完成容器的beanFactory的实例化,初始化所有剩余单例bean  
  37.                 finishBeanFactoryInitialization(beanFactory);  
  38.   
  39.                 //调用LifecycleProcessor的onRefresh()以及发布 org.springframework.context.event.ContextRefreshedEvent。  
  40.                 finishRefresh();  
  41.             }  
  42.   
  43.             catch (BeansException ex) {  
  44.                 // Destroy already created singletons to avoid dangling resources.  
  45.                 destroyBeans();  
  46.   
  47.                 // Reset 'active' flag.  
  48.                 cancelRefresh(ex);  
  49.   
  50.                 // Propagate exception to caller.  
  51.                 throw ex;  
  52.             }  
  53.         }  
  54.     }  


先看refresh()方法中的prepareBeanFactory()

[java]  view plain copy print ? 在CODE上查看代码片 派生到我的代码片
  1. //AbstractApplicationContext  
  2. protected void prepareBeanFactory(ConfigurableListableBeanFactory beanFactory) {  
  3.         // Tell the internal bean factory to use the context's class loader etc.  
  4.         beanFactory.setBeanClassLoader(getClassLoader());  
  5.         beanFactory.setBeanExpressionResolver(new StandardBeanExpressionResolver());  
  6.         beanFactory.addPropertyEditorRegistrar(new ResourceEditorRegistrar(this, getEnvironment()));  
  7.   
  8.         // Configure the bean factory with context callbacks.  
  9.         beanFactory.addBeanPostProcessor(new ApplicationContextAwareProcessor(this));  
  10.         beanFactory.ignoreDependencyInterface(ResourceLoaderAware.class);  
  11.         beanFactory.ignoreDependencyInterface(ApplicationEventPublisherAware.class);  
  12.         beanFactory.ignoreDependencyInterface(MessageSourceAware.class);  
  13.         beanFactory.ignoreDependencyInterface(ApplicationContextAware.class);  
  14.         beanFactory.ignoreDependencyInterface(EnvironmentAware.class);  
  15.   
  16.         // BeanFactory interface not registered as resolvable type in a plain factory.  
  17.         // MessageSource registered (and found for autowiring) as a bean.  
  18.         beanFactory.registerResolvableDependency(BeanFactory.class, beanFactory);  
  19.         beanFactory.registerResolvableDependency(ResourceLoader.classthis);  
  20.         beanFactory.registerResolvableDependency(ApplicationEventPublisher.classthis);  
  21.         beanFactory.registerResolvableDependency(ApplicationContext.classthis);  
  22.   
  23.         // Detect a LoadTimeWeaver and prepare for weaving, if found.  
  24.         if (beanFactory.containsBean(LOAD_TIME_WEAVER_BEAN_NAME)) {  
  25.             beanFactory.addBeanPostProcessor(new LoadTimeWeaverAwareProcessor(beanFactory));  
  26.             // Set a temporary ClassLoader for type matching.  
  27.             beanFactory.setTempClassLoader(new ContextTypeMatchClassLoader(beanFactory.getBeanClassLoader()));  
  28.         }  
  29.   
  30.         // Register default environment beans.  
  31.         if (!beanFactory.containsLocalBean(ENVIRONMENT_BEAN_NAME)) {  
  32.             beanFactory.registerSingleton(ENVIRONMENT_BEAN_NAME, getEnvironment());  
  33.         }  
  34.         if (!beanFactory.containsLocalBean(SYSTEM_PROPERTIES_BEAN_NAME)) {  
  35.             beanFactory.registerSingleton(SYSTEM_PROPERTIES_BEAN_NAME, getEnvironment().getSystemProperties());  
  36.         }  
  37.         if (!beanFactory.containsLocalBean(SYSTEM_ENVIRONMENT_BEAN_NAME)) {  
  38.             beanFactory.registerSingleton(SYSTEM_ENVIRONMENT_BEAN_NAME, getEnvironment().getSystemEnvironment());  
  39.         }  
  40.     }  

这里都是为beanFactory(也就是DefaultListableBeanFactory)设置一些属性


我们再看一下ConfigurableListableBeanFactory beanFactory = obtainFreshBeanFactory();里面的操作

[java]  view plain copy print ? 在CODE上查看代码片 派生到我的代码片
  1. //AbstractApplicationContext  
  2. /** 
  3.      * Tell the subclass to refresh the internal bean factory. 
  4.      * @return the fresh BeanFactory instance 
  5.      * @see #refreshBeanFactory() 
  6.      * @see #getBeanFactory() 
  7.      */  
  8.     protected ConfigurableListableBeanFactory obtainFreshBeanFactory() {  
  9.         refreshBeanFactory();    //创建一个DefaultListableBeanFactory,并加载类,实例化为对应的BeanDefinition  
  10.         ConfigurableListableBeanFactory beanFactory = getBeanFactory();   //取得该DefaultListableBeanFactory,后面返回  
  11.         if (logger.isDebugEnabled()) {  
  12.             logger.debug("Bean factory for " + getDisplayName() + ": " + beanFactory);  
  13.         }  
  14.         return beanFactory;  
  15.     }  

我们在看一下refreshBeanFactory()


[java]  view plain copy print ? 在CODE上查看代码片 派生到我的代码片
  1. //AbstractRefreshableApplicationContext  
  2. /** 
  3.      * This implementation performs an actual refresh of this context's underlying 
  4.      * bean factory, shutting down the previous bean factory (if any) and 
  5.      * initializing a fresh bean factory for the next phase of the context's lifecycle. 
  6.      */  
  7.     @Override  
  8.     protected final void refreshBeanFactory() throws BeansException {  
  9.         if (hasBeanFactory()) {  
  10.             destroyBeans();  
  11.             closeBeanFactory();  
  12.         }  
  13.         try {  
  14.             DefaultListableBeanFactory beanFactory = createBeanFactory();  //这里创建了一个DefaultListableBeanFactory,供后面实例化bean  
  15.             beanFactory.setSerializationId(getId());  
  16.             customizeBeanFactory(beanFactory);  
  17.             loadBeanDefinitions(beanFactory);               
  18.             synchronized (this.beanFactoryMonitor) {  
  19.                 this.beanFactory = beanFactory;  
  20.             }  
  21.         }  
  22.         catch (IOException ex) {  
  23.             throw new ApplicationContextException("I/O error parsing bean definition source for " + getDisplayName(), ex);  
  24.         }  
  25.     }  

我们在进入看loadBeanDefinitions()

[java]  view plain copy print ? 在CODE上查看代码片 派生到我的代码片
  1. //XmlWebApplicationContext  
  2. /** 
  3.      * Loads the bean definitions via an XmlBeanDefinitionReader. 
  4.      * @see org.springframework.beans.factory.xml.XmlBeanDefinitionReader 
  5.      * @see #initBeanDefinitionReader 
  6.      * @see #loadBeanDefinitions 
  7.      */  
  8.     @Override  
  9.     protected void loadBeanDefinitions(DefaultListableBeanFactory beanFactory) throws BeansException, IOException {  
  10.         // Create a new XmlBeanDefinitionReader for the given BeanFactory.  
  11.         XmlBeanDefinitionReader beanDefinitionReader = new XmlBeanDefinitionReader(beanFactory);  
  12.   
  13.         // 这里为beanDefinitionReader配置容器的属性  
  14.         beanDefinitionReader.setEnvironment(this.getEnvironment());  
  15.         beanDefinitionReader.setResourceLoader(this);  
  16.         beanDefinitionReader.setEntityResolver(new ResourceEntityResolver(this));  
  17.   
  18.   
  19.         initBeanDefinitionReader(beanDefinitionReader);     //这个方法其实是空的,留给以后subclass去实现  
  20.         loadBeanDefinitions(beanDefinitionReader);         //这里开始加载BeanDefinition了  
  21.     }  

我们再进入loadBeanDefinitions()

[java]  view plain copy print ? 在CODE上查看代码片 派生到我的代码片
  1. //XmlWebApplicationContext  
  2. /** 
  3.      * Load the bean definitions with the given XmlBeanDefinitionReader. 
  4.      * <p>The lifecycle of the bean factory is handled by the refreshBeanFactory method; 
  5.      * therefore this method is just supposed to load and/or register bean definitions. 
  6.      * <p>Delegates to a ResourcePatternResolver for resolving location patterns 
  7.      * into Resource instances. 
  8.      * @throws java.io.IOException if the required XML document isn't found 
  9.      * @see #refreshBeanFactory 
  10.      * @see #getConfigLocations 
  11.      * @see #getResources 
  12.      * @see #getResourcePatternResolver 
  13.      */  
  14.     protected void loadBeanDefinitions(XmlBeanDefinitionReader reader) throws IOException {  
  15.         String[] configLocations = getConfigLocations();   //这里开始读取配置文件了,就是我们之前的applicationContext.xml的配置文件了  
  16.         if (configLocations != null) {  
  17.             for (String configLocation : configLocations) {  
  18.                 reader.loadBeanDefinitions(configLocation); //这里就开始加载配置文件中的bean了,实例化成beandefinition  
  19.             }  
  20.         }  
  21.     }  

reader.loadBeanDefinitions(configLocation)

[java]  view plain copy print ? 在CODE上查看代码片 派生到我的代码片
  1. //AbstractBeanDefinitionReader  
  2. public int loadBeanDefinitions(String location, Set<Resource> actualResources) throws BeanDefinitionStoreException {  
  3.         ResourceLoader resourceLoader = getResourceLoader();  
  4.         if (resourceLoader == null) {  
  5.             throw new BeanDefinitionStoreException(  
  6.                     "Cannot import bean definitions from location [" + location + "]: no ResourceLoader available");  
  7.         }  
  8.   
  9.         if (resourceLoader instanceof ResourcePatternResolver) {  
  10.             // Resource pattern matching available.  
  11.             try {  
  12.                 Resource[] resources = ((ResourcePatternResolver) resourceLoader).getResources(location);  
  13.                 int loadCount = loadBeanDefinitions(resources); //这里就是加载了,返回加载类的数目  
  14.                 if (actualResources != null) {  
  15.                     for (Resource resource : resources) {  
  16.                         actualResources.add(resource);  
  17.                     }  
  18.                 }  
  19.                 if (logger.isDebugEnabled()) {  
  20.                     logger.debug("Loaded " + loadCount + " bean definitions from location pattern [" + location + "]");  
  21.                 }  
  22.                 return loadCount;  
  23.             }  
  24.             catch (IOException ex) {  
  25.                 throw new BeanDefinitionStoreException(  
  26.                         "Could not resolve bean definition resource pattern [" + location + "]", ex);  
  27.             }  
  28.         }  
  29.         else {  
  30.             // Can only load single resources by absolute URL.  
  31.             Resource resource = resourceLoader.getResource(location);  
  32.             int loadCount = loadBeanDefinitions(resource);  
  33.             if (actualResources != null) {  
  34.                 actualResources.add(resource);  
  35.             }  
  36.             if (logger.isDebugEnabled()) {  
  37.                 logger.debug("Loaded " + loadCount + " bean definitions from location [" + location + "]");  
  38.             }  
  39.             return loadCount;  
  40.         }  
  41.     }  


接着我们再看refresh()中的invokeBeanFactoryPostProcessors()


他最后交给DefaultListableBeanFactory去实例话那些注册到BeanFactoryPostProcessor的那些类


[java]  view plain copy print ? 在CODE上查看代码片 派生到我的代码片
  1. //DefaultListableBeanFactory  
  2. private String[] doGetBeanNamesForType(Class<?> type, boolean includeNonSingletons, boolean allowEagerInit) {  
  3.         List<String> result = new ArrayList<String>();  
  4.   
  5.         // 获得之前加载的类名  
  6.         String[] beanDefinitionNames = getBeanDefinitionNames();      
  7.         for (String beanName : beanDefinitionNames) {//遍历之前加载的全部类,并从中找出注册到<span style="font-family: 微软雅黑; font-size: 14.399999618530273px;">BeanFactoryPostProcessor的那些类,把他们加入到result,为下面实例化</span>  
  8.             // Only consider bean as eligible if the bean name  
  9.             // is not defined as alias for some other bean.  
  10.             if (!isAlias(beanName)) {  
  11.                 try {  
  12.                     RootBeanDefinition mbd = getMergedLocalBeanDefinition(beanName);  
  13.                     // Only check bean definition if it is complete.  
  14.                     if (!mbd.isAbstract() && (allowEagerInit ||  
  15.                             ((mbd.hasBeanClass() || !mbd.isLazyInit() || this.allowEagerClassLoading)) &&  
  16.                                     !requiresEagerInitForType(mbd.getFactoryBeanName()))) {  
  17.                         // In case of FactoryBean, match object created by FactoryBean.  
  18.                         boolean isFactoryBean = isFactoryBean(beanName, mbd);  
  19.                         boolean matchFound = (allowEagerInit || !isFactoryBean || containsSingleton(beanName)) &&  
  20.                                 (includeNonSingletons || isSingleton(beanName)) && isTypeMatch(beanName, type);  
  21.                         if (!matchFound && isFactoryBean) {  
  22.                             // In case of FactoryBean, try to match FactoryBean instance itself next.  
  23.                             beanName = FACTORY_BEAN_PREFIX + beanName;  
  24.                             matchFound = (includeNonSingletons || mbd.isSingleton()) && isTypeMatch(beanName, type);  
  25.                         }  
  26.                         if (matchFound) {  
  27.                             result.add(beanName);  
  28.                         }  
  29.                     }  
  30.                 }  
  31.                 catch (CannotLoadBeanClassException ex) {  
  32.                     if (allowEagerInit) {  
  33.                         throw ex;  
  34.                     }  
  35.                     // Probably contains a placeholder: let's ignore it for type matching purposes.  
  36.                     if (this.logger.isDebugEnabled()) {  
  37.                         this.logger.debug("Ignoring bean class loading failure for bean '" + beanName + "'", ex);  
  38.                     }  
  39.                     onSuppressedException(ex);  
  40.                 }  
  41.                 catch (BeanDefinitionStoreException ex) {  
  42.                     if (allowEagerInit) {  
  43.                         throw ex;  
  44.                     }  
  45.                     // Probably contains a placeholder: let's ignore it for type matching purposes.  
  46.                     if (this.logger.isDebugEnabled()) {  
  47.                         this.logger.debug("Ignoring unresolvable metadata in bean definition '" + beanName + "'", ex);  
  48.                     }  
  49.                     onSuppressedException(ex);  
  50.                 }  
  51.             }  
  52.         }  

这里,后面的refresh()的registerBeanPostProcessors(beanFactory)实例化过程是和之前的invokeBeanFactoryPostProcessors()一样的。


我们再来看refresh()的initMessageSource()

[java]  view plain copy print ? 在CODE上查看代码片 派生到我的代码片
  1. //AbstractApplicationContext  
  2. protected void initMessageSource() {  
  3.         ConfigurableListableBeanFactory beanFactory = getBeanFactory();  
  4.         if (beanFactory.containsLocalBean(MESSAGE_SOURCE_BEAN_NAME)) {   //如果配置文件applicationContext.xml有配置messageSource,就根据配置文件实例化  
  5.                         this.messageSource = beanFactory.getBean(MESSAGE_SOURCE_BEAN_NAME, MessageSource.class);  
  6.             // Make MessageSource aware of parent MessageSource.  
  7.             if (this.parent != null && this.messageSource instanceof HierarchicalMessageSource) {  
  8.                 HierarchicalMessageSource hms = (HierarchicalMessageSource) this.messageSource;  
  9.                 if (hms.getParentMessageSource() == null) {  
  10.                     // Only set parent context as parent MessageSource if no parent MessageSource  
  11.                     // registered already.  
  12.                     hms.setParentMessageSource(getInternalParentMessageSource());  
  13.                 }  
  14.             }  
  15.             if (logger.isDebugEnabled()) {  
  16.                 logger.debug("Using MessageSource [" + this.messageSource + "]");  
  17.             }  
  18.         }  
  19.         else {  
  20.             // Use empty MessageSource to be able to accept getMessage calls.  
  21.             DelegatingMessageSource dms = new DelegatingMessageSource();  
  22.             dms.setParentMessageSource(getInternalParentMessageSource());  
  23.             this.messageSource = dms;  
  24.             beanFactory.registerSingleton(MESSAGE_SOURCE_BEAN_NAME, this.messageSource);  
  25.             if (logger.isDebugEnabled()) {  
  26.                 logger.debug("Unable to locate MessageSource with name '" + MESSAGE_SOURCE_BEAN_NAME +  
  27.                         "': using default [" + this.messageSource + "]");  
  28.             }  
  29.         }  
  30.     }  

这里就是根据我们在配置文件applicationContext.xml中的时候有messagesource的配置,有的话就是实例化,没有的话就实例化一个DelegatingMessageSource,再把他设置到容器,在把他注册到单例集合中


接着,refresh()的initApplicationEventMulticaster()就是初始化ApplicationEventMulticaster。如果我们自己没有配置自定义的ApplicationEventMulticaster那就使用SimpleApplicationEventMulticaster



实例化思路还是和实例化messageSource差不多,都是从配置文件优先,如果没有明确配置就用默认的


接着,我们再来看refresh()的registerListener(),他就是先注册静态的容器本来级就应该有的类,然后在从我们之前加载的类中筛选listener,帅选实例化过程和之前的invokeBeanFactoryPostProcessors()实例化过程是一样的,接着在把listener加入到上面实例化的ApplicationEventMulticaster(它其实就是一个listener容器)中

[java]  view plain copy print ? 在CODE上查看代码片 派生到我的代码片
  1. //AbstractApplicationContext  
  2. protected void registerListeners() {  
  3.         // Register statically specified listeners first.  
  4.         for (ApplicationListener<?> listener : getApplicationListeners()) {  
  5.             getApplicationEventMulticaster().addApplicationListener(listener);  
  6.         }  
  7.         // Do not initialize FactoryBeans here: We need to leave all regular beans  
  8.         // uninitialized to let post-processors apply to them!  
  9.         String[] listenerBeanNames = getBeanNamesForType(ApplicationListener.classtruefalse);  
  10.         for (String lisName : listenerBeanNames) {  
  11.             getApplicationEventMulticaster().addApplicationListenerBean(lisName);  
  12.         }  
  13.     }  

接着就是refresh()的finishBeanFactoryInitialization()

[java]  view plain copy print ? 在CODE上查看代码片 派生到我的代码片
  1. //AbstractApplicationContext      
  2. /** 
  3.      * Finish the initialization of this context's bean factory, 
  4.      * initializing all remaining singleton beans. 
  5.      */  
  6.     protected void finishBeanFactoryInitialization(ConfigurableListableBeanFactory beanFactory) {  
  7.         // Initialize conversion service for this context.  
  8.         if (beanFactory.containsBean(CONVERSION_SERVICE_BEAN_NAME) &&  
  9.                 beanFactory.isTypeMatch(CONVERSION_SERVICE_BEAN_NAME, ConversionService.class)) {  
  10.             beanFactory.setConversionService(  
  11.                     beanFactory.getBean(CONVERSION_SERVICE_BEAN_NAME, ConversionService.class));  
  12.         }  
  13.   
  14.         // Initialize LoadTimeWeaverAware beans early to allow for registering their transformers early.  
  15.         String[] weaverAwareNames = beanFactory.getBeanNamesForType(LoadTimeWeaverAware.classfalsefalse);  
  16.         for (String weaverAwareName : weaverAwareNames) {  
  17.             getBean(weaverAwareName);  
  18.         }  
  19.   
  20.         // Stop using the temporary ClassLoader for type matching.  
  21.         beanFactory.setTempClassLoader(null);  
  22.   
  23.         // 允许缓存所有将不会被修改或进一步后期处理的bean定义元数据  
  24.         beanFactory.freezeConfiguration();  
  25.   
  26.         // 实例化所有剩下的单例bean  
  27.         beanFactory.preInstantiateSingletons();  
  28.     }  


再接着,refresh()的finishRefresh()


最后回到上篇博客中的initWebApplicationContext中

[java]  view plain copy print ? 在CODE上查看代码片 派生到我的代码片
  1. //ClassLoader  
  2. public WebApplicationContext initWebApplicationContext(ServletContext servletContext) {  
  3.         if (servletContext.getAttribute(WebApplicationContext.ROOT_WEB_APPLICATION_CONTEXT_ATTRIBUTE) != null) {  
  4.             throw new IllegalStateException(  
  5.                     "Cannot initialize context because there is already a root application context present - " +  
  6.                     "check whether you have multiple ContextLoader* definitions in your web.xml!");  
  7.         }  
  8.   
  9.         Log logger = LogFactory.getLog(ContextLoader.class);  
  10.         servletContext.log("Initializing Spring root WebApplicationContext");  
  11.         if (logger.isInfoEnabled()) {  
  12.             logger.info("Root WebApplicationContext: initialization started");  
  13.         }  
  14.         long startTime = System.currentTimeMillis();  
  15.   
  16.         try {  
  17.             // Store context in local instance variable, to guarantee that  
  18.             // it is available on ServletContext shutdown.  
  19.             if (this.context == null) {  
  20.                 this.context = createWebApplicationContext(servletContext);  
  21.             }  
  22.             if (this.context instanceof ConfigurableWebApplicationContext) {  
  23.                 ConfigurableWebApplicationContext cwac = (ConfigurableWebApplicationContext) this.context;  
  24.                 if (!cwac.isActive()) {  
  25.                     // The context has not yet been refreshed -> provide services such as  
  26.                     // setting the parent context, setting the application context id, etc  
  27.                     if (cwac.getParent() == null) {  
  28.                         // The context instance was injected without an explicit parent ->  
  29.                         // determine parent for root web application context, if any.  
  30.                         ApplicationContext parent = loadParentContext(servletContext);  
  31.                         cwac.setParent(parent);  
  32.                     }  
  33.                     configureAndRefreshWebApplicationContext(cwac, servletContext);  
  34.                 }  
  35.             }  
  36.             servletContext.setAttribute(WebApplicationContext.ROOT_WEB_APPLICATION_CONTEXT_ATTRIBUTE, this.context);  
  37.   
  38.             ClassLoader ccl = Thread.currentThread().getContextClassLoader();  
  39.             if (ccl == ContextLoader.class.getClassLoader()) {  
  40.                 currentContext = this.context;  
  41.             }  
  42.             else if (ccl != null) {  
  43.                 currentContextPerThread.put(ccl, this.context);  
  44.             }  
  45.   
  46.             if (logger.isDebugEnabled()) {  
  47.                 logger.debug("Published root WebApplicationContext as ServletContext attribute with name [" +  
  48.                         WebApplicationContext.ROOT_WEB_APPLICATION_CONTEXT_ATTRIBUTE + "]");  
  49.             }  
  50.             if (logger.isInfoEnabled()) {  
  51.                 long elapsedTime = System.currentTimeMillis() - startTime;  
  52.                 logger.info("Root WebApplicationContext: initialization completed in " + elapsedTime + " ms");  
  53.             }  
  54.   
  55.             return this.context;  
  56.         }  
  57.         catch (RuntimeException ex) {  
  58.             logger.error("Context initialization failed", ex);  
  59.             servletContext.setAttribute(WebApplicationContext.ROOT_WEB_APPLICATION_CONTEXT_ATTRIBUTE, ex);  
  60.             throw ex;  
  61.         }  
  62.         catch (Error err) {  
  63.             logger.error("Context initialization failed", err);  
  64.             servletContext.setAttribute(WebApplicationContext.ROOT_WEB_APPLICATION_CONTEXT_ATTRIBUTE, err);  
  65.             throw err;  
  66.         }  
  67.     }  

servletContext.setAttribute(WebApplicationContext.ROOT_WEB_APPLICATION_CONTEXT_ATTRIBUTE, this.context); 将容器设置为ServletContext的属性,之前我们已经这是了ServletContext作为WebApplicationContext的属性,于是,两者相关联,可以通过ServletContext.getAttribute(
WebApplicationContext.ROOT_WEB_APPLICATION_CONTEXT_ATTRIBUTE)获得容器


自此,Spring容器创建完毕


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值