浅谈servlet3异步原理与实践

浅谈servlet3异步原理与实践

什么是Servlet3异步

Servlet3.0规范中增加了异步处理的功能,使Servlet容器的性能可以进一步提升。Servlet3.0之前,servlet都是由线程来处理的,每次请求都需要创建一个线程,处理完请求后才会销毁这个线程。如果请求量很大,反复创建销毁线程的过程会给服务器造成很大负担。

而异步Servlet能够处理复杂和耗时的操作,而不用将请求交给固定的线程进行处理。异步Servlet通过启用一个线程来处理某个请求,然后在到达I/O操作之前将控制权交回到Servlet容器。这样一来,线程便得到释放,不会阻塞应用程序的其他部分,最终提高了整个应用程序的性能。

Servlet3异步实现代码

在Servlet3中,异步处理需要先调用 AsyncContextstartAsync() 方法来开启异步模式。

接下来我们来看一个使用异步的Servlet示例:

@WebServlet("/asyncServlet")
public class AsyncServlet extends HttpServlet {

    @Override
    protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {

        final AsyncContext asyncContext = req.startAsync();
        asyncContext.setTimeout(30_000L);
        asyncContext.start(new Runnable() {
            @Override
            public void run() {
                try {
                    Thread.sleep(5_000L);
                    PrintWriter writer = asyncContext.getResponse().getWriter();
                    writer.println("Hello, World!");
                    writer.flush();
                    asyncContext.complete();
                } catch (Exception e) {
                    throw new RuntimeException(e);
                }
            }
        });
    }
}

在上面的代码中,当客户端访问 /asyncServlet 地址时,服务器会将请求交由 HttpServlet处理。正如之前解释的那样,在代码中我们需要调用 startAsync() 来开启异步模式。

接下来,我们在异步 Servlet 中创建一个新的线程(我们使用Java的 Lambda 表达式实现 Runnable 的 run() 方法),并在这个线程中处理请求。在这个例子中,我们让线程休眠5秒钟,然后再向客户端返回“Hello, World!”的消息。

最后调用 complete() 方法来告知Servlet容器这个请求已经处理完毕。GetMethod实例处理不会刷新并提交响应。

进阶使用

除了在 doGet() 里创建异步上下文之外,还可以在 doPost() 或者 doPut() 里使用异步上下文。如果你希望有多个异步操作,你可以创建多个 Runnable 的实例,并使用多个线程并行工作,从而快速响应客户端。

示例二

@WebServlet("/asyncServlet")
public class AsyncServlet extends HttpServlet {      
    @Override
    protected void doGet(HttpServletRequest req, HttpServletResponse resp)
            throws ServletException, IOException {
        AsyncContext asyncContext = req.startAsync();
        asyncContext.setTimeout(9000); //设置异步上下文的超时时间
        asyncContext.addListener(new AsyncListener() { 
            @Override
            public void onComplete(AsyncEvent asyncEvent) throws IOException, ServletException {
                LOG.info("执行 onComplete 方法. ");
            }

            @Override
            public void onError(AsyncEvent asyncEvent) throws IOException, ServletException {
                LOG.info("执行 onError 方法 time={}", System.currentTimeMillis());
            }

            @Override
            public void onTimeout(AsyncEvent asyncEvent) throws IOException, ServletException {
                LOG.info("执行 onTimeout 方法 time={}", System.currentTimeMillis());
            }

            @Override
            public void onStartAsync(AsyncEvent asyncEvent) throws IOException, ServletException {
                LOG.info("执行 onStartAsync 方法 time={}", System.currentTimeMillis());
            }
        });
        asyncContext.start(new Runnable() {
            @Override
            public void run() {
                //模拟一个阻塞操作
                try {
                    Thread.sleep(8000);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
                //触发OnComplete事件
                asyncContext.complete(); 
            }
        });   
    }
}

在这个示例中,我们使用了 addListener() 方法来添加多个异步事件的监听器。如果我们在 AsyncServlet 内部执行一个耗时长的操作,例如等待另一个远程服务返回数据,我们需要将超时时间设置的长一些,否则异步 Operaion 会超时导致失败。所以在代码中,我们将超时时间设置为了 9 秒。

最终,在异步完成后, AsyncListener#onComplete() 方法会被调用。如果异步 Operation 超时, AsyncListener#onTimeout() 方法会被调用。

总结

到此,我们就详细讲解了 Servlet 3 异步处理的基本原理和实现,在实际开发中,使用异步能够有效的提升服务器的响应速度,节省服务器资源,加速系统的处理速度。为了防止超时,我们需要灵活的设置超时时间,并为异步事件添加监听器,以便及时发现并处理回调事件。

本站文章如无特殊说明,均为本站原创,如若转载,请注明出处:浅谈servlet3异步原理与实践 - Python技术站

(0)
上一篇 2023年5月20日
下一篇 2023年5月20日

相关文章

  • Java初学者问题图解(动力节点Java学院整理)

    对于“Java初学者问题图解(动力节点Java学院整理)”这个主题,我可以提供以下完整攻略: Java初学者问题图解 前言 Java作为一门广受欢迎的编程语言,吸引了许多初学者,但在学习过程中难免会遇到问题。本文就对Java学习过程中常见的问题进行了整理,并提供了图解和解决方法。 字符串问题 1. 字符串比较 问题描述:如何比较两个字符串是否相等? 问题分析…

    Java 2023年5月25日
    00
  • 之前很火给女朋友推送微信服务号消息是怎么做的?

    经过了几天的奋战,终于把微信服务号的模板消息给写完了。后端其实没花多少时间,因为之前已经有同学提过pull request了,我在这基础之上简单优化下就完事了,主要的时间都是花在前端上,对前端页面和参数的适配比较麻烦。 消息推送平台?推送下发【邮件】【短信】【微信服务号】【微信小程序】【企业微信】【钉钉】等消息类型。 https://gitee.com/zh…

    Java 2023年4月18日
    00
  • 如何创建线程池?

    以下是关于如何创建线程池的完整使用攻略: 如何创建线程池? 在Java中,可以使用java.util.concurrent包中的Executor框架来创建线程池。Executor框架提供了一组于管理线程池的接口和类,可以方便地创建和管理线程池。 创建线程池的步骤 创建线程池的步骤如下: 创建一个ExecutorService对象,该对象是一个线程池的管理器。…

    Java 2023年5月12日
    00
  • 解析Java异步之call future

    解析Java异步之call future 在Java中,Future是JDK5中新增加的一个接口,可以用于异步调用方法,也就是说在调用Future的get方法时会阻塞,直到异步调用结束并返回结果。下面是一些详细步骤和示例说明。 1. 创建线程池 Java中的Future可以通过ExecutorService的submit方法来实现异步调用。因此我们需要先创建…

    Java 2023年5月26日
    00
  • Java中生成随机数的实现方法总结

    Java中生成随机数的实现方法总结 在Java中,生成随机数是一种广泛使用的功能,常见的应用场景包括加密、生成验证码、游戏中的随机事件等。本文将介绍Java中生成随机数的几种实现方法。 方法一:使用Math类生成随机数 最简单的生成随机数的方法是使用java.util.Math类中的静态方法random()。每次调用它都会生成一个0到1之间的随机数。 pub…

    Java 2023年5月26日
    00
  • Java如何把文件夹打成压缩包并导出

    Java 通过 ZipOutputStream 类提供了将一个文件夹打成压缩包并导出的功能。以下是详细的攻略: 第一步:导入ZipOutputStream类 为了使用ZipOutputStream类,需要先将其导入到你的Java代码中。可以使用以下代码: import java.io.FileOutputStream; import java.io.IOEx…

    Java 2023年5月19日
    00
  • js判断IE6/IE7/FF的代码[XMLHttpRequest]

    判断IE6/IE7/FF的代码是前端开发中常用的技巧之一,可以根据用户使用的浏览器类型,来应用不同的兼容性处理方式,提高网站的访问体验和兼容性。 这里我分享一下判断IE6/IE7/FF的代码的攻略步骤及其代码示例,希望对大家有所帮助。 步骤一:创建XMLHttpRequest对象 在JavaScript代码中,创建一个XMLHttpRequest对象,用来请…

    Java 2023年6月15日
    00
  • 推荐一个可以提高生产力的在线游戏

    很久没推荐好玩的工具了,今天给家推荐一个非常有意思的游戏:Habitica Habitica除了是个游戏之外,居然还是一个生产力应用! 为什么说Habitica还是个生产力应用呢?因为它还可以帮助我们养成习惯! 通过Habitica,我们可以用它的每日目标和代办事项列表功能来跟踪和管理你的习惯 在完成任务之后,你可以以此来升级你的虚拟角色,同时解锁游戏中更多…

    Java 2023年4月25日
    00
合作推广
合作推广
分享本页
返回顶部