【问题标题】:Tomcat 7.0.32 +Spring MVC Servlet 3 Async is not workingTomcat 7.0.32 +Spring MVC Servlet 3 异步不起作用
【发布时间】:2013-05-26 16:02:49
【问题描述】:

我写了一个非常简单的控制器来测试 Servlet 3 的特性:

@Autowired
    ThreadPoolTaskExecutor taskExecutor;

    @RequestMapping(value="{name}", method = RequestMethod.GET)
    public @ResponseBody DeferredResult<MyResponse> getShopInJSON(@PathVariable String name) {

        DeferredResult<MyResponse> df = new DeferredResult<MyResponse>();
        taskExecutor.submit(new MyRunnable(df));    

        return df; 
    }

在单独的线程中,我只执行 5 秒的睡眠命令,之后我将 MyResult POJO 返回到 DeferredResult

我的 web.xml 文件符合 Servlet 3 规范:

<web-app xmlns="http://java.sun.com/xml/ns/javaee"
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://java.sun.com/xml/ns/javaee
                             http://java.sun.com/xml/ns/javaee/web-app_3_0.xsd"
         version="3.0"
         metadata-complete="true">
  <display-name>Archetype Created Web Application</display-name>
    <servlet>
    <async-supported>true</async-supported>
    <servlet-name>mvc-dispatcher</servlet-name>
    <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
    <load-on-startup>1</load-on-startup>
  </servlet>
  <servlet-mapping>
    <servlet-name>mvc-dispatcher</servlet-name>
    <url-pattern>/</url-pattern>
  </servlet-mapping>
</web-app>

我的连接器 tomcat 如下:

 <Connector port="8080" protocol="HTTP/1.1"
                maxThreads="5"
                acceptCount="5"
                connectionTimeout="20000"
                redirectPort="8443" />

现在这是有趣的部分。当运行打开 10 个并发连接的简单程序时,我看到第一个连接只有 5 个连接,第二个连接在第一组释放后提供了 5 个连接(您可以从 time stemps 看到它)。这不是 Servlet 3.0 的行为方式

Fri May 31 01:17:57 IDT 2013: Preparing 10 concurrent connections
Fri May 31 01:18:02 IDT 2013: Output from Server int thread 9 :{"props1":"param1","props2":"param1"}
Fri May 31 01:18:02 IDT 2013: Output from Server int thread 8 :{"props1":"param1","props2":"param1"}
Fri May 31 01:18:02 IDT 2013: Output from Server int thread 4 :{"props1":"param1","props2":"param1"}
Fri May 31 01:18:02 IDT 2013: Output from Server int thread 7 :{"props1":"param1","props2":"param1"}
Fri May 31 01:18:02 IDT 2013: Output from Server int thread 2 :{"props1":"param1","props2":"param1"}
Fri May 31 01:18:07 IDT 2013: Output from Server int thread 1 :{"props1":"param1","props2":"param1"}
Fri May 31 01:18:07 IDT 2013: Output from Server int thread 0 :{"props1":"param1","props2":"param1"}
Fri May 31 01:18:07 IDT 2013: Output from Server int thread 5 :{"props1":"param1","props2":"param1"}
Fri May 31 01:18:07 IDT 2013: Output from Server int thread 6 :{"props1":"param1","props2":"param1"}
Fri May 31 01:18:07 IDT 2013: Output from Server int thread 3 :{"props1":"param1","props2":"param1"}

如果将 Tomcat 连接器更改为

   <Connector connectionTimeout="200000" maxThreads="5" port="8080" protocol="org.apache.coyote.http11.Http11NioProtocol" redirectPort="8443"/>

它就像魅力一样。我不想这样做。根据 Tomcat 文档,我应该收到没有 Http11NioProtocol 连接器的 Servlet 3.0 功能。

怎么了?

【问题讨论】:

  • tikalk.com/java/servlet-3-support-spring-mvc-32 谈到了你提到的同样的问题。
  • @brainOverflow,谢谢,但我是这篇文章的作者 :) 我只是认为这种行为是不正常的,根据 Tomcat 文档 Servlet 3 也应该适用于 BIO。跨度>
  • 哦,好吧...我只是想通过引用该帖子来表示对您的主张的一些支持... :-) 顺便说一句,我遇到了另一个post,他们说:@ 987654331@您是否尝试过使用 AsyncContext 而不是 DeferredResult ?可能是春天在这里引入了一些行为!
  • @brainOverflow,DeferredResult 只是包装器。它具有 AsyncContext 并在请求上调用 startAsync() 方法。使用 NIO 连接器行为正确的事实告诉我们,它更有可能是 Tomcat 行为。

标签: spring tomcat servlets spring-mvc servlet-3.0


【解决方案1】:

您是否尝试将 maxThreads 增加到 10?看起来您的 Tomcat 连接器上限为 5 个线程

【讨论】:

  • 这是真的,根据 Servlet 3.0 规范,这 5 个线程应该立即释放。这就是异步测试的方式。
  • 那么你期待什么,那些tomcat工作线程在你的JSON响应返回之前被释放?那么如果线程已经消失了,它将来如何返回呢?也许它是异步的,因为您的 servlet 方法可以返回一个“承诺”,它将在未来写入响应然后退出。然而,tomcat 工作线程必须处于活动状态,直到这个承诺得到履行
  • 也许至少protocol="HTTP/1.1"tomcat线程是这样工作的
  • 我预计所有 10 个结果将在提交后的同一时间(5 秒)内返回,这是因为 Tomcat 将继续执行 5 个请求并将其传递给另一个工作人员并立即继续到另一个 5 请求,我在使用 nio 连接器时遇到了这种行为。
【解决方案2】:

问题是由于您的 Tomcat 配置中的 maxThreads=5 设置造成的。

对于非NIO的情况,这个设置不仅限制了请求处理线程的最大数量,还限制了最大连接数!

由于您没有指定 maxConnections,它正在为 maxConnections 选择一个默认值。 以下是Tomcat doc 中关于它如何为 maxConnections 选择默认值的摘录:

maxConnections : 服务器的最大连接数 将在任何给定时间接受和处理。当这个号码被 达到,服务器将不再接受任何连接,直到 连接数低于此值。操作系统可能 仍然接受基于 acceptCount 设置的连接。默认 值因连接器类型而异。 对于 BIO,默认值为 maxThreads 除非使用 Executor 在这种情况下默认将 是执行者的 maxThreads 的值。 对于 NIO,默认为 10000。对于 APR/native,默认值为 8192。

您可以显式指定 maxConnections="10"(例如)设置来覆盖此默认行为。然后,您应该看到,无论使用何种连接器,您都可以处理 10 个并行请求。我试过了,效果很好。

【讨论】:

    猜你喜欢
    • 2011-03-21
    • 2014-09-14
    • 2011-12-19
    • 2011-05-05
    • 2016-05-30
    • 2014-06-29
    • 2011-09-13
    • 2014-06-12
    • 2015-11-13
    相关资源
    最近更新 更多