ServletContext 和 spring ApplicationContext 的线程问题

2017-02-04 11:33:27 +08:00
 lml12377

看到 spring 的 ServeltContextListener 加载方式时,有个问题。

不知道我的理解对不对:

tomcat 下一个 web 应用目录对应一个 ServeltContext 单例,假设使用 Servelt 处理请求,那一个 Servelt class 其实在 tomcat 容器中也是单例,但是为了提升并发性能,这个单例可能会被多个线程使用。

再到 spring ,在 servlet 被实例化这一步之前, spring 的 ContextLoaderListener 监听器被调用,通过 org.springframework.web.context.ContextLoader 创建 ApplicationContext 对象

问题主要在 ApplicartionContext 这个地方:

这个应用上下文是多线程的吗?因为看到了 static volatile 的 currentContext 和 ConcurrentHashMap 的 currentContextPerThread ,但是为什么还要保存一份当前线程 ContextClassLoader 管理的 WebApplicationContext ?直接用 Heap 区的那一份 currentContext 不行吗?还有,其它线程的 WebApplicationContext 又是在什么时机被创建出来的呢?

3093 次点击
所在节点    Java
5 条回复
ihuotui
2017-02-04 23:02:33 +08:00
看 web xml 然后看看到底有多少个 context ,看看启动过程。每个 context 的作用。
yidinghe
2017-02-05 18:12:58 +08:00
ServletContext 是一个 Servlet 对象对应的上下文环境,通常 Servlet 是单实例的,因此当你实现一个 Servlet 时,必须保证其线程安全性;至于 ServletContext ,一个 Servlet 对应的 ServletContext 对象也会一直保持在那里,是不会变的。

一般来说,一个 Web 应用会有多个 Servlet ,而它们的 ServletContext 则是共用的一个。这个是由 Servlet 容器(如 Tomcat 、 Jetty )来决定。

ApplicationContext 是 Spring Bean 的上下文环境,它的创建理论上与 ServletContext 无关,但在 SpringMVC 中,这个创建过程自动化了(具体是由 `org.springframework.web.servlet.DispatcherServlet` 触发的),并自动绑定到 ServletContext 下。

ApplicationContext 本身当然是线程安全的,而且里面的 bean (就是你写的那些 Controller 和其他的相关类),缺省情况下也必须是线程安全的。

WebApplicationContext 是 SpringMVC 中对 ApplicationContext 的具体实现,每个 ServletContext 下只会有一个 WebApplicationContext ,在应用初始化时就创建出来了,而不是等浏览器请求来了才创建。
lml12377
2017-02-07 10:04:10 +08:00
@yidinghe 谢谢耐心的回答,还有一个问题请教一下:

假设我的 web.xml 包含这样的配置:

<listener>
<listener-class>com.xxx.ContextLoaderListener</listener-class>
</listener>
<servlet>
<servlet-name>business</servlet-name>
<servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
<load-on-startup>1</load-on-startup>
</servlet>

ServletContext 是在 Servlet 之前初始化的:

首先初始化并创建 ServletContext ,接着创建自定义的 ContextLoaderListener.contextInitialized 并把刚刚创建的 ServletContext 传递给它,看代码 WebApplicationContext 应该是在 ContextLoader.initWebApplicationContext 里创建出来的;接着才是 DispatcherServlet 的创建。

你上面说的 [这个创建过程自动化了(具体是由 `org.springframework.web.servlet.DispatcherServlet` 触发的)],是不是指的是当我不指定 ContextLoaderListener 的情况?
yidinghe
2017-02-07 11:28:54 +08:00
可能我描述有不准确的地方。以代码为准就是了。
lml12377
2017-02-07 13:38:46 +08:00
@yidinghe 谢谢~还是 v2 大神多,感觉比 seg 靠谱多了

这是一个专为移动设备优化的页面(即为了让你能够在 Google 搜索结果里秒开这个页面),如果你希望参与 V2EX 社区的讨论,你可以继续到 V2EX 上打开本讨论主题的完整版本。

https://www.v2ex.com/t/338000

V2EX 是创意工作者们的社区,是一个分享自己正在做的有趣事物、交流想法,可以遇见新朋友甚至新机会的地方。

V2EX is a community of developers, designers and creative people.

© 2021 V2EX