国产一级a片免费看高清,亚洲熟女中文字幕在线视频,黄三级高清在线播放,免费黄色视频在线看

打開(kāi)APP
userphoto
未登錄

開(kāi)通VIP,暢享免費(fèi)電子書(shū)等14項(xiàng)超值服

開(kāi)通VIP
spring源碼研究之IoC容器在web容器中初始化過(guò)程 - ljbal - JavaEy...

spring源碼研究之IoC容器在web容器中初始化過(guò)程

    前段時(shí)間在公司做了一個(gè)項(xiàng)目,項(xiàng)目用了spring框架實(shí)現(xiàn),WEB容器是Tomct 5,雖然說(shuō)把項(xiàng)目做完了,但是一直對(duì)spring的IoC容器在web容器如何啟動(dòng)和起作用的并不清楚。所以就抽時(shí)間看一下spring的源代碼,借此了解它的原理。

    我們知道,對(duì)于使用Spring的web應(yīng)用,無(wú)須手動(dòng)創(chuàng)建Spring容器,而是通過(guò)配置文件,聲明式的創(chuàng)建Spring容器。因此在Web應(yīng)用中創(chuàng)建Spring容器有如下兩種方式:

    1. 直接在web.xml文件中配置創(chuàng)建Spring容器。

    2. 利用第三方MVC框架的擴(kuò)展點(diǎn),創(chuàng)建Spring容器。

    其實(shí)第一種方式是更加常見(jiàn)。為了讓Spring容器隨Web應(yīng)用的啟動(dòng)而啟動(dòng),有如下兩種方式:

    1. 利用ServletContextListener實(shí)現(xiàn)。

    2. 利用load-on-startup Servlet實(shí)現(xiàn)。

    Spring提供ServletContextListener的一個(gè)實(shí)現(xiàn)類(lèi)ContextLoaderListener,該類(lèi)可以作為L(zhǎng)istener 使用,它會(huì)在創(chuàng)建時(shí)自動(dòng)查找WEB-INF下的applicationContext.xml文件,因此,如果只有一個(gè)配置文件,并且文件名為applicationContext.xml,則只需在web.xml文件中增加以下配置片段就可以了。

   

Java代碼
  1. <listener>   
  2.       <listener-class>   
  3.      org.springframework.web.context.ContextLoaderListener   
  4.       </listener-class>   
  5. </listener>  

    如果有多個(gè)配置文件需要載入,則考慮使用<context-param...>元素來(lái)確定配置文件的文件名。ContextLoaderListener加載時(shí),會(huì)查找名為contentConfigLocation的初始化參數(shù)。因此,配置<context-param...>時(shí)就指定參數(shù)名為contextConfigLocation。

    帶多個(gè)配置文件的web.xml文件如下:

   

S代碼
  1. <context-param>     
  2.           <param-name>contextLoaderListener</param-name>   
  3.      <param-value>      
  4.                    WEB-INF/*.xml, classpath:spring/*.xml   
  5.                  </param-value>   
  6. </context-param>  
S代碼
  1. <listener>   
  2.       <listener-class>   
  3.      org.springframework.web.context.ContextLoaderListener   
  4.       </listener-class>   
  5. </listener>  

    多個(gè)配置文件之間用“,”隔開(kāi)。

 

    下面我們來(lái)看它的具體實(shí)現(xiàn)過(guò)程是怎樣的,首先我們從ContextLoaderListener入手,它的代碼如下:

   

Java代碼
  1. public class ContextLoaderListener implements ServletContextListener    
  2. {   
  3.   
  4.     private ContextLoader contextLoader;   
  5.   
  6.   
  7.     /**  
  8.      * 這個(gè)方法就是用來(lái)初始化web application context的  
  9.      */  
  10.     public void contextInitialized(ServletContextEvent event)    
  11.                 {   
  12.         this.contextLoader = createContextLoader();   
  13.         this.contextLoader.initWebApplicationContext(event.getServletContext());   
  14.     }   
  15.   
  16.     /**  
  17.      * 創(chuàng)建一個(gè)contextLoader.  
  18.      * @return the new ContextLoader  
  19.      */  
  20.     protected ContextLoader createContextLoader()   
  21.                 {   
  22.         return new ContextLoader();   
  23.     }   
  24.      ................   
  25.               
  26. }  

   我們看到初始化web application context的時(shí)候,首先通過(guò)new ContextLoader()創(chuàng)建一個(gè)contextLoader,

   new ContextLoader()具體做了什么事呢?ContextLoader的代碼片段:

   

Java代碼
  1. static {   
  2.     try {   
  3.         // 這里創(chuàng)建一個(gè)ClassPathResource對(duì)象,載入ContextLoader.properties,用于創(chuàng)建對(duì)應(yīng)的ApplicationContext容器   
  4.         // 這個(gè)文件跟ContextLoader類(lèi)在同一個(gè)目錄下,文件內(nèi)容如:   
  5.         // org.springframework.web.context.WebApplicationContext=org.springframework.web.context.support.XmlWebApplicationContext   
  6.         // 如此說(shuō)來(lái),spring默認(rèn)初始化的是XmlWebApplicationContext   
  7.         ClassPathResource resource = new ClassPathResource(DEFAULT_STRATEGIES_PATH, ContextLoader.class);   
  8.         // 得到一個(gè)Properties對(duì)象,后面根據(jù)類(lèi)名來(lái)創(chuàng)建ApplicationContext容器   
  9.         defaultStrategies = PropertiesLoaderUtils.loadProperties(resource);   
  10.            }   
  11.            catch (IOException ex) {   
  12.          throw new IllegalStateException("Could not load 'ContextLoader.properties': " + ex.getMessage());   
  13.            }   
  14.             }  

    代碼注釋里面已經(jīng)說(shuō)得很清楚了,很容易理解吧?嘿嘿......

    再下來(lái)我們?cè)倏匆幌耰nitWebApplicationContext方法的實(shí)現(xiàn)過(guò)程:

   

Java代碼
  1. public WebApplicationContext initWebApplicationContext(ServletContext servletContext)   
  2.             throws IllegalStateException, BeansException {   
  3.   
  4.         // 從servletContext中獲取ApplicationContext容器;如果已經(jīng)存在,則提示初始化容器失敗,檢查web.xml文件中是否定義有多個(gè)容器加載器   
  5.         // ServletContext接口的簡(jiǎn)述:public interface ServletContext   
  6.         // 定義了一系列方法用于與相應(yīng)的servlet容器通信,比如:獲得文件的MIME類(lèi)型,分派請(qǐng)求,或者是向日志文件寫(xiě)日志等。   
  7.         // 每一個(gè)web-app只能有一個(gè)ServletContext,web-app可以是一個(gè)放置有web application 文件的文件夾,也可以是一個(gè).war的文件。   
  8.         // ServletContext對(duì)象包含在ServletConfig對(duì)象之中,ServletConfig對(duì)象在servlet初始化時(shí)提供servlet對(duì)象。   
  9.   
  10.         if (servletContext.getAttribute(WebApplicationContext.ROOT_WEB_APPLICATION_CONTEXT_ATTRIBUTE) != null) {   
  11.             throw new IllegalStateException(   
  12.                     "Cannot initialize context because there is already a root application context present - " +   
  13.                     "check whether you have multiple ContextLoader* definitions in your web.xml!");   
  14.         }   
  15.   
  16.         servletContext.log("Initializing Spring root WebApplicationContext");   
  17.         if (logger.isInfoEnabled()) {   
  18.             logger.info("Root WebApplicationContext: initialization started");   
  19.         }   
  20.         long startTime = System.currentTimeMillis();   
  21.   
  22.         try {   
  23.             // Determine parent for root web application context, if any.   
  24.             // 獲取父容器   
  25.             ApplicationContext parent = loadParentContext(servletContext);   
  26.   
  27.             // Store context in local instance variable, to guarantee that   
  28.             // it is available on ServletContext shutdown.   
  29.             // 創(chuàng)建ApplicationContext容器   
  30.             this.context = createWebApplicationContext(servletContext, parent);   
  31.             // 把容器放入到servletContext中   
  32.             servletContext.setAttribute(WebApplicationContext.ROOT_WEB_APPLICATION_CONTEXT_ATTRIBUTE, this.context);   
  33.   
  34.             if (logger.isDebugEnabled()) {   
  35.                 logger.debug("Published root WebApplicationContext as ServletContext attribute with name [" +   
  36.                         WebApplicationContext.ROOT_WEB_APPLICATION_CONTEXT_ATTRIBUTE + "]");   
  37.             }   
  38.             if (logger.isInfoEnabled()) {   
  39.                 long elapsedTime = System.currentTimeMillis() - startTime;   
  40.                 logger.info("Root WebApplicationContext: initialization completed in " + elapsedTime + " ms");   
  41.             }   
  42.   
  43.             return this.context;   
  44.         }   
  45.         catch (RuntimeException ex) {   
  46.             logger.error("Context initialization failed", ex);   
  47.             servletContext.setAttribute(WebApplicationContext.ROOT_WEB_APPLICATION_CONTEXT_ATTRIBUTE, ex);   
  48.             throw ex;   
  49.         }   
  50.         catch (Error err) {   
  51.             logger.error("Context initialization failed", err);   
  52.             servletContext.setAttribute(WebApplicationContext.ROOT_WEB_APPLICATION_CONTEXT_ATTRIBUTE, err);   
  53.             throw err;   
  54.         }   
  55.     }  

 

    從上面的代碼可以看出,我們創(chuàng)建好的applicationContext容器會(huì)放在servletContext中。servletContext是什么  呢?

    在web容器中,通過(guò)ServletContext為Spring的IOC容器提供宿主環(huán)境,對(duì)應(yīng)的建立起一個(gè)IOC容器的體系。其中,首先需要建立的是根上下文,這個(gè)上下文持有的對(duì)象可以有業(yè)務(wù)對(duì)象,數(shù)據(jù)存取對(duì)象,資源,事物管理器等各種中間層對(duì)象。在這個(gè)上下文的基礎(chǔ)上,和web MVC相關(guān)還會(huì)有一個(gè)上下文來(lái)保存控制器之類(lèi)的MVC對(duì)象,這樣就構(gòu)成了一個(gè)層次化的上下文結(jié)構(gòu)。

    從initWebApplicationContext中可以看到真正創(chuàng)建applicationContext容器是由createWebApplicationContext方法來(lái)實(shí)現(xiàn)的,它的代碼如下:

   

Java代碼
  1. protected WebApplicationContext createWebApplicationContext(   
  2.             ServletContext servletContext, ApplicationContext parent) throws BeansException    
  3.     {   
  4.         // 首先決定要?jiǎng)?chuàng)建的applicationContext容器的類(lèi)   
  5.         Class contextClass = determineContextClass(servletContext);   
  6.         // 如果獲取到的類(lèi)不是ConfigurableWebApplicationContext類(lèi)型的,則創(chuàng)建容器失敗,所以這里創(chuàng)建的容器必須是ConfigurableWebApplicationContext類(lèi)型的   
  7.         if (!ConfigurableWebApplicationContext.class.isAssignableFrom(contextClass))    
  8.         {   
  9.             throw new ApplicationContextException("Custom context class [" + contextClass.getName() +   
  10.                     "] is not of type [" + ConfigurableWebApplicationContext.class.getName() + "]");   
  11.         }   
  12.   
  13.         // 實(shí)例化spring容器   
  14.         ConfigurableWebApplicationContext wac =   
  15.                 (ConfigurableWebApplicationContext) BeanUtils.instantiateClass(contextClass);   
  16.         wac.setParent(parent);   
  17.         wac.setServletContext(servletContext);   
  18.         // 獲取contextConfigLocation初始化參數(shù),該參數(shù)記錄的是需要載入的多個(gè)配置文件(即定義bean的配置文件)   
  19.         String configLocation = servletContext.getInitParameter(CONFIG_LOCATION_PARAM);   
  20.         if (configLocation != null)    
  21.         {   
  22.             wac.setConfigLocations(StringUtils.tokenizeToStringArray(configLocation,   
  23.                     ConfigurableWebApplicationContext.CONFIG_LOCATION_DELIMITERS));   
  24.         }   
  25.   
  26.         wac.refresh();   
  27.         return wac;   
  28.     }  

    createWebApplicationContext方法實(shí)現(xiàn)步驟為:

    1. 首先決定要?jiǎng)?chuàng)建的applicationContext容器的類(lèi)
    2. 實(shí)例化applicationContext容器

    但它是如何決定要?jiǎng)?chuàng)建的容器類(lèi)呢?我們看一下determineContextClass方法:

   

Java代碼
  1. protected Class determineContextClass(ServletContext servletContext) throws ApplicationContextException    
  2.     {   
  3.         // 從web.xml中獲取需要初始化的容器的類(lèi)名   
  4.         String contextClassName = servletContext.getInitParameter(CONTEXT_CLASS_PARAM);   
  5.         // 如果獲取到的類(lèi)名不為空,則創(chuàng)建該容器的Class對(duì)象   
  6.         if (contextClassName != null)    
  7.         {   
  8.             try {   
  9.                 return ClassUtils.forName(contextClassName);   
  10.             }   
  11.             catch (ClassNotFoundException ex) {   
  12.                 throw new ApplicationContextException(   
  13.                         "Failed to load custom context class [" + contextClassName + "]", ex);   
  14.             }   
  15.         }   
  16.         // 否則創(chuàng)建默認(rèn)的容器的Class對(duì)象,即:org.springframework.web.context.support.XmlWebApplicationContext   
  17.         // 在創(chuàng)建ContextLoader時(shí),defaultStrategies = PropertiesLoaderUtils.loadProperties(resource);這句代碼已經(jīng)準(zhǔn)備好默認(rèn)的容器類(lèi)   
  18.         else    
  19.         {   
  20.             contextClassName = defaultStrategies.getProperty(WebApplicationContext.class.getName());   
  21.             try    
  22.             {   
  23.                 return ClassUtils.forName(contextClassName);   
  24.             }   
  25.             catch (ClassNotFoundException ex)    
  26.             {   
  27.                 throw new ApplicationContextException(   
  28.                         "Failed to load default context class [" + contextClassName + "]", ex);   
  29.             }   
  30.         }   
  31.     }  

 

    該方法首先判斷從web.xml文件的初始化參數(shù)CONTEXT_CLASS_PARAM(的定義為public static final String CONTEXT_CLASS_PARAM = "contextClass";)獲取的的類(lèi)名是否存在,如果存在,則容器的Class;否則返回默認(rèn)的

Class。如何獲取默認(rèn)的容器Class,注意看創(chuàng)建contextLoader時(shí)的代碼注釋就知道了。

    由此看來(lái),spring不僅有默認(rèn)的applicationContext的容器類(lèi),還允許我們自定義applicationContext容器類(lèi),不過(guò)Spring不建義我們自定義applicationContext容器類(lèi)。

   

 

   好了,這就是spring的IoC容器在web容器如何啟動(dòng)和起作用的全部過(guò)程。細(xì)心的朋友可以看出創(chuàng)建applicationContext容器的同時(shí)會(huì)初始化配置文件中定義的bean類(lèi),createWebApplicationContext方法中的wac.refresh();這段代碼就是用來(lái)初始化配置文件中定義的bean類(lèi)的。它具體的實(shí)現(xiàn)過(guò)程現(xiàn)在還沒(méi)完全搞清楚,等搞清楚了再跟大家分享!

本站僅提供存儲(chǔ)服務(wù),所有內(nèi)容均由用戶發(fā)布,如發(fā)現(xiàn)有害或侵權(quán)內(nèi)容,請(qǐng)點(diǎn)擊舉報(bào)
打開(kāi)APP,閱讀全文并永久保存 查看更多類(lèi)似文章
猜你喜歡
類(lèi)似文章
詳解contextConfigLocation
spring在web.xml中和在struts中的不同配置 - gwt600的專(zhuān)欄 - C...
Spring源代碼分析之(二):IOC容器在web容器中的啟動(dòng)
spring階段性的一點(diǎn)感受
spring是如何解析自己的配置文件的(1)
轉(zhuǎn):SpringMVC理解之一:應(yīng)用上下文webApplicationContext
更多類(lèi)似文章 >>
生活服務(wù)
分享 收藏 導(dǎo)長(zhǎng)圖 關(guān)注 下載文章
綁定賬號(hào)成功
后續(xù)可登錄賬號(hào)暢享VIP特權(quán)!
如果VIP功能使用有故障,
可點(diǎn)擊這里聯(lián)系客服!

聯(lián)系客服