ContextLoaderListener初始化了webapp的root context(應用根上下文),過程以下java
ContextLoaderListener繼承了ContextLoader,主要方法以下web
private WebApplicationContext context; public WebApplicationContext initWebApplicationContext(ServletContext servletContext) { //判斷是否已經有根上下文,若是已經有了,報錯,不然,建立根上下文 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!"); } else { //開始建立根上下文 try { if(this.context == null) { //建立根上下文 this.context = this.createWebApplicationContext(servletContext); } if(this.context instanceof ConfigurableWebApplicationContext) { ConfigurableWebApplicationContext err = (ConfigurableWebApplicationContext)this.context; if(!err.isActive()) { if(err.getParent() == null) { ApplicationContext elapsedTime = this.loadParentContext(servletContext); err.setParent(elapsedTime); } // 給上下文設置各類屬性 // 給上下文設置id // 給上下文設置配置文件的路徑(applicationcontext.xml相似) // 經過refresh方法設置beanfactory?這裏不是太清楚 this.configureAndRefreshWebApplicationContext(err, servletContext); } } //建立好的根上下文放到servletContext裏,整個webapp只有一個servletContext //servletContext是ServletConfig的一個成員變量 servletContext.setAttribute(WebApplicationContext.ROOT_WEB_APPLICATION_CONTEXT_ATTRIBUTE, this.context); ClassLoader err1 = Thread.currentThread().getContextClassLoader(); if(err1 == ContextLoader.class.getClassLoader()) { currentContext = this.context; } else if(err1 != null) { currentContextPerThread.put(err1, this.context); } return this.context; } catch (RuntimeException var8) { } } }
protected WebApplicationContext createWebApplicationContext(ServletContext sc) { //獲取上下文類型,只能爲ConfigurableWebApplicationContext類型的 Class contextClass = this.determineContextClass(sc); if(!ConfigurableWebApplicationContext.class.isAssignableFrom(contextClass)) { throw new ApplicationContextException("Custom context class [" + contextClass.getName() + "] is not of type [" + ConfigurableWebApplicationContext.class.getName() + "]"); } else { //若是類型正確,實例化並返回 return (ConfigurableWebApplicationContext)BeanUtils.instantiateClass(contextClass); } }
protected Class<?> determineContextClass(ServletContext servletContext) { //首先,看在web.xml中有沒有配置咱們本身的上下文類型,很明顯,咱們沒有,此處爲null String contextClassName = servletContext.getInitParameter("contextClass"); if(contextClassName != null) { try { return ClassUtils.forName(contextClassName, ClassUtils.getDefaultClassLoader()); } catch (ClassNotFoundException var4) { throw new ApplicationContextException("Failed to load custom context class [" + contextClassName + "]", var4); } } else { //因爲咱們本身沒有配置,spring加載本身的默認類型(XmlWebApplicaionContext.java) contextClassName = defaultStrategies.getProperty(WebApplicationContext.class.getName()); try { return ClassUtils.forName(contextClassName, ContextLoader.class.getClassLoader()); } catch (ClassNotFoundException var5) { throw new ApplicationContextException("Failed to load default context class [" + contextClassName + "]", var5); } } }
//這個是默認類型 static { try { ClassPathResource ex = new ClassPathResource("ContextLoader.properties", ContextLoader.class); defaultStrategies = PropertiesLoaderUtils.loadProperties(ex); } catch (IOException var1) { throw new IllegalStateException("Could not load \'ContextLoader.properties\': " + var1.getMessage()); } currentContextPerThread = new ConcurrentHashMap(1); }
ContextLoader.properties文件內容以下spring
org.springframework.web.context.WebApplicationContext= org.springframework.web.context.support.XmlWebApplicationContext
XmlWebApplicationContext是web應用中定製的getBean的方法tomcat
ServletContext servletContext = request.getSession().getServletContext(); WebApplicationContext was = WebApplicationContextUtils.getWebApplicationContext(servletContext); User user = (User)was.getBean("user");
其他兩種方法爲:session
ApplicationContext ctx =mybatis
new FileSystemXmlApplicationContext( "G:/Test/applicationcontext.xml ");app
或webapp
ApplicationContext ctx =this
new ClassPathXmlApplicationContext( "/applicationcontext.xml ");spa
最後一句話:一個請求一個request,一個用戶一個session,一個應用一個ServletContext
ServletContext中能夠存儲共享的數據,由於它的生命週期很長,從應用啓動直到消亡。因此裏面不要存大的數據,會很佔內存
ServletContext對象是由容器建立的,也就是tomcat
和request同樣,ServletContext也有setAttribute以及getAttribute和removeAttribute方法
經過ServletContext,咱們也能夠在servlet之間傳遞信息,也能夠讀取web.xml中的初始化參數context-param,如web.xml中context-param以下
<context-param> <param-name>log4jConfigLocation</param-name> <param-value>classpath:${env}-conf/log4j.properties</param-value> </context-param> <context-param> <param-name>contextConfigLocation</param-name> <param-value>classpath:spring.xml</param-value> <!-- <param-value>classpath:spring-mybatis.xml</param-value> --> </context-param> <context-param> <param-name>webAppRootKey</param-name> <param-value>ott-vms-admin.root</param-value> </context-param>
ServletContext servletContext = request.getSession().getServletContext(); String value = (String)servletContext.getInitParameter("contextConfigLocation");