浅谈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日

相关文章

  • SpringBoot中处理的转发与重定向方式

    SpringBoot中处理转发与重定向的方式有以下几种: 转发(forward) 使用转发的方式可以将请求转发给另一个URL处理,同时请求的地址栏不会发生改变。SpringBoot中使用ModelAndView来实现请求转发。示例如下: @RequestMapping("/test") public ModelAndView test()…

    Java 2023年6月15日
    00
  • 详解MyBatis开发Dao层的两种方式(Mapper动态代理方式)

    详解MyBatis开发Dao层的两种方式(Mapper动态代理方式) MyBatis是一种优秀的ORM工具,它提供了多种开发Dao层的方式。其中,Mapper动态代理方式是一种非常常用的Dao层开发方式。本篇攻略将详细讲解Mapper动态代理方式的实现过程和示例。 动态代理 Mapper动态代理方式是基于Java动态代理技术实现的。Java动态代理是指,在运…

    Java 2023年5月19日
    00
  • Java中的定时器Timer详解

    Java中的定时器Timer详解 什么是定时器Timer 定时器是一种Java中的工具,它可以在指定的时间间隔内重复执行特定任务或者仅仅执行一次特定的任务。 Timer的使用方法 该类包含两个直接实现接口Runnable的类:Task和TimerThread,其中TimerThread作为线程实现了计时,而Task实现了具体的任务内容。 Timer time…

    Java 2023年5月20日
    00
  • IDEA生成可运行jar包(包含第三方jar包)流程详解

    下面是”IDEA生成可运行jar包(包含第三方jar包)流程详解”的完整攻略: 一、前置条件 在进行下面的步骤之前,必须确保满足以下条件: 安装了Java开发工具包(JDK) 安装了IntelliJ IDEA开发环境 确保本地已经存在可运行程序的代码 二、生成可运行jar包 1. 配置Maven 在IntelliJ IDEA中打开Maven Projects…

    Java 2023年5月19日
    00
  • java实现电话本系统

    Java实现电话本系统攻略 1. 系统概述 Java实现电话本系统,是指使用Java编程语言和相关的开发框架实现一个方便用户管理联系人信息的系统。系统的目标是支持联系人的增删改查、分组管理、导入导出、备份恢复等功能。具体而言,系统将包括以下模块: 用户登录和注册:为用户提供账号管理功能,增强系统的安全性; 联系人管理:用户可以查看、添加、删除、修改联系人的信…

    Java 2023年5月19日
    00
  • 没有外网IDEA离线使用maven仓库的方法

    请看以下攻略: 问题背景 在没有外网的情况下,我们在使用 IDEA 进行开发时,如何使用 Maven 的依赖包? 解决方案 1. 下载 Maven 仓库依赖包 在有外网的环境下,打开 IDEA,新建一个空项目,在 pom.xml 文件中添加需要的依赖,然后将项目打包,此时 Maven 会将依赖包下载到本地仓库(默认路径为用户目录下的 .m2 目录)中。将本地…

    Java 2023年5月20日
    00
  • java String[]字符串数组自动排序的简单实现

    下面是 “java String[]字符串数组自动排序的简单实现” 的完整攻略: 1. 问题背景 对于 Java 开发者而言,经常需要进行字符串数组的排序操作。比如,将一组字符串按照字母表顺序进行排序。手动实现这些排序操作需要编写很多代码,而且难以维护。本文将介绍一个简单的实现方法,通过调用系统自带的 Arrays.sort() 方法来实现字符串数组的自动排…

    Java 2023年5月26日
    00
  • Java 轻松入门了解File类的使用

    Java 轻松入门了解 File 类的使用 在 Java 中,File 类是一个常见的类,用于对文件或目录进行操作。在我们进行 Java 开发时,经常需要使用到文件或目录的操作,为了更好地使用 File 类,我们需要完全了解它的使用方法。本文将从以下几个方面详细讲解 File 类的使用。 1. 创建 File 对象 创建 File 对象有两种方式,一种是使用…

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