Maison  >  Article  >  Java  >  Explication détaillée des deux méthodes de requête asynchrone de Spring Boot

Explication détaillée des deux méthodes de requête asynchrone de Spring Boot

Y2J
Y2Joriginal
2017-05-08 15:54:073449parcourir

Le traitement asynchrone des requêtes a été ajouté au printemps 3.2 et aux versions ultérieures. Cet article présente principalement Spring Boot pour implémenter les requêtes asynchrones (Servlet 3.0. Les amis intéressés peuvent s'y référer).

Le traitement asynchrone des requêtes a été ajouté au printemps 3.2 et dans les versions ultérieures, dans le but d'augmenter la vitesse de traitement des requêtes et de réduire la consommation de performances du service.

Nous avons effectué un traitement fastidieux dans notre requête. Dans le cas de requêtes simultanées, afin d'éviter les problèmes de performances causés par une occupation à long terme du pool de connexions du serveur Web, un thread de service non Web est utilisé. généré après l'appel pour le traitement, augmente le débit du serveur Web.

Pour cette raison, Servlet 3.0 a ajouté le traitement asynchrone des requêtes, et Spring l'a également encapsulé sur cette base.

Cet article utilise toujours des exemples de code pour expliquer comment appliquer des requêtes asynchrones dans Spring Boot.

Permettez-moi d'abord de parler de quelques points clés :

1 asyncSupported = true dans les annotations @WebFilter et @WebServlet Attributs.

S'il y a un filtre dans le servlet traité de manière asynchrone, l'annotation @WebFilter du filtre doit être définie asyncSupported=true,

Sinon , une erreur Un filtre ou sera signalé. Le servlet de la chaîne actuelle ne prend pas en charge les opérations asynchrones.

2 annotation @EnableAsync

Spring Boot en ajoute. filtre pour intercepter /* par défaut Parce que /* interceptera toutes les requêtes, il va de soi que nous devrions également définir l'attribut asyncSupported=true. Étant donné que ces filtres sont initialisés par Spring Boot, il fournit l'annotation @EnableAsync pour une configuration unifiée. Cette annotation n'est valable que pour les "annotations non-@WebFilter et @WebServlet", donc le filtre que nous définissons doit toujours configurer asyncSupported= true nous-mêmes. .

3. AsyncContext Object

Obtenir l'objet contextuel d'une requête asynchrone.

4. asyncContext.setTimeout(20 * 1000L);

Nous ne pouvons pas laisser les requêtes asynchrones attendre indéfiniment et définir le délai d'expiration maximum via setTimeout .

Testez les tâches asynchrones de deux manières :

Ajoutez d'abord l'annotation @EnableAsync sur SpringBootSampleApplication.

Vérifiez à nouveau tous les filtres personnalisés. S'il y a deux situations ci-dessous, vous devez configurer asyncSupported=true

1) Interceptions de filtres personnalisés /*

2) Un certain filtre intercepte /shanhy/*, et la requête asynchrone Servlet que nous devons exécuter est /shanhy/testcomet

Méthode 1 : méthode de servlet natif

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长连接实现
 *
 * @author 单红宇(365384722)
 * @myblog http://blog.csdn.net/catoop/
 * @create 2016年3月29日
 */
@WebServlet(urlPatterns = "/xs/cometservlet", asyncSupported = true)
//异步处理的servlet若存在过滤器,则过滤器的注解@WebFilter应设置asyncSupported=true,
//否则会报错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);// 秒,模拟耗时操作
      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();
 }
}

Méthode 2 : Méthode du contrôleur

@Controller
public class PageController {

 @RequestMapping("/async/test")
 @ResponseBody
 public Callable<String> callable() {
  // 这么做的好处避免web server的连接池被长期占用而引起性能问题,
  // 调用后生成一个非web的服务线程来处理,增加web服务器的吞吐量。
  return new Callable<String>() {
   @Override
   public String call() throws Exception {
    Thread.sleep(3 * 1000L);
    return "小单 - " + System.currentTimeMillis();
   }
  };
 }

}

Enfin, écrivez un test de page comet.jsp :

<%@ page pageEncoding="UTF-8"%>
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
<html>
 <head>
 <title>长连接测试</title>
 <script type="text/javascript" src="${pageContext.request.contextPath }/webjarslocator/jquery/jquery.js"></script>
 <script type="text/javascript">
  $(function(){
   function longPolling(){
    $.getJSON(&#39;${pageContext.request.contextPath }/xs/cometservlet&#39;, function(data){
     console.log(data.result);
     $(&#39;#n1&#39;).html(data.result);
     longPolling();
    });
   }
   longPolling();

   function longPolling2(){
    $.get(&#39;${pageContext.request.contextPath }/async/test&#39;, function(data){
     console.log(data);
     $(&#39;#n2&#39;).html(data);
     longPolling2();
    });
   }
   longPolling2();
  });
 </script>
 </head>

 <body>
 <h1>长连接测试</h1>
 <h2 id="n1"></h2>
 <h2 id="n2"></h2>
 </body>
</html>

[Recommandations associées]

1. Tutoriel vidéo Java gratuit

2 Tutoriel vidéo Java sur la mise en œuvre de miniatures à proportions égales pour les images

3. 🎜> Manuel du didacticiel FastJson

Ce qui précède est le contenu détaillé de. pour plus d'informations, suivez d'autres articles connexes sur le site Web de PHP en chinois!

Déclaration:
Le contenu de cet article est volontairement contribué par les internautes et les droits d'auteur appartiennent à l'auteur original. Ce site n'assume aucune responsabilité légale correspondante. Si vous trouvez un contenu suspecté de plagiat ou de contrefaçon, veuillez contacter admin@php.cn