Spring Boot實(shí)現(xiàn)異步請(qǐng)求(Servlet 3.0)
在spring 3.2 及以后版本中增加了對(duì)請(qǐng)求的異步處理,旨在提高請(qǐng)求的處理速度降低服務(wù)性能消耗。
在我們的請(qǐng)求中做了耗時(shí)處理,當(dāng)并發(fā)請(qǐng)求的情況下,為了避免web server的連接池被長(zhǎng)期占用而引起性能問(wèn)題,調(diào)用后生成一個(gè)非web的服務(wù)線程來(lái)處理,增加web服務(wù)器的吞吐量。
為此 Servlet 3.0 新增了請(qǐng)求的異步處理,Spring 也在此基礎(chǔ)上做了封裝處理。
本文還是以代碼例子的方式說(shuō)明如何在 Spring Boot 中應(yīng)用異步請(qǐng)求。
首先說(shuō)一下幾個(gè)要點(diǎn):
1、@WebFilter 和 @WebServlet 注解中的 asyncSupported = true 屬性
異步處理的servlet若存在過(guò)濾器,則過(guò)濾器的注解@WebFilter應(yīng)設(shè)置asyncSupported=true,
否則會(huì)報(bào)錯(cuò) A filter or servlet of the current chain does not support asynchronous operations.
2、@EnableAsync 注解
Spring Boot 默認(rèn)添加了一些攔截 /* 的過(guò)濾器,因?yàn)?/* 會(huì)攔截所有請(qǐng)求,按理說(shuō)我們也要設(shè)置 asyncSupported=true 屬性。因?yàn)檫@些過(guò)濾器都是 Spring Boot 初始化的,所以它提供了 @EnableAsync 注解來(lái)統(tǒng)一配置,該注解只針對(duì) “非 @WebFilter 和 @WebServlet 注解的有效”,所以我們自己定義的 Filter 還是需要自己配置 asyncSupported=true 的。
3、AsyncContext 對(duì)象
獲取一個(gè)異步請(qǐng)求的上下文對(duì)象。
4、asyncContext.setTimeout(20 * 1000L);
我們不能讓異步請(qǐng)求無(wú)限的等待下去,通過(guò) setTimeout 來(lái)設(shè)定最大超時(shí)時(shí)間。
下面通過(guò)兩種方式來(lái)測(cè)試異步任務(wù):
先在 SpringBootSampleApplication 上添加 @EnableAsync 注解。
再檢查所有自定義的Filter,如存在如下兩種情況需要配置 asyncSupported=true
1) 自定義Filter 攔截了 /*
2) 某Filter 攔截了 /shanhy/* ,我們需要執(zhí)行的異步請(qǐng)求的 Servlet 為 /shanhy/testcomet
方法一:原生Servlet方式
package org.springboot.sample.servlet;
import java.io.IOException;
import java.util.Queue;
import java.util.concurrent.LinkedBlockingQueue;
import java.util.concurrent.TimeUnit;
import javax.servlet.AsyncContext;
import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
/**
* HTTP長(zhǎng)連接實(shí)現(xiàn)
*
* @author 單紅宇(365384722)
* @myblog http://blog.csdn.net/catoop/
* @create 2016年3月29日
*/
@WebServlet(urlPatterns = "/xs/cometservlet", asyncSupported = true)
//異步處理的servlet若存在過(guò)濾器,則過(guò)濾器的注解@WebFilter應(yīng)設(shè)置asyncSupported=true,
//否則會(huì)報(bào)錯(cuò)A filter or servlet of the current chain does not support asynchronous operations.
public class CometServlet extends HttpServlet {
private static final long serialVersionUID = -8685285401859800066L;
private final Queue<AsyncContext> asyncContexts = new LinkedBlockingQueue<>();
private final Thread generator = new Thread("Async Event generator") {
@Override
public void run() {
while (!generator.isInterrupted()) {// 線程有效
try {
while (!asyncContexts.isEmpty()) {// 不為空
TimeUnit.SECONDS.sleep(10);// 秒,模擬耗時(shí)操作
AsyncContext asyncContext = asyncContexts.poll();
HttpServletResponse res = (HttpServletResponse) asyncContext.getResponse();
res.getWriter().write("{\"result\":\"OK - "+System.currentTimeMillis()+"\"}");
res.setStatus(HttpServletResponse.SC_OK);
res.setContentType("application/json");
asyncContext.complete();// 完成
}
} catch (InterruptedException e) {
Thread.currentThread().interrupt();
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
}
}
};
@Override
public void init() throws ServletException {
super.init();
generator.start();
}
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
System.out.println(">>>>>>>>>>CometServlet Request<<<<<<<<<<<");
doPost(req, resp);
}
@Override
protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
AsyncContext asyncContext = req.startAsync();
asyncContext.setTimeout(20 * 1000L);
asyncContexts.offer(asyncContext);
}
@Override
public void destroy() {
super.destroy();
generator.interrupt();
}
}
方法二:Controller 方式
@Controller
public class PageController {
@RequestMapping("/async/test")
@ResponseBody
public Callable<String> callable() {
// 這么做的好處避免web server的連接池被長(zhǎng)期占用而引起性能問(wèn)題,
// 調(diào)用后生成一個(gè)非web的服務(wù)線程來(lái)處理,增加web服務(wù)器的吞吐量。
return new Callable<String>() {
@Override
public String call() throws Exception {
Thread.sleep(3 * 1000L);
return "小單 - " + System.currentTimeMillis();
}
};
}
}
最后寫(xiě)一個(gè)comet.jsp頁(yè)面測(cè)試:
<%@ page pageEncoding="UTF-8"%>
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
<html>
<head>
<title>長(zhǎng)連接測(cè)試</title>
<script type="text/javascript" src="${pageContext.request.contextPath }/webjarslocator/jquery/jquery.js"></script>
<script type="text/javascript">
$(function(){
function longPolling(){
$.getJSON('${pageContext.request.contextPath }/xs/cometservlet', function(data){
console.log(data.result);
$('#n1').html(data.result);
longPolling();
});
}
longPolling();
function longPolling2(){
$.get('${pageContext.request.contextPath }/async/test', function(data){
console.log(data);
$('#n2').html(data);
longPolling2();
});
}
longPolling2();
});
</script>
</head>
<body>
<h1>長(zhǎng)連接測(cè)試</h1>
<h2 id="n1"></h2>
<h2 id="n2"></h2>
</body>
</html>
以上就是本文的全部?jī)?nèi)容,希望對(duì)大家的學(xué)習(xí)有所幫助,也希望大家多多支持腳本之家。
相關(guān)文章
使用Java實(shí)現(xiàn)百萬(wàn)Excel數(shù)據(jù)導(dǎo)出
這篇文章主要為大家詳細(xì)介紹了如何使用Java實(shí)現(xiàn)百萬(wàn)Excel數(shù)據(jù)導(dǎo)出,文中的示例代碼講解詳細(xì),具有一定的借鑒價(jià)值,有需要的小伙伴可以參考一下2024-03-03
使用idea搭建一個(gè)spring mvc項(xiàng)目的圖文教程
這篇文章主要介紹了使用idea直接創(chuàng)建一個(gè)spring mvc項(xiàng)目的圖文教程,本文通過(guò)圖文并茂的方式給大家介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下2020-03-03
mybatis-plus實(shí)現(xiàn)四種lambda表達(dá)式方式
使用了lambda表達(dá)式 可以通過(guò)方法引用的方式來(lái)使用實(shí)體字段名的操作,本文主要介紹了mybatis-plus實(shí)現(xiàn)四種lambda表達(dá)式方式,具有一定的參考價(jià)值,感興趣的可以了解一下2024-06-06
SpringAMQP消息隊(duì)列實(shí)戰(zhàn)教程
這篇文章主要介紹了SpringAMQP消息隊(duì)列的相關(guān)知識(shí),本文通過(guò)實(shí)例代碼給大家介紹的非常詳細(xì),感興趣的朋友一起看看吧2024-02-02
關(guān)于slf4j_log4j2源碼學(xué)習(xí)心得
這篇文章主要介紹了slf4j_log4j2源碼學(xué)習(xí)心得,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2021-12-12
將springboot項(xiàng)目生成可依賴的jar并引入到項(xiàng)目中的方法
SpringBoot項(xiàng)目默認(rèn)打包的是可運(yùn)行jar包,也可以打包成不可運(yùn)行的jar包,本文給大家介紹將springboot項(xiàng)目生成可依賴的jar并引入到項(xiàng)目中的方法,感興趣的朋友一起看看吧2023-11-11
Java實(shí)現(xiàn)高效隨機(jī)數(shù)算法的示例代碼
這篇文章主要介紹了Java實(shí)現(xiàn)高效隨機(jī)數(shù)算法的示例代碼,小編覺(jué)得挺不錯(cuò)的,現(xiàn)在分享給大家,也給大家做個(gè)參考。一起跟隨小編過(guò)來(lái)看看吧2019-02-02
MyBatis配置的應(yīng)用與對(duì)比jdbc的優(yōu)勢(shì)
這篇文章主要介紹了MyBatis配置的使用與相對(duì)于jdbc的優(yōu)勢(shì),文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧2022-07-07

