我不了解 servlets 3.0 API 中的异步支持

Posted

技术标签:

【中文标题】我不了解 servlets 3.0 API 中的异步支持【英文标题】:I don't understand Async support in servlets 3.0 API 【发布时间】:2012-04-21 08:58:48 【问题描述】:

我有 Java SE 背景,做过一些 servlet 教程并阅读了 Head First JSP 和 servlet。我正在阅读 JavaWorld.com 关于异步支持的文章,但我不太明白。

什么是异步? Ajax 和 Servlet Async 有什么区别?

P.S 我有 ajax 的 php 背景,我知道这个概念,但我没有用 java 尝试过

【问题讨论】:

【参考方案1】:

在传统的 Servlet 模型中,通常是 1 个请求对应 1 个线程。

这些线程通常来自一个由 Servlet 容器管理的池。 Servlet 容器只有在该池中有空闲线程时才能处理新请求。只要你自己的代码忙于处理请求,线程就不是空闲的。

在某些情况下,打破这种模式可能是值得的。发生的情况是请求通过这样的 Servlet 容器托管线程到达 Servlet,然后您的代码要求异步执行。然后您可以从 Servlet 请求返回,容器线程将被释放。

与同步请求处理相反,这不会提交任何响应,也不会关闭连接。相反,您可以将异步上下文交给另一个线程池,该线程池可以获取它,当某个线程有空闲处理它时,为它提供服务并能够写入响应。

一个例子:

@WebServlet(urlPatterns = "/somepath", asyncSupported = true)
public class AsyncServlet extends HttpServlet 

    @EJB
    private AsyncBean asyncBean;

    public void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException 
        AsyncContext asyncContext = request.startAsync();

        // The following line will not block and return immediately
        asyncBean.doAsyncStuff(asyncContext);

     // Shortly after this method has ended, thread will be returned to pool

AsyncBean 被实现为:

@Stateless
public class AsyncBean 

    @Asynchronous
    public void doAsyncStuff(AsyncContext asyncContext) throws IOException 
        asyncContext.getResponse().getWriter().write("test");
    

在上面的代码中,在您从AsyncServlet#doGet() 方法返回后不久,Servlet 线程将返回到池中。用于执行AsyncBean#doAsyncStuff() 的“请求”(任务)将被放入队列中以供 EJB 线程池获取。

为什么以及何时使用它的答案并不那么简单。如果您只是想保留线程,那么在上述情况下,您将用一个线程池中的一个线程交换另一个线程(在这种情况下是 Servlet 池与 EJB 异步池),净收益不会那么多。你也可以给你的 Servlet 线程池一个额外的线程。

在更高级的场景中,您可以对请求进行更细粒度的管理;将它们分成多个任务,并让线程池为这些任务提供服务。例如。想象一下 100 个 10MB 文件的下载请求,由 10 个线程处理,循环给予每次发送 100KB 到每个请求。

另一个应用程序是需要等待来自外部系统的数据的请求,并且该外部系统能够发送可以中继回请求者的消息。 IE。数据库调用在这里没有意义,因为无论如何您都需要另一个线程等待响应。然后,您将再次将一个线程更改为另一个线程。但是,如果您需要等待收到的电子邮件,那么一个线程可以等待任何电子邮件并将其中继到任何暂停的请求。

【讨论】:

非常感谢Arjan,第一段非常清晰易懂。 从可伸缩性的角度来看,我不完全理解将一个线程从一个池移动到另一个池会有什么不同。我看到了将服务器侦听器线程返回到池中的意义,但我真的不知道这是否可以大大提高您的应用程序可伸缩性。 交换线程无助于可扩展性,但请参阅下载示例。几个线程可能能够提供许多异步连接。如果请求可以分解为可以排队的多个任务等,那么考虑这种模式可能是值得的。否则,确实没有太多预期的好处。 谢谢!我已经在网上搜索了有关此主题的信息,但我发现的几乎所有示例都只交换了一个线程,并且不讨论该问题!我认为大多数人只是(愚蠢地)使用异步处理而不知道他们在做什么/为什么要这样做。 在您的示例中,您必须像 asyncContext.complete() 那样调用 complete() 来完成该过程,否则 jQuery、ajax 客户端调用会出错:

以上是关于我不了解 servlets 3.0 API 中的异步支持的主要内容,如果未能解决你的问题,请参考以下文章

Servlet 3.0 特性

如何使用 R 处理 OLS 中的异方差性

如何配置 maven 以使用 servlet 3

使用 Servlet 3.0 以编程方式控制登录

Servlet 3.0笔记之异步请求Comet推送iFrame示范

Spring mvc 中的 Servlet