獲取WebApplicationContext的幾種方式


加載WebApplicationContext的方式

  WebApplicationContext是ApplicationContext的子接口,縱觀Spring框架的幾種容器,BeanFactory作為頂級的接口,是所有IOC容器的最上層接口,顧名思義WebApplicationContext是依賴於Web容器的一個Spring的IOC容器。前提條件是web容器啟動后這個容器才能啟動。那么如何借助web容器來啟動Spring web的上下文?

  第一種方式:我們可以通過org.springframework.web.context.ContextLoaderServlet;第二種式:org.springframework.web.context.ContextLoaderListener.

這兩種方式有什么不同呢?listener完全是觀察者的設計,僅僅執行的是監聽的任務,而servlet的啟動要稍微延遲一些,啟動的前后順序是有影像的。所以我認為listener更好用一些,實際開發中的框架配置中也是listener更多一些,這一點大家應該有所體會。

配置如下:

1 <context-param> 
2 <param-name>contextConfigLocation</param-name> 
3 <param-value>/WEB-INF/applicationContext.xml</param-value> 
4 </context-param> 
5 
6 <listener> 
7 <listener-class>org.springframework.web.context.ContextLoaderListener</listener-class> 
8 </listener>

上面那一種是Spring Web容器放在classpath下的任何路徑的配置,如果是放在web.xml約定的配置,則可以省略context-param的配置

通過查看ContextLoaderListener的源代碼可以發現它的類的結構如下圖所示:

 

 通過上圖可以發現ContextLoaderListener繼承了ContextLoader類以及實現了ServletContextListener接口,ServletContextListener又實現了EvenListener接口,所以這個監聽器具有事件監聽的功能,並且是監聽了web容器,web容器啟動馬上加載執行。ContextLoader感覺更像是執行加載web容器的一個小小的core組件,負責執行加載web容器的邏輯。下面重點來說一說這個。

 

public void contextInitialized(ServletContextEvent event) {
     //首先先獲取ContextLoader對象
this.contextLoader = createContextLoader(); if (this.contextLoader == null) { this.contextLoader = this; }
     //通過servletContext對象去加載WebApplicationContext
this.contextLoader.initWebApplicationContext(event.getServletContext()); }

initWebApplicationContext的主要代碼:

 

public WebApplicationContext initWebApplicationContext(ServletContext servletContext) {
     //去servlet容器中去尋找org.springframework.web.context.WebApplicationContext.root作為key的value,也就是webApplicationContext對象
if (servletContext.getAttribute(WebApplicationContext.ROOT_WEB_APPLICATION_CONTEXT_ATTRIBUTE) != null) { throw new IllegalStateException( "Cannot initialize context because there is already a root application context present - " + "check whether you have multiple ContextLoader* definitions in your web.xml!"); } Log logger = LogFactory.getLog(ContextLoader.class); servletContext.log("Initializing Spring root WebApplicationContext"); if (logger.isInfoEnabled()) { logger.info("Root WebApplicationContext: initialization started"); } long startTime = System.currentTimeMillis(); try { // Store context in local instance variable, to guarantee that // it is available on ServletContext shutdown. if (this.context == null) { this.context = createWebApplicationContext(servletContext); } if (this.context instanceof ConfigurableWebApplicationContext) { configureAndRefreshWebApplicationContext((ConfigurableWebApplicationContext)this.context, servletContext); }
       //將ApplicationContext放入ServletContext中,其key為<WebApplicationContext.ROOT_WEB_APPLICATION_CONTEXT_ATTRIBUTE servletContext.setAttribute(WebApplicationContext.ROOT_WEB_APPLICATION_CONTEXT_ATTRIBUTE,
this.context);        
       //將ApplicationContext放入ContextLoader的全局靜態常量Map中,其中key為:Thread.currentThread().getContextClassLoader()即當前線程類加載器 ClassLoader ccl
= Thread.currentThread().getContextClassLoader(); if (ccl == ContextLoader.class.getClassLoader()) { currentContext = this.context; } else if (ccl != null) { currentContextPerThread.put(ccl, this.context); } if (logger.isDebugEnabled()) { logger.debug("Published root WebApplicationContext as ServletContext attribute with name [" + WebApplicationContext.ROOT_WEB_APPLICATION_CONTEXT_ATTRIBUTE + "]"); } if (logger.isInfoEnabled()) { long elapsedTime = System.currentTimeMillis() - startTime; logger.info("Root WebApplicationContext: initialization completed in " + elapsedTime + " ms"); } return this.context; } catch (RuntimeException ex) { logger.error("Context initialization failed", ex); servletContext.setAttribute(WebApplicationContext.ROOT_WEB_APPLICATION_CONTEXT_ATTRIBUTE, ex); throw ex; } catch (Error err) { logger.error("Context initialization failed", err); servletContext.setAttribute(WebApplicationContext.ROOT_WEB_APPLICATION_CONTEXT_ATTRIBUTE, err); throw err; } }

 

從上面的代碼大家應該明白了Spring初始化之后,將ApplicationContext存到在了兩個地方(servletContext中和currentContextPerThread中),那么是不是意味着我們可以通過兩種方式取得ApplicationContext?

第一種獲取方式:

 1 request.getSession().getServletContext().getAttribute("org.springframework.web.context.WebApplicationContext.ROOT")  

這樣確實可以獲取,但是如果需要我們自己去這樣獲取的話,未免Spring也太low了吧?那樣會辜負Spring作為web開發第一核心框架的地位的。話不多說,其實Spring已經給我們提供接口了:

在WebApplicationContextUtils類中有一個靜態方法:

1 public static WebApplicationContext getRequiredWebApplicationContext(ServletContext sc)
2             throws IllegalStateException {
3 
4         WebApplicationContext wac = getWebApplicationContext(sc);
5         if (wac == null) {
6             throw new IllegalStateException("No WebApplicationContext found: no ContextLoaderListener registered?");
7         }
8         return wac;
9     }
1 public static WebApplicationContext getWebApplicationContext(ServletContext sc) {  
2         return getWebApplicationContext(sc, WebApplicationContext.ROOT_WEB_APPLICATION_CONTEXT_ATTRIBUTE);  
3     }  

通過執行上面的方法可以獲取WebApplicationContext對象。

第二種方法:

借用ApplicationContextAware,ApplicationContext的幫助類能夠自動裝載ApplicationContext,只要你將某個類實現這個接口,並將這個實現類在Spring配置文件中進行配置,Spring會自動幫你進行注入 ApplicationContext.ApplicationContextAware的代碼結構如下:

1 public interface ApplicationContextAware {  
2 
3         void setApplicationContext(ApplicationContext applicationContext) throws BeansException;  
4 
5 }  

就這一個接口。可以這樣簡單的實現一個ApplicationContextHelper類:

 1 public class ApplicationHelper implements ApplicationContextAware {  
 2 
 3 
 4     private ApplicationContext applicationContext; 
 5 
 6     public void setApplicationContext(ApplicationContext applicationContext)  
 7             throws BeansException {  
 8             this.applicationContext = applicationContext;  
 9     }  
10 
11 
12     public  ApplicationContext getApplicationContext(){
13         return this.applicationContext;  
14     }  
15 }  

通過ApplicationHelper我們就可以獲得咱們想要的AppilcationContext類了。

這是我對如何獲取Spring Web上下文的一個理解。

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM