文章详情

短信预约-IT技能 免费直播动态提醒

请输入下面的图形验证码

提交验证

短信预约提醒成功

Javaservlet通过事件驱动进行高性能长轮询详解

2024-04-02 19:55

关注

servlet3.0的异步原理

servlet基础就不做介绍了,这里就介绍servlet3.0的一个重要的新特性:异步。

servlet3.0原理图:

servlet3.0将tomcat工作线程和业务线程分隔开来,这样tomcat工作线程就能处理更多的连接请求。业务线程主要处理业务逻辑。在这种模式下,可以更好的分配业务线程的数量,也能根据不同的业务,设置不同的线程数量,更加灵活。

注意:tomcat的NIO和servlet3.0的异步没有关系。tomcat NIO模式,是对于http连接的处理使用,目的是用更少的线程处理更多的连接。servlet3.0是在tomcat工作线程的处理逻辑上实现异步处理功能。

使用servlet3.0实现长轮询

什么是长轮询:

短轮询、长轮询和长连接比较:

优点:后端程序编写比较容易,适于小型应用。。

缺点:请求中有大半是无用,浪费带宽和服务器资源。

优点:在无消息的情况下不会频繁的请求。

缺点:服务器hold连接会消耗资源。

优点:可靠性高,实时性高。

缺点:实现复杂,要维护心跳,服务器维持连接消耗资源。

长轮询实现

原理图:

下面看下具体实现:

事件定义,这里只是定义一个简单的事件:

package com.hiwe.demo.event;
import javax.servlet.AsyncContext;
public class HttpEvent {
    
    private String requestName;
    private AsyncContext asyncContext;
    public HttpEvent(String requestName,AsyncContext asyncContext){
        this.requestName = requestName;
        this.asyncContext = asyncContext;
    }
    public String getRequestName() {
        return requestName;
    }
    public AsyncContext getAsyncContext() {
        return asyncContext;
    }
}

事件管理器:

package com.hiwe.demo.event;
import javax.servlet.AsyncContext;
import java.io.IOException;
import java.io.PrintWriter;
import java.util.HashMap;
import java.util.Map;
public class EventManager {
    private final static Map<String,HttpEvent> subHttpEvents = new HashMap<>();
    
    public static void addHttpEvent(HttpEvent event){
        subHttpEvents.put(event.getRequestName(),event);
    }
    
    public static void onEvent(String requestName){
        HttpEvent httpEvent = subHttpEvents.get(requestName);
        if(httpEvent==null){
            return;
        }
        AsyncContext asyncContext = httpEvent.getAsyncContext();
        try {
            PrintWriter writer = asyncContext.getResponse().getWriter();
            writer.print(requestName+" request success!");
            writer.flush();
            asyncContext.complete();
            subHttpEvents.remove(requestName);
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
}

异步请求监听器:

package com.hiwe.demo.listener;
import javax.servlet.AsyncContext;
import javax.servlet.AsyncEvent;
import javax.servlet.AsyncListener;
import javax.servlet.ServletResponse;
import javax.servlet.annotation.WebListener;
import java.io.IOException;
import java.io.PrintWriter;
@WebListener
public class AppAsyncListener implements AsyncListener {
    @Override
    public void onComplete(AsyncEvent asyncEvent) throws IOException {
        System.out.println("AppAsyncListener onComplete");
        // we can do resource cleanup activity here
    }
    @Override
    public void onError(AsyncEvent asyncEvent) throws IOException {
        System.out.println("AppAsyncListener onError");
        //we can return error response to client
    }
    @Override
    public void onStartAsync(AsyncEvent asyncEvent) throws IOException {
        System.out.println("AppAsyncListener onStartAsync");
        //we can log the event here
    }
    
    @Override
    public void onTimeout(AsyncEvent asyncEvent) throws IOException {
        AsyncContext asyncContext = asyncEvent.getAsyncContext();
        ServletResponse response = asyncEvent.getAsyncContext().getResponse();
        PrintWriter out = response.getWriter();
        //返回code码,以便前端识别,并重建请求
        out.write(201+" longPolling timeout");
        out.flush();
        asyncContext.complete();
    }
}

长轮询接口:

package com.hiwe.demo.controller;
import com.hiwe.demo.listener.AppAsyncListener;
import com.hiwe.demo.event.EventManager;
import com.hiwe.demo.event.HttpEvent;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;
import javax.servlet.AsyncContext;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
@RestController
@RequestMapping("/app")
public class AsyncController {
    
    @GetMapping("/asyncGet")
    public void getDemo(@RequestParam(value = "requestName") String requestName, HttpServletRequest request, HttpServletResponse response){
        //开启异步支持
        request.setAttribute("org.apache.catalina.ASYNC_SUPPORTED", true);
        AsyncContext asyncContext = request.startAsync();
        //添加监听器
        asyncContext.addListener(new AppAsyncListener());
        //设置超时时间
        asyncContext.setTimeout(30000);
        //添加到事件集合中去
        HttpEvent httpEvent = new HttpEvent(requestName, asyncContext);
        EventManager.addHttpEvent(httpEvent);
    }
    
    @GetMapping("/trigger")
    public void triggerDemo(@RequestParam(value = "requestName") String requestName){
        EventManager.onEvent(requestName);
    }
}

以上一个简单的长轮询就实现了,我们可以进行一下测试:

启动应用后访问:http://localhost:8080/app/asyncGet?requestName=123

服务端因为数据未准备就绪,所以会hold住请求。当等待30s后会返回超时信息:

我们在30s内触发event:http://localhost:8080/app/trigger?requestName=123

返回:

以上整个长轮询实现完成了,如果有错误,欢迎指正!

到此这篇关于Java servlet通过事件驱动进行高性能长轮询详解的文章就介绍到这了,更多相关Java 高性能长轮询内容请搜索编程网以前的文章或继续浏览下面的相关文章希望大家以后多多支持编程网!

阅读原文内容投诉

免责声明:

① 本站未注明“稿件来源”的信息均来自网络整理。其文字、图片和音视频稿件的所属权归原作者所有。本站收集整理出于非商业性的教育和科研之目的,并不意味着本站赞同其观点或证实其内容的真实性。仅作为临时的测试数据,供内部测试之用。本站并未授权任何人以任何方式主动获取本站任何信息。

② 本站未注明“稿件来源”的临时测试数据将在测试完成后最终做删除处理。有问题或投稿请发送至: 邮箱/279061341@qq.com QQ/279061341

软考中级精品资料免费领

  • 历年真题答案解析
  • 备考技巧名师总结
  • 高频考点精准押题
  • 2024年上半年信息系统项目管理师第二批次真题及答案解析(完整版)

    难度     813人已做
    查看
  • 【考后总结】2024年5月26日信息系统项目管理师第2批次考情分析

    难度     354人已做
    查看
  • 【考后总结】2024年5月25日信息系统项目管理师第1批次考情分析

    难度     318人已做
    查看
  • 2024年上半年软考高项第一、二批次真题考点汇总(完整版)

    难度     435人已做
    查看
  • 2024年上半年系统架构设计师考试综合知识真题

    难度     224人已做
    查看

相关文章

发现更多好内容

猜你喜欢

AI推送时光机
位置:首页-资讯-后端开发
咦!没有更多了?去看看其它编程学习网 内容吧
首页课程
资料下载
问答资讯