fil asynchrone Boot Spring


système de gestion de base générale a des capacités d'exportation du rapport, pour l'exportation du rapport de grandes quantités de données, généralement plus de temps, comme l'administrateur clique sur un bouton pour l'exportation, doivent souvent attendre longtemps jusqu'à ce que nous pouvons avec succès exporter le rapport à l'étape suivante de toute évidence d'une manière synchronisée telle n'a pas répondu à la demande. Le développement réel est maintenant couramment utilisé est d'utiliser des moyens de file d'attente de messages JMS pour envoyer des messages à d'autres systèmes destinés à l'exportation, ou activer le fil asynchrone dans le projet pour terminer le travail de temps l'exportation. Ce document fera rapport des scénarios d'exportation d'expliquer comment une partie de l'amorçage Spring permet fil asynchrone.

pool de threads de mesure disponible et permet asynchrone
présente Spring une interface AsyncConfigurer d'interface qui est utilisée pour configurer le pool de threads d'interface asynchrone, il dispose de deux méthodes, getAsyncExecutor et getAsyncUncaughtExceptionHandler, le premier procédé est d'obtenir un pool de threads, la seconde le procédé est utilisé pour traiter une anomalie se produit dans le fil asynchrone. Sa source est la suivante:

package org.springframework.scheduling.annotation;

import java.util.concurrent.Executor;
import org.springframework.aop.interceptor.AsyncUncaughtExceptionHandler;
import org.springframework.lang.Nullable;

public interface AsyncConfigurer {

    // 获取线程池
    @Nullable
    default Executor getAsyncExecutor() {
        return null;
    }

    // 异步异常处理器
    @Nullable
    default AsyncUncaughtExceptionHandler getAsyncUncaughtExceptionHandler() {
        return null;
    }
}


L'interface offre ici sont vides à atteindre, donc je veux ouvrir le mécanisme de fil asynchrone, nous devons mettre en œuvre manuellement cette interface, la classe mettra en œuvre l'interface étiquetée classe de configuration Spring, puis a ouvert le asynchrone Spring est disponible, le printemps sera obtenu par un fil getAsyncExecutor être utilisé pour effectuer une opération asynchrone, bien sûr, aussi besoin d'ouvrir l'ensemble de la liaison deux annotations asynchrones, un @EnableAsync, l'autre est @Async, est marqué dans une première classe de configuration en ce printemps dit est disponible en mode asynchrone, le deuxième commentaire est généralement marqué dans une méthode, lors de l' appel de cette méthode, vous obtiendrez un nouveau fil de la piscine de fil pour l' exécuter.
Maintenant , nous allons définir le pool de threads et ouvert asynchrone est disponible, ici pour écrire une classe de profil AsyncConfig pour atteindre AsyncConfigurer, le code comme suit:

package cn.itlemon.springboot.async.config;

import lombok.extern.slf4j.Slf4j;
import org.springframework.aop.interceptor.AsyncUncaughtExceptionHandler;
import org.springframework.context.annotation.Configuration;
import org.springframework.scheduling.annotation.AsyncConfigurer;
import org.springframework.scheduling.annotation.EnableAsync;
import org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor;

import java.util.concurrent.Executor;

/**
 * @author jiangpingping
 * @date 2018/10/30 19:28
 */
@Configuration
@EnableAsync
@Slf4j
public class AsyncConfig implements AsyncConfigurer {

    @Override
    public Executor getAsyncExecutor() {
        // 自定义线程池
        ThreadPoolTaskExecutor taskExecutor = new ThreadPoolTaskExecutor();
        // 核心线程数
        taskExecutor.setCorePoolSize(10);
        // 最大线程数
        taskExecutor.setMaxPoolSize(30);
        // 线程队列最大线程数
        taskExecutor.setQueueCapacity(2000);
        // 初始化线程池
        taskExecutor.initialize();
        return taskExecutor;
    }

    @Override
    public AsyncUncaughtExceptionHandler getAsyncUncaughtExceptionHandler() {
        return (ex, method, params) -> {
            log.error("Error Occurs in async method:{}", ex.getMessage());
        };
    }
}



La première méthode, nous définissons un pool de threads et régler certains paramètres de base, tels que le nombre de base de fils, le nombre maximum d'unités d'exécution, la file d'attente du fil et le nombre maximal de fils, le second procédé est thread asynchrone de manipulation d'exception, qui est un gestionnaire d'exceptions, renvoie l'interface objet de la classe AsyncUncaughtExceptionHandler à réaliser, étant donné que l'interface est une AsyncUncaughtExceptionHandler de fonction (résumé seulement une méthode d'interface, l'interface notée d'annotation @FunctionalInterface généralement utilisé), de sorte que les expressions lambda est utilisé ici en abrégé sa classe de mise en oeuvre objets, la gestion des exceptions asynchrones sont enregistrées ici sur le journal, et ne l'ont pas d'autre opération logique, sinon familiarisé avec les expressions lambda, vous pouvez utiliser directement une classe interne anonyme pour créer un objet classe d'implémentation AsyncUncaughtExceptionHandler, comme suit:

@Override
public AsyncUncaughtExceptionHandler getAsyncUncaughtExceptionHandler() {

    return new AsyncUncaughtExceptionHandler() {
        @Override
        public void handleUncaughtException(Throwable ex, Method method, Object... params) {
            log.error("Error Occurs in async method:{}", ex.getMessage());
        }
    };
}


Une chose à noter est que nous avons ajouté des notes @EnableAsync dans la classe de configuration ci-dessus, puis enregistrez les classes de configuration au printemps est le temps du printemps Bean, il ouvrira des mécanismes asynchrones disponibles.

Test de mécanisme asynchrone disponible
pour écrire une interface de couche de service pour générer des rapports montrent:

package cn.itlemon.springboot.async.service;

import java.util.concurrent.Future;

/**
 * @author jiangpingping
 * @date 2018/10/30 19:32
 */
public interface AsyncService {

    /**
     * 模拟生成报表的异步方法
     */
    void generateReport();

}


Sa classe d'implémentation est:

package cn.itlemon.springboot.async.service.impl;

import cn.itlemon.springboot.async.service.AsyncService;
import org.springframework.scheduling.annotation.Async;
import org.springframework.scheduling.annotation.AsyncResult;
import org.springframework.stereotype.Service;

import java.util.concurrent.Future;

/**
 * @author jiangpingping
 * @date 2018/10/30 19:33
 */
@Service
public class AsyncServiceImpl implements AsyncService {

    @Override
    @Async
    public void generateReport() {
        // 模拟异步生成报表代码,这里设置为打印
        System.out.println("报表线程名称:【" + Thread.currentThread().getName() + "】");
    }
    
}


On suppose que le travail exporte un rapport, de sorte que les instructions d'impression d'utilisation à une simulation simple, et marqué méthode d'annotation @Async, puis lors de l'appel de la méthode, Spring va acquérir un nouveau thread pour exécuter cette méthode, ici pour imprimer le nom de l'exécution du fil de la méthode actuelle. Nous écrivons un contrôleur, comme suit:

package cn.itlemon.springboot.async.controller;

import cn.itlemon.springboot.async.service.AsyncService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

import java.util.concurrent.ExecutionException;
import java.util.concurrent.Future;

/**
 * @author jiangpingping
 * @date 2018/10/30 19:36
 */
@RestController
@RequestMapping("/async")
@Slf4j
public class AsyncController {

    private final AsyncService asyncService;

    @Autowired
    public AsyncController(AsyncService asyncService) {
        this.asyncService = asyncService;
    }

    @GetMapping("/page")
    public String asyncPage() {
        System.out.println("当前请求线程名称为:【" + Thread.currentThread().getName() + "】");
        // 异步调用
        asyncService.generateReport();
        // 返回结果
        return "async";
    }
    
}


Nous imprimons aussi le thread en cours dans le processus actuel du contrôleur, exécutez le projet, l'accès à l'URL spécifiée, vous pouvez comparer lorsque vous appelez la méthode generateReport si le nouveau thread est activé. Nous commençons l'application Spring Boot, dans l'adresse navigateur: http: // localhost: 8080 / async / page, le résultat est imprimé dans la console:

Le nom de thread de requête en cours: [http-nio-8080-Exec- 1 ]
Rapports Enfiler Nom: [ThreadPoolTaskExecutor-1] De

toute évidence, ce n'est pas le même fil, que nous ouvrons avec succès fil asynchrone.

La gestion des exceptions fil asynchrone
généralement traitée dans une exception de fil asynchrone Spring divisée en deux catégories, l' une est une méthode asynchrone ne retourne pas de valeur, et l'autre est une méthode asynchrone retourne une valeur.

La première méthode ne retourne pas de valeur
pour la première classe pas de valeur de retour, nous avons été dans la configuration de la classe de configuration AsyncConfig, à savoir parvenir à la méthode getAsyncUncaughtExceptionHandler, qui est, lorsque le code asynchrone exception de thread se produit, nous appellerons cette méthode pour la gestion des exceptions, pour les essais, notre méthode de generateReport AsyncServiceImpl ajouter manuellement une ligne System.out.println (1/0), l' amenant à l'exception de zéro, le code est le suivant:

@Override
@Async
public void generateReport() {
    // 模拟异步生成报表代码,这里设置为打印
    System.out.println("报表线程名称:【" + Thread.currentThread().getName() + "】");
    System.out.println(1 / 0);
}



Lors du démarrage de l'application Spring Boot nouveau dans l'adresse navigateur: http: // localhost: 8080 / async / page, puis l'exception se produit dans un processus asynchrone, car il est une exception se produit dans différents threads, donc il n'a pas effets après l'exécution du fil conducteur, et l'exception se produit, sera traité, le mode de traitement est d'utiliser la méthode log enregistré getAsyncUncaughtExceptionHandler configuré, à l'exception:

10 2018-10-31: 57 est: ERROR 2391 --- 09,952 cispringboot.async.config.AsyncConfig [-lTaskExecutor 1.]: Erreur du produit dans la async Méthode: / par ZERO
. 1
la seconde classe a une valeur de retour de la méthode
pour le second cas , que la méthode asynchrone renvoie une valeur, alors comment pouvons-nous arriver à la valeur de retour du traitement de fil asynchrone, la méthode habituelle est de retour valeur de la méthode asynchrone en utilisant l'avenir de l' interface, ListenableFuture ou emballage classe AsyncResult, sera bientôt de retour valeur en tant que générique passant à ladite interface ou classe. nous examinons brièvement les méthodes utilisées dans le code source.

interfaces futures:

public interface Future<V> {

    boolean cancel(boolean mayInterruptIfRunning);
    
    boolean isCancelled();
    
    boolean isDone();
    
    V get() throws InterruptedException, ExecutionException;
    
    V get(long timeout, TimeUnit unit) throws InterruptedException, ExecutionException, TimeoutException;
}



La méthode d'analyse:

annuler méthode pour annuler la tâche, si la tâche avec succès annuler renvoie true si elle retourne false pour annuler la mission échoue. paramètre MayInterruptIfRunning indique si pour permettre d' annuler la tâche en cours d' exécution , mais n'a pas été achevée, si elle est définie vrai, la tâche peut être annulée dans le processus de mise en œuvre. Si la tâche est terminée, quel que soit mayInterruptIfRunning est vrai ou faux, cette méthode renvoie certainement faux, qui est, si l'annulation est terminée retourne tâche fausse, si la tâche exécutée, si mayInterruptIfRunning la valeur true, renvoie true si mayInterruptIfRunning la valeur false , faux est retourné, si la tâche n'a pas été exécutée, quelle que soit mayInterruptIfRunning est vrai ou faux, revenir certainement vrai.
méthode isCancelled indique si la tâche a été annulée avec succès, si le succès est annulé avant que la tâche est terminée normalement, il retourne vrai.
méthode isDone indique si la tâche est terminée, si la tâche est terminée, le retour à la vraie, la
méthode GET est utilisée pour obtenir les résultats, cette méthode produira une obstruction, attendra jusqu'à ce que la tâche soit terminée avant le retour,
GET (délai d' attente longue, Unité TimeUnit) utilisé pour obtenir les résultats, si dans le délai imparti, ne pas obtenir un résultat, le null retour direct.
ListenableFuture Interface:

public interface ListenableFuture<T> extends Future<T> {

    void addCallback(ListenableFutureCallback<? super T> callback);

    void addCallback(SuccessCallback<? super T> successCallback, FailureCallback failureCallback);

    default CompletableFuture<T> completable() {
        CompletableFuture<T> completable = new DelegatingCompletableFuture<>(this);
        addCallback(completable::complete, completable::completeExceptionally);
        return completable;
    }
}


ListenableFuture a hérité des interfaces futures, il ajoute également le site trois méthodes supplémentaires, principalement utilisés pour ajouter callbacks asynchrone peut être utilisé pour gérer les exceptions et obtenir la valeur de retour de la méthode asynchrone. classe AsyncResult ListenableFuture implémente une interface, il met également en œuvre toutes les méthodes. Ensuite, nous présenterons comment capturer la valeur de retour de traitement et la gestion des exceptions asynchrones.

utilisation future de l'interface

Nous ajoutons une méthode d'interface AsyncService: ReturnMessage (), et utilise l'interface pour l'emballage futur, comme suit:

/ **
 * Méthode message de rappel asynchrone
 *
 * @return string
 * /
Future <String> ReturnMessage ();

classe de code de mise en œuvre est la suivante:

@Override
@Async
public Future<String> returnMessage() {
    System.out.println(Thread.currentThread().getName());
    String message = "Async Method Result";
    return new AsyncResult<>(message);
}


Ensuite, la couche contrôleur, peut être acquise pour atteindre la classe d'objet de l'avenir, comme suit:

@GetMapping("/page1")
public String asyncPage1() {
    try {
        System.out.println(Thread.currentThread().getName());
        Future<String> result = asyncService.returnMessage();
        System.out.println(result.get());
    } catch (ExecutionException | InterruptedException e) {
        log.error("发生了异常:{}", e.getMessage());
    }
    return "async";
}


été essayer ici asynchrone ... catch gestion des exceptions, également utilisé l'avenir de la méthode get pour obtenir la valeur de retour de la méthode asynchrone, mais ce mode d'acquisition de la valeur de retour bloque le thread courant, c'est-à-dire, après avoir appelé la méthode get, thread attend asynchrone pour la ligne de code suivante avant l'exécution est terminée.

Utilisation ListenableFuture Interface

Nous ajoutons une méthode d'interface AsyncService: returnMsg (), et utilise l'interface à l'emballage ListenableFuture, comme suit:

/**
 * 异步回调消息方法
 *
 * @return 字符串
 */
ListenableFuture<String> returnMsg();


Code de la classe de mise en œuvre suit comme:

@Override
@Async
public ListenableFuture<String> returnMsg() {
    System.out.println(Thread.currentThread().getName());
    String message = "Async Method Result";
    return new AsyncResult<>(message);
}


Ensuite, la couche contrôleur, peut être réalisée pour obtenir l'objet de classe ListenableFuture, comme suit:

@GetMapping("/page2")
public String asyncPage2() {
    System.out.println(Thread.currentThread().getName());
    ListenableFuture<String> result = asyncService.returnMsg();
    result.addCallback(new SuccessCallback<String>() {
        @Override
        public void onSuccess(String result) {
            System.out.println("返回的结果是:" + result);
        }
    }, new FailureCallback() {
        @Override
        public void onFailure(Throwable ex) {
            log.error("发生了异常:{}", ex.getMessage());
        }
    });
    return "async";
}


Comme on peut le voir à partir du code ci-dessus, ajoutez les deux résultats renvoyés de rappel, respectivement, pour atteindre la classe d'objet et le traitement asynchrone de traitement asynchrone de l'échec des interfaces de rappel pour atteindre avec succès objet de classe de rappel Interface anomalie FailureCallback se produit. ListenableFuture Interface est une extension de l'interface future, supports de rappel, effectivement éviter problème de blocage de fil, qui est, il surveillera la mise en œuvre de l'interface future, une fois terminé, il appellera la méthode onSuccess de la réussite du traitement, en cas d'anomalie , méthode onFailure est appelée la gestion des exceptions. En comparaison, plus recommandé ListenableFuture d'avoir une valeur de retour de traitement asynchrone. Pour Java1.8, en fait, plus ou goyave recommandé CompletableFuture de ListenableFuture, les étudiants intéressés peuvent effectuer des recherches approfondies, ils seront plus de capacité puissant pour gérer asynchrone
 

Publié 48 articles originaux · louange gagné 26 · vues 70000 +

Je suppose que tu aimes

Origine blog.csdn.net/qq_38316721/article/details/104883281
conseillé
Classement