来源:tuhooo
cnblogs.com/tuhooo/p/6491903.html
cnblogs.com/tuhooo/p/6491903.html
一、ServletContext对象获取Demo
Servlet容器在启动时会加载Web应用,并为每个Web应用创建唯一的ServletContext对象。
可以把ServletContext看作一个Web应用的服务器端组件的共享内存。在ServletContext中可以存放共享数据,有4个读取或者设置共享数据的方法:
CounterServlet.java
1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950
package com.servletContext.demo;import java.io.IOException; import javax.servlet.ServletConfig;import javax.servlet.ServletContext;import javax.servlet.ServletException;import javax.servlet.http.HttpServlet;import javax.servlet.http.HttpServletRequest;import javax.servlet.http.HttpServletResponse; public class CounterServlet extends HttpServlet { @Override public void init(ServletConfig config) throws ServletException { super.init(config); } @Override protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { doPost(req, resp); } @Override protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { // 获得ServletContext的引用 ServletContext context = getServletContext(); // 从ServletContext读取count属性 Integer count = (Integer) context.getAttribute("count"); // 如果没有读到count属性,那么创建count属性,并设置初始值为0 if(count == null) { System.out.println("context中还没有count属性呢"); count = new Integer(0); context.setAttribute("count", count); } count = count + 1; // count增加之后还要写回去,引用为什么还要重新存回去 context.setAttribute("count", count); System.out.println("您是第" + count + "个访问的!"); } @Override public void destroy() { super.destroy(); } }
public ServletContextEvent(ServletContext source);
这个方法是从一个给定的ServletContext构建一个ServletContextEvent。而public ServletContext getServletContext();则是返回已经改变的ServletContext,暂时不知道有啥用,是不是给监听器塞ServletContext用的啊?
想自己也写一个ServletContextListener呢!
1234567891011121314151617181920212223242526272829303132333435
package com.servletContext.demo;import javax.servlet.ServletContext;import javax.servlet.ServletContextEvent;import javax.servlet.ServletContextListener; public class MyServletContextListener implements ServletContextListener { @Override public void contextInitialized(ServletContextEvent sce) { // 从web.xml中拿出添加的参数 ServletContext ctx = sce.getServletContext(); String initParam = ctx.getInitParameter("myContextListener"); System.out.println("我配置的初始化参数为:" + initParam); // 利用初始化参数找到配置文件机型初始化 System.out.println("context初始化了咯"); System.out.println("这里假装初始化Spring容器....."); } @Override public void contextDestroyed(ServletContextEvent sce) { // 在销毁之前获得ServletContext ServletContext ctx = sce.getServletContext(); // 正好刚刚存了一个值进去了,销毁之前拿出来瞅瞅 Integer count = (Integer) ctx.getAttribute("count"); System.out.println("在销毁之前,count的值为:" + count); } }
package com.servletContext.demo;
import javax.servlet.ServletContext;
import javax.servlet.ServletContextEvent;
import javax.servlet.ServletContextListener;
public class MyServletContextListener implements ServletContextListener {
@Override
public void contextInitialized(ServletContextEvent sce) {
// 从web.xml中拿出添加的参数
ServletContext ctx = sce.getServletContext();
String initParam = ctx.getInitParameter(“myContextListener”);
System.out.println(“我配置的初始化参数为:” + initParam);
// 利用初始化参数找到配置文件机型初始化
System.out.println(“context初始化了咯”);
System.out.println(“这里假装初始化Spring容器…..”);
}
@Override
public void contextDestroyed(ServletContextEvent sce) {
// 在销毁之前获得ServletContext
ServletContext ctx = sce.getServletContext();
// 正好刚刚存了一个值进去了,销毁之前拿出来瞅瞅
Integer count = (Integer) ctx.getAttribute(“count”);
System.out.println(“在销毁之前,count的值为:” + count);
}
}
这他喵的居然真的可以!
web.xml为:
123456789101112131415161718192021222324252627282930313233
?xml version="1.0" encoding="UTF-8"?web-app xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns="http://java.sun.com/xml/ns/javaee" xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd" id="WebApp_ID" version="2.5" display-nameServletContext/display-name welcome-file-list welcome-fileindex.html/welcome-file welcome-fileindex.htm/welcome-file welcome-fileindex.jsp/welcome-file welcome-filedefault.html/welcome-file welcome-filedefault.htm/welcome-file welcome-filedefault.jsp/welcome-file /welcome-file-list !-- 假装为Spring监听器提供启动参数,其实是给ServletContext提供的 -- context-param param-namemyContextListener/param-name !-- 这里如果bean.xml在包cn.ssh下,那么就应该写为:cn/ssh/bean.xml -- param-value这是我设置的值/param-value /context-param !-- 配置Spring的监听器 -- listener listener-classcom.servletContext.demo.MyServletContextListener/listener-class /listener servlet servlet-namecount/servlet-name servlet-classcom.servletContext.demo.CounterServlet/servlet-class /servlet servlet-mapping servlet-namecount/servlet-name url-pattern/counter/url-pattern /servlet-mapping /web-app
?xml version=”1.0” encoding=”UTF-8”?
web-app xmlns:xsi=”http://www.w3.org/2001/XMLSchema-instance" xmlns=”http://java.sun.com/xml/ns/javaee" xsi:schemaLocation=”http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd" id=”WebApp_ID” version=”2.5”
display-nameServletContext/display-name
welcome-file-list
welcome-fileindex.html/welcome-file
welcome-fileindex.htm/welcome-file
welcome-fileindex.jsp/welcome-file
welcome-filedefault.html/welcome-file
welcome-filedefault.htm/welcome-file
welcome-filedefault.jsp/welcome-file
/welcome-file-list
!– 假装为Spring监听器提供启动参数,其实是给ServletContext提供的 –
context-param
param-namemyContextListener/param-name
!– 这里如果bean.xml在包cn.ssh下,那么就应该写为:cn/ssh/bean.xml –
param-value这是我设置的值/param-value
/context-param
!– 配置Spring的监听器 –
listener
listener-classcom.servletContext.demo.MyServletContextListener/listener-class
/listener
servlet
servlet-namecount/servlet-name
servlet-classcom.servletContext.demo.CounterServlet/servlet-class
/servlet
servlet-mapping
servlet-namecount/servlet-name
url-pattern/counter/url-pattern
/servlet-mapping
/web-app
测试结果为:
看来真的是可以了,这里关闭服务器的时候Console中的内容也被清除了,暂时没有看到ServletContext销毁时的消息。
Spring提供的是ContextLoaderListener,这个监听器实现了ServletContextListener接口,可以作为Listener使用,它会在创建的时候自动查找WEB-INF/下的applicationContext.xml文件,因此,如果只有一个配置文件,并且文件名为applicationContext.xml,则只需要在web.xml中加入对Listener的配置就可以。
如果有多个配置文件需要加载,则要考虑使用context-param…/元素来确定配置文件的文件名。ContextLoaderListener加载的时候,会查找名为contextConfigLocation的初始化参数。因此context-param…/时应该指定参数名为contextConfigLocation。
12345678910
!-- 为Spring监听器提供启动参数 --context-param param-namecontextConfigLocation/param-name !-- 这里如果bean.xml在包cn.ssh下,那么就应该写为:cn/ssh/bean.xml -- param-valueclasspath:bean.xml/param-value/context-param!-- 配置Spring的监听器 --listener listener-classorg.springframework.web.context.ContextLoaderListener/listener-class/listener
!– 为Spring监听器提供启动参数 –
context-param
param-namecontextConfigLocation/param-name
!– 这里如果bean.xml在包cn.ssh下,那么就应该写为:cn/ssh/bean.xml –
param-valueclasspath:bean.xml/param-value
/context-param
!– 配置Spring的监听器 –
listener
listener-classorg.springframework.web.context.ContextLoaderListener/listener-class
/listener
如果没有使用contextConfigLocation指定配置文件,则Spring自动查找applicationContext.xml配置文件;如果有contextConfigLocation,则利用该参数确定配置文件。如果无法找到适合的配置文件,Spring将无法初始化。
Spring根据指定的文件创建WebApplicationContext对象,并将其保存在Web应用的ServletContext中。大部分情况下,应用中的Bean无需感受到ApplicationContext的存在,只要用ApplicationContext中的IoC即可。
这个监听器所在的jar包为:
如果需要利用ApplicationContext的实例,可以通过如下代码获取:
1234567891011121314151617181920212223242526272829303132333435
package com.ssh.domain;import javax.servlet.ServletContext;import javax.servlet.http.HttpServletRequest; import org.apache.struts2.ServletActionContext;import org.springframework.web.context.WebApplicationContext;import org.springframework.web.context.support.WebApplicationContextUtils; import com.opensymphony.xwork2.ActionSupport;import com.ssh.test.TestAdd; public class TestAction extends ActionSupport { @Override public String execute() throws Exception { HttpServletRequest request = ServletActionContext.getRequest(); ServletContext servletContext = request.getServletContext(); // 这里不是通过依赖注入,而是直接从容器中拿 WebApplicationContext ctx = WebApplicationContextUtils.getWebApplicationContext(servletContext); // 也可以是下面这样的 WebApplicationContext ctx1 = (WebApplicationContext) servletContext.getAttribute(WebApplicationContext.ROOT_WEB_APPLICATION_CONTEXT_ATTRIBUTE); if(ctx == ctx1) { System.out.println("两次获得对象是一样的"); } TestAdd testAdd = (TestAdd) ctx.getBean("testAdd"); testAdd.add(); return NONE; }}
package com.ssh.domain;
import javax.servlet.ServletContext;
import javax.servlet.http.HttpServletRequest;
import org.apache.struts2.ServletActionContext;
import org.springframework.web.context.WebApplicationContext;
import org.springframework.web.context.support.WebApplicationContextUtils;
import com.opensymphony.xwork2.ActionSupport;
import com.ssh.test.TestAdd;
public class TestAction extends ActionSupport {
@Override
public String execute() throws Exception {
HttpServletRequest request = ServletActionContext.getRequest();
ServletContext servletContext = request.getServletContext();
// 这里不是通过依赖注入,而是直接从容器中拿
WebApplicationContext ctx = WebApplicationContextUtils.getWebApplicationContext(servletContext);
// 也可以是下面这样的
WebApplicationContext ctx1 = (WebApplicationContext)
servletContext.getAttribute(WebApplicationContext.ROOT_WEB_APPLICATION_CONTEXT_ATTRIBUTE);
if(ctx == ctx1) {
System.out.println(“两次获得对象是一样的”);
}
TestAdd testAdd = (TestAdd) ctx.getBean(“testAdd”);
testAdd.add();
return NONE;
}
}
TestAdd.java
1234567
package com.ssh.test;public class TestAdd { public void add( ) { System.out.println("通过WebContext获得的而打印...."); }}
package com.ssh.test;
public class TestAdd {
public void add( ) {
System.out.println(“通过WebContext获得的而打印….”);
}
}
测试结果为:
http://localhost:8080/spring_struts2/testAction
打开源码,就蛋疼了,有封装了一下:
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101
package org.springframework.web.context;import javax.servlet.ServletContextEvent;import javax.servlet.ServletContextListener; /*** Bootstrap listener to start up and shut down Spring's root {@link WebApplicationContext}.* Simply delegates to {@link ContextLoader} as well as to {@link ContextCleanupListener}.** pThis listener should be registered after {@link org.springframework.web.util.Log4jConfigListener}* in {@code web.xml}, if the latter is used.** pAs of Spring 3.1, {@code ContextLoaderListener} supports injecting the root web* application context via the {@link #ContextLoaderListener(WebApplicationContext)}* constructor, allowing for programmatic configuration in Servlet 3.0+ environments.* See {@link org.springframework.web.WebApplicationInitializer} for usage examples.** @author Juergen Hoeller* @author Chris Beams* @since 17.02.2003* @see #setContextInitializers* @see org.springframework.web.WebApplicationInitializer* @see org.springframework.web.util.Log4jConfigListener*/public class ContextLoaderListener extends ContextLoader implements ServletContextListener { /** * Create a new {@code ContextLoaderListener} that will create a web application * context based on the "contextClass" and "contextConfigLocation" servlet * context-params. See {@link ContextLoader} superclass documentation for details on * default values for each. * pThis constructor is typically used when declaring {@code ContextLoaderListener} * as a {@code listener} within {@code web.xml}, where a no-arg constructor is * required. * pThe created application context will be registered into the ServletContext under * the attribute name {@link WebApplicationContext#ROOT_WEB_APPLICATION_CONTEXT_ATTRIBUTE} * and the Spring application context will be closed when the {@link #contextDestroyed} * lifecycle method is invoked on this listener. * @see ContextLoader * @see #ContextLoaderListener(WebApplicationContext) * @see #contextInitialized(ServletContextEvent) * @see #contextDestroyed(ServletContextEvent) */ public ContextLoaderListener() { } /** * Create a new {@code ContextLoaderListener} with the given application context. This * constructor is useful in Servlet 3.0+ environments where instance-based * registration of listeners is possible through the {@link javax.servlet.ServletContext#addListener} * API. * pThe context may or may not yet be {@linkplain * org.springframework.context.ConfigurableApplicationContext#refresh() refreshed}. If it * (a) is an implementation of {@link ConfigurableWebApplicationContext} and * (b) has strongnot/strong already been refreshed (the recommended approach), * then the following will occur: * ul * liIf the given context has not already been assigned an {@linkplain * org.springframework.context.ConfigurableApplicationContext#setId id}, one will be assigned to it/li * li{@code ServletContext} and {@code ServletConfig} objects will be delegated to * the application context/li * li{@link #customizeContext} will be called/li * liAny {@link org.springframework.context.ApplicationContextInitializer ApplicationContextInitializer}s * specified through the "contextInitializerClasses" init-param will be applied./li * li{@link org.springframework.context.ConfigurableApplicationContext#refresh refresh()} will be called/li * /ul * If the context has already been refreshed or does not implement * {@code ConfigurableWebApplicationContext}, none of the above will occur under the * assumption that the user has performed these actions (or not) per his or her * specific needs. * pSee {@link org.springframework.web.WebApplicationInitializer} for usage examples. * pIn any case, the given application context will be registered into the * ServletContext under the attribute name {@link * WebApplicationContext#ROOT_WEB_APPLICATION_CONTEXT_ATTRIBUTE} and the Spring * application context will be closed when the {@link #contextDestroyed} lifecycle * method is invoked on this listener. * @param context the application context to manage * @see #contextInitialized(ServletContextEvent) * @see #contextDestroyed(ServletContextEvent) */ public ContextLoaderListener(WebApplicationContext context) { super(context); } /** * Initialize the root web application context. */ @Override public void contextInitialized(ServletContextEvent event) { initWebApplicationContext(event.getServletContext()); } /** * Close the root web application context. */ @Override public void contextDestroyed(ServletContextEvent event) { closeWebApplicationContext(event.getServletContext()); ContextCleanupListener.cleanupAttributes(event.getServletContext()); } }
package org.springframework.web.context;
import javax.servlet.ServletContextEvent;
import javax.servlet.ServletContextListener;
/**
- Bootstrap listener to start up and shut down Spring’s root {@link WebApplicationContext}.
- Simply delegates to {@link ContextLoader} as well as to {@link ContextCleanupListener}.
- pThis listener should be registered after {@link org.springframework.web.util.Log4jConfigListener}
- in {@code web.xml}, if the latter is used.
- pAs of Spring 3.1, {@code ContextLoaderListener} supports injecting the root web
- application context via the {@link #ContextLoaderListener(WebApplicationContext)}
- constructor, allowing for programmatic configuration in Servlet 3.0+ environments.
- See {@link org.springframework.web.WebApplicationInitializer} for usage examples.
- @author Juergen Hoeller
- @author Chris Beams
- @since 17.02.2003
- @see #setContextInitializers
- @see org.springframework.web.WebApplicationInitializer
- @see org.springframework.web.util.Log4jConfigListener
*/
public class ContextLoaderListener extends ContextLoader implements ServletContextListener {
/**
* Create a new {@code ContextLoaderListener} that will create a web application
* context based on the “contextClass” and “contextConfigLocation” servlet
* context-params. See {@link ContextLoader} superclass documentation for details on
* default values for each.
* pThis constructor is typically used when declaring {@code ContextLoaderListener}
* as a {@code listener} within {@code web.xml}, where a no-arg constructor is
* required.
* pThe created application context will be registered into the ServletContext under
* the attribute name {@link WebApplicationContext#ROOT_WEB_APPLICATION_CONTEXT_ATTRIBUTE}
* and the Spring application context will be closed when the {@link #contextDestroyed}
* lifecycle method is invoked on this listener.
* @see ContextLoader
* @see #ContextLoaderListener(WebApplicationContext)
* @see #contextInitialized(ServletContextEvent)
* @see #contextDestroyed(ServletContextEvent)
*/
public ContextLoaderListener() {
}
/**
* Create a new {@code ContextLoaderListener} with the given application context. This
* constructor is useful in Servlet 3.0+ environments where instance-based
* registration of listeners is possible through the {@link javax.servlet.ServletContext#addListener}
* API.
* pThe context may or may not yet be {@linkplain
* org.springframework.context.ConfigurableApplicationContext#refresh() refreshed}. If it
* (a) is an implementation of {@link ConfigurableWebApplicationContext} and
* (b) has strongnot/strong already been refreshed (the recommended approach),
* then the following will occur:
* ul
* liIf the given context has not already been assigned an {@linkplain
* org.springframework.context.ConfigurableApplicationContext#setId id}, one will be assigned to it/li
* li{@code ServletContext} and {@code ServletConfig} objects will be delegated to
* the application context/li
* li{@link #customizeContext} will be called/li
* liAny {@link org.springframework.context.ApplicationContextInitializer ApplicationContextInitializer}s
* specified through the “contextInitializerClasses” init-param will be applied./li
* li{@link org.springframework.context.ConfigurableApplicationContext#refresh refresh()} will be called/li
* /ul
* If the context has already been refreshed or does not implement
* {@code ConfigurableWebApplicationContext}, none of the above will occur under the
* assumption that the user has performed these actions (or not) per his or her
* specific needs.
* pSee {@link org.springframework.web.WebApplicationInitializer} for usage examples.
* pIn any case, the given application context will be registered into the
* ServletContext under the attribute name {@link
* WebApplicationContext#ROOT_WEB_APPLICATION_CONTEXT_ATTRIBUTE} and the Spring
* application context will be closed when the {@link #contextDestroyed} lifecycle
* method is invoked on this listener.
* @param context the application context to manage
* @see #contextInitialized(ServletContextEvent)
* @see #contextDestroyed(ServletContextEvent)
*/
public ContextLoaderListener(WebApplicationContext context) {
super(context);
}
/**
* Initialize the root web application context.
*/
@Override
public void contextInitialized(ServletContextEvent event) {
initWebApplicationContext(event.getServletContext());
}
/**
* Close the root web application context.
*/
@Override
public void contextDestroyed(ServletContextEvent event) {
closeWebApplicationContext(event.getServletContext());
ContextCleanupListener.cleanupAttributes(event.getServletContext());
}
}
源码果然是个好东西,平时敲代码那会注意到这么多细节。这个类不复杂,两个构造方法,外加一个初始化的时候创建Spring容器和服务关闭的时候对容器的清理,封装了之后还要看其他的类,哎。
首先第一段注释是对这个类的描述:
这个启动监听器是用开启和关闭Spring的root的,这里他用了root而不是容器。简单的代理给了ContextLoader和ContextCleanupListener这两个类来处理。如果这个org.springframework.web.util.Log4jConfigListener被用到了,那么ContextLoaderListener应该在它之后注册。
在Spring3.1中,ContextLoaderListener支持通过ContextLoaderListener(WebApplicationContext)这个构造方法向应用上下文中注入root(也就是Spring的容器),这样可以以编程的方式来配置Servlet 3.0+的环境。
第二段注释是,新建一个ContextLoaderListener的类将会基于Servlet的”contextClass”和”contextCofigLocation”这两个参数来创建web应用的上下文。
翻译的好累啊,反正意思差不多就是这样5555….
来看这段代码:
1234567
/*** Initialize the root web application context.*/@Overridepublic void contextInitialized(ServletContextEvent event) { initWebApplicationContext(event.getServletContext());}
/**
- Initialize the root web application context.
*/
@Override
public void contextInitialized(ServletContextEvent event) {
initWebApplicationContext(event.getServletContext());
}
这个initWebApplicationContext方法是ContextLoad.java这个类里面的方法。
12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576
/*** Initialize Spring's web application context for the given servlet context,* using the application context provided at construction time, or creating a new one* according to the "{@link #CONTEXT_CLASS_PARAM contextClass}" and* "{@link #CONFIG_LOCATION_PARAM contextConfigLocation}" context-params.* @param servletContext current servlet context* @return the new WebApplicationContext* @see #ContextLoader(WebApplicationContext)* @see #CONTEXT_CLASS_PARAM* @see #CONFIG_LOCATION_PARAM*/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!"); } 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) { ConfigurableWebApplicationContext cwac = (ConfigurableWebApplicationContext) this.context; if (!cwac.isActive()) { // The context has not yet been refreshed - provide services such as // setting the parent context, setting the application context id, etc if (cwac.getParent() == null) { // The context instance was injected without an explicit parent - // determine parent for root web application context, if any. ApplicationContext parent = loadParentContext(servletContext); cwac.setParent(parent); } configureAndRefreshWebApplicationContext(cwac, servletContext); } } servletContext.setAttribute(WebApplicationContext.ROOT_WEB_APPLICATION_CONTEXT_ATTRIBUTE, this.context); 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; }}
/**
- Initialize Spring’s web application context for the given servlet context,
- using the application context provided at construction time, or creating a new one
- according to the “{@link #CONTEXT_CLASS_PARAM contextClass}” and
- “{@link #CONFIG_LOCATION_PARAM contextConfigLocation}” context-params.
- @param servletContext current servlet context
- @return the new WebApplicationContext
- @see #ContextLoader(WebApplicationContext)
- @see #CONTEXT_CLASS_PARAM
- @see #CONFIG_LOCATION_PARAM
/
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!”);
}
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) {
ConfigurableWebApplicationContext cwac = (ConfigurableWebApplicationContext) this.context;
if (!cwac.isActive()) {
// The context has not yet been refreshed - provide services such as
// setting the parent context, setting the application context id, etc
if (cwac.getParent() == null) {
// The context instance was injected without an explicit parent -
// determine parent for root web application context, if any.
ApplicationContext parent = loadParentContext(servletContext);
cwac.setParent(parent);
}
configureAndRefreshWebApplicationContext(cwac, servletContext);
}
}
servletContext.setAttribute(WebApplicationContext.ROOT_WEB_APPLICATION_CONTEXT_ATTRIBUTE, this.context);
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;
}
}
ContextLoad.initWebApplicationContext是为给定的servlet context来初始化web应用的上下文的。
业务逻辑解读:
首先从ServletContext中看看有没有Spring创建的这个容器;然后为ContextLoader存一份实例变量,使得在ServletContext关闭之后仍可以访问;
1
this.context = createWebApplicationContext(servletContext);
this.context = createWebApplicationContext(servletContext);
这句就是创建一个WebApplicationContext相当于我们自己加载配置文件的那个类。
1
configureAndRefreshWebApplicationContext(cwac, servletContext);
configureAndRefreshWebApplicationContext(cwac, servletContext);
这句话也很明显,就是配置并且刷新WebAppCtx的。
1
servletContext.setAttribute(WebApplicationContext.ROOT_WEB_APPLICATION_CONTEXT_ATTRIBUTE, this.context);
servletContext.setAttribute(WebApplicationContext.ROOT_WEB_APPLICATION_CONTEXT_ATTRIBUTE, this.context);
这句将创建的Spring的context作为属性放到servletContext中。
1
return this.context;
return this.context;
然后就返回了Spring的容器了…..是不是简洁(装逼装不下去了),调用链好长。
暂时只能分析到这里!
关注后端技术精选,每天推送优质好文