记载一下两种方式的web项目中的context对比与使用,这里的context均指spring的ApplicationContext,注意区别servlet容器的ServletContext。
1、spring mvc中的上下文
传统MVC拥有两个context:
根上下文root context,为全局上下文,无法访问子容器即mvc context中bean:
//root context 作为attrName名
WebApplicationContext.ROOT_WEB_APPLICATION_CONTEXT_ATTRIBUTE;
//在ServletContext中以属性保存
WebApplicationContext root = servletContext.getAttribute(attrName);
和mvc context,其父容器为root context:
//mvc context作为HttpServletRequest的属性,名字为
DispatcherServlet.WEB_APPLICATION_CONTEXT_ATTRIBUTE;
2、传统MVC中context创建时机
1)root context:
ContextLoaderListener在servlet容器启动完成后,执行initWebApplicationContext()方法
public WebApplicationContext initWebApplicationContext(ServletContext servletContext) {
...
if (this.context == null) {
//创建root context
this.context = createWebApplicationContext(servletContext);
}
...
//设置到servletContext属性
servletContext.setAttribute(
WebApplicationContext.ROOT_WEB_APPLICATION_CONTEXT_ATTRIBUTE,
this.context
);
...
}
2)mvc context
从初始化servlet的javax.servlet.GenericServlet.init开始到FrameworkServlet.initWebApplicationContext
protected WebApplicationContext initWebApplicationContext() {
//首先拿到root context
WebApplicationContext rootContext =...;
WebApplicationContext wac = null;
...
if (wac == null) {
//这里创建mvc context,rootContext作为父容器,子可以访问父
wac = createWebApplicationContext(rootContext);
}
...
return wac;
}
3、boot 中的web上下文与创建时机
boot默认使用embed tomcat做servlet容器,只有一个root context,或者说mvc context也是同一个。
不同在于创建时机,servlet容器是被spring容器启动的;启动一个SpringBoot应用时:
public static void main(String[] args) {
//run返回ConfigurableApplicationContext
SpringApplication.run(App.class, args);
}
run的返回结果就是全局context,平常也可以通过ApplicationContextAware拿到,所以在DispatchServlet的父类中:
public abstract class FrameworkServlet extends HttpServletBean implements ApplicationContextAware {
...
public void setApplicationContext(ApplicationContext applicationContext) {
if (this.webApplicationContext == null
&& applicationContext instanceof WebApplicationContext) {
//设置mvc上下文
this.webApplicationContext = (WebApplicationContext) applicationContext;
this.webApplicationContextInjected = true;
}
}
...
}
boot在走创建mvc context流程时(上面2.2),可以看出root、mvc context是同一个。
protected WebApplicationContext initWebApplicationContext() {
WebApplicationContext rootContext =...
WebApplicationContext wac = null;
//此时webApplicationContext == rootContext
//类型AnnotationConfigServletWebServerApplicationContext
if (this.webApplicationContext != null) {
wac = this.webApplicationContext;
...
}
...
}
4、一些工具方法
通过查看源码可以看到一些spring提供的工具类和一些静态属性名,就可以善加利用,下面在不同场景下获取。
1)获取请求和session
//获取请求
HttpServletRequest request = ((ServletRequestAttributes)
RequestContextHolder.getRequestAttributes())
.getRequest();
//获取响应
HttpServletResponse response = ((ServletRequestAttributes)
RequestContextHolder.getRequestAttributes())
.getResponse();
//获取session
HttpSession session = request.getSession();
2)获取ServletContext
//1中获取了session
session.getServletContext();
//有了context后,如ContextLoader.getCurrentWebApplicationContext().
webApplicationContext.getServletContext();
3)获取root context:
//根据servletContext获取
WebApplicationContextUtils.getWebApplicationContext(servletContext);
//需要当前线程classloader和context相同
ContextLoader.getCurrentWebApplicationContext();
4)获取mvc context
RequestContextUtils.findWebApplicationContext(httpServletRequest);
//or
RequestContextUtils.findWebApplicationContext(httpServletRequest, servletContext);