V2EX = way to explore
V2EX 是一个关于分享和探索的地方
现在注册
已注册用户请  登录
lml12377
V2EX  ›  Java

ServletContext 和 spring ApplicationContext 的线程问题

  •  
  •   lml12377 · 2017-02-04 11:33:27 +08:00 · 3161 次点击
    这是一个创建于 2841 天前的主题,其中的信息可能已经有所发展或是发生改变。

    看到 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 又是在什么时机被创建出来的呢?

    5 条回复    2017-02-07 13:38:46 +08:00
    ihuotui
        1
    ihuotui  
       2017-02-04 23:02:33 +08:00 via iPhone   ❤️ 1
    看 web xml 然后看看到底有多少个 context ,看看启动过程。每个 context 的作用。
    yidinghe
        2
    yidinghe  
       2017-02-05 18:12:58 +08:00   ❤️ 1
    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
        3
    lml12377  
    OP
       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
        4
    yidinghe  
       2017-02-07 11:28:54 +08:00   ❤️ 1
    可能我描述有不准确的地方。以代码为准就是了。
    lml12377
        5
    lml12377  
    OP
       2017-02-07 13:38:46 +08:00
    @yidinghe 谢谢~还是 v2 大神多,感觉比 seg 靠谱多了
    关于   ·   帮助文档   ·   博客   ·   API   ·   FAQ   ·   实用小工具   ·   4029 人在线   最高记录 6679   ·     Select Language
    创意工作者们的社区
    World is powered by solitude
    VERSION: 3.9.8.5 · 29ms · UTC 04:11 · PVG 12:11 · LAX 20:11 · JFK 23:11
    Developed with CodeLauncher
    ♥ Do have faith in what you're doing.