봄 부팅 비동기 스레드


일반 배경 관리 시스템은 보고서 수출, 데이터, 많은 양의 보고서의 수출 기능이 일반적으로 더 많은 시간이 소요 관리자가 내보내기 버튼을 클릭 같은, 종종 우리는 성공적으로 다음 단계로 보고서를 내보낼 수있을 때까지 시간이 오래 기다릴 필요 분명 이러한 동기화 방식은 수요를 충족하기 위해 실패했습니다. 실제 개발은 현재 일반적으로 사용되는 방법은 수출의 시간이 소요되는 작업을 완료하기 위해 수출을 위해 다른 시스템에 메시지를 보내 JMS 메시지 큐 방식을 사용하거나 프로젝트에 비동기 스레드에서 설정하는 것입니다. 본 논문은 봄 부팅 중 일부는 비동기 스레드를 가능하게하는 방법을 설명하기 위해 수출 시나리오를보고합니다.

사용자 스레드 풀 가능하고 비동기 있도록
스프링 본에게 비동기 인터페이스 스레드 풀을 구성하는 데 사용되는 인터페이스 AsyncConfigurer 인터페이스,이 두 가지 방법, getAsyncExecutor 및 getAsyncUncaughtExceptionHandler를 가지며, 첫 번째 방법은 스레드 풀을 수득하고, 두번째 상기 방법은 이상 비동기 스레드에서 발생하는 처리에 사용된다. 다음과 같이 그것의 소스는 다음과 같습니다

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;
    }
}


내가 비동기 스레드 메커니즘을 열려는, 그래서 여기의 인터페이스를 달성 비어 제공, 우리는 수동으로이 인터페이스를 구현해야, Spring 설정 클래스로 표시된 인터페이스를 구현하는 클래스는, 다음, 봄 비동기를 사용할 수있는 오픈 스프링 스레드 getAsyncExecutor 의해 얻을 수는 물론, 비동기 개의 특수 결합 전체를 열 필요가 비동기 동작을 수행 할 하나 @EnableAsync는 다른 @Async이고, 제 1 구성 클래스에 표시된 그 봄이 비동기, 두 번째 의견은 일반적으로 하나의 방법으로 표시되어 있습니다 알려줍니다이 메소드를 호출 할 때, 당신은 그것을 실행하는 스레드 풀에서 새 스레드를 얻을 것이다.
이제 스레드 풀 및 비동기 공개는 다음과 같이 코드를 AsyncConfigurer를 달성하기 위해 프로파일 클래스 AsyncConfig를 작성하는 여기 수 있습니다 정의 할 수 있습니다 :

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());
        };
    }
}



첫 번째 방법은 우리가 스레드 풀을 정의하고 이러한 코어 스레드 수가 최대 스레드, 스레드 큐 스레드의 최대 수와 같은 기본적인 파라미터를 설정, 두 번째 방법은 비동기 예외 처리 스레드 인 상기 인터페이스는 함수 AsyncUncaughtExceptionHandler (추상적 만 하나의 인터페이스에있어서, 표시된 일반적으로 사용 @FunctionalInterface 주석 인터페이스) 때문에 람다 식은 본원 구현 클래스 약칭 듯이 예외 핸들러는, 달성 클래스 오브젝트 AsyncUncaughtExceptionHandler 인터페이스를 반환 객체는 비동기 예외 처리가 로그에 대해 여기에 기록되며, 람다 표현식에 익숙하지 않은, 당신은 직접 구현 클래스 개체 AsyncUncaughtExceptionHandler를 만들 익명의 내부 클래스를 사용할 수있는 경우로서 다음, 다른 논리 연산을하지 않았다 :

@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());
        }
    };
}


주의 할 점은 우리가 위의 구성 클래스에 @EnableAsync 노트를 추가 한 봄, 그것은 가능한 비동기 메커니즘을 열 봄 콩의 시간에 다음 구성 클래스를 등록 할 것입니다.

가능한 비동기 메커니즘 테스트
보고서가 보여 생성하는 서비스 계층 인터페이스를 쓰기를 :

package cn.itlemon.springboot.async.service;

import java.util.concurrent.Future;

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

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

}


그것의 구현 클래스는 다음과 같습니다

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() + "】");
    }
    
}


메서드를 호출 할 때이 작업은 간단한 시뮬레이션에 사용하는 인쇄 문을 보고서를 내보낼 수 있도록되어 있다고 가정하고, @Async 주석 방법을 표시되어, 다음, 봄은 그래서,이 방법을 실행하기 위해 새로운 스레드를 취득합니다 현재 메소드의 스레드 실행의 이름을 인쇄하려면 여기를. 다음과 같이 우리는 컨트롤러를 쓰기 :

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";
    }
    
}


새로운 스레드가 활성화되어 있는지 여부 generateReport 메소드를 호출 할 때 우리는 또한, 현재 컨트롤러 과정에서 현재의 thread를 인쇄 프로젝트를 실행, 지정된 URL에 접근, 당신은 비교할 수 있습니다. HTTP : 우리는 브라우저의 주소 표시 줄에, 봄 부팅 응용 프로그램을 시작 // localhost를 : 8080 / 비동기 / 페이지, 결과는 콘솔에 인쇄되어 있습니다 :

현재 요청 스레드 이름 : [HTTP-NIO-8080-exec- 1 ]
[위한 ThreadPoolTaskExecutor-1] : 보고서는 이름이 스레드

우리가 성공적으로 비동기 스레드를 열 것을 분명히,이 같은 스레드하지 않습니다.

비동기 예외 처리 스레드
일반적 스프링 두 가지 범주로 나누어 실 비동기 예외 처리는 하나의 값을 반환하지 않는 비동기 방식이고, 다른 하나는 비동기 방식은 값을 반환한다.

첫 번째 방법은 값을 반환하지 않는
코드 비동기 스레드 예외가 발생할 때 첫 번째 클래스, 우리는 즉 getAsyncUncaughtExceptionHandler 방법을 달성하기 위해, AsyncConfig 구성 클래스 구성에서왔다 없음 반환 값, 즉, 우리는이 메소드를 호출 예외 처리, 테스트, generateReport AsyncServiceImpl 우리의 방법은 수동으로 광고에서 System.out.println (1/0)을 첨가, 다음과 같이 제로 예외를 일으키는 코드이다 :

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



HTTP : 브라우저의 주소 표시 줄에 다시 봄 부팅 응용 프로그램을 시작할 때 // localhost를 : 그것은 예외가 다른 스레드에서 발생하기 때문에 그렇지 않은 있도록 8080 / 비동기 / 페이지, 다음을 제외하고는, 비동기 과정에서 발생 메인 쓰레드의 실행 후 이펙트 및 예외가 발생은 getAsyncUncaughtExceptionHandler 구성 방법은, 다음의 예외가 처리되며, 상기 프로세싱 모드는 로그 기록을 사용하는 것이다 :

2018년 10월 31일 10 : 57이다 ERROR 2391 --- 09.952 cispringboot.async.config.AsyncConfig [1 -lTaskExecutor.] 중에 오류가 비동기 방식에서 발생 / ZERO 의한
. 1 개
번째 클래스 메소드 리턴 값을 가지고
두 번째 경우를위한 비동기 방법은 값을 반환 것, 그 다음 우리가 어떻게 비동기 스레드 처리의 반환 값을받을 수 있나요, 일반적인 방법은 인터페이스의 미래를 사용하는 비동기 방식의 값을 반환하는 것입니다, ListenableFuture 또는 클래스 AsyncResult 포장, 곧 일반으로 값을 반환합니다 말했다 인터페이스 또는 클래스에 전달합니다. 여기에서 우리는 간단히들이 소스 코드에 사용되는 방법을 확인합니다.

미래 인터페이스 :

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;
}



분석 방법 :

이 임무가 실패 취소 false를 반환하는 경우 작업이 성공적으로 진정한 수익을 취소 할 경우, 작업을 취소하는 방법을 취소 할 수 있습니다. 매개 변수를 MayInterruptIfRunning하는 작업이 수행되고 있지만, true로 설정하면, 작업이 실행되는 과정에서 취소 할 수 있습니다 완료되지 않은 취소 할 수 있는지 여부를 나타냅니다. 작업이 완료 된 경우에 관계없이 mayInterruptIfRunning는 취소가 잘못된 작업의 반환을 완료 한 경우,이 방법은 확실히, 즉, false를 돌려 참 또는 거짓이며, 작업이 수행되는 경우, false로 mayInterruptIfRunning 세트 경우는 true, 반환에 mayInterruptIfRunning 설정하는 경우는 true 거짓이 리턴되며, 작업이 실행되지 않은 경우에 관계없이 mayInterruptIfRunning는 확실히 true를 반환 true 또는 false입니다.
의 isCancelled 방법은 성공이 작업이 정상적으로 완료되기 전에, 그것이 사실 반환 취소되는 경우 작업이 성공적으로 취소되었는지 여부를 나타냅니다.
의 isDone 방법은 작업이 완료되는 경우 작업이 true로 반환이 완료되었는지 여부를 나타내며
, 작업이 반환하기 전에 완료 될 때까지 GET 방법은 결과를 얻는 데 사용됩니다, 방해를 생성합니다이 방법은 대기
의 취득에 사용 GET (긴 시간 제한, TimeUnit와 단위) 그 결과, 지정된 시간 내에 그 결과, 직접적인는 null를 얻을하지 않을 경우.
ListenableFuture 인터페이스 :

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은 또한 예외를 처리 및 비동기 메서드의 반환 값을 가져 오는 데 사용할 수 있습니다 주로 비동기 콜백 사이트를 추가하는 데 사용되는 세 개의 추가 방법을 추가, 미래의 인터페이스를 상속. AsyncResult ListenableFuture의 클래스가 구현하는 인터페이스, 또한 모든 메소드를 구현합니다. 다음으로, 우리는 비동기 처리와 예외 처리의 반환 값을 캡처하는 방법을 소개합니다.

인터페이스의 미래 사용

다음과 같이 ReturnMessage ()와 미래 패키징에 대한 인터페이스를 사용하여 우리는 AsyncService 인터페이스 메소드를 추가 :

/ **
 * 방법 비동기 콜백 메시지
 *
 * @return 문자열
 * /
미래 <문자열> ReturnMessage ();

다음과 같이 구현 코드 클래스는 다음과 같습니다

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


다음과 같이 컨트롤러 레이어, 미래의 객체 클래스를 달성하기 위해 획득 될 수있다 :

@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";
}


여기 비동기하고 시도 ... 캐치 예외 처리도 비동기 메소드의 반환 값을 얻기 위해 get 메소드의 미래를 사용하지만,이 획득 모드는 반환 값은 get 메소드를 호출 한 후, 말을하는 것입니다 현재 스레드를 차단합니다 실행하기 전에 코드의 다음 라인에 대한 비동기 스레드 대기가 완료됩니다.

사용 ListenableFuture 인터페이스

다음과 같이 returnMsg () 및 ListenableFuture 포장에 대한 인터페이스를 사용하여 우리는 AsyncService 인터페이스 메소드를 추가 :

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


구현 클래스 코드는 다음과 같습니다 :

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


다음과 같이 컨트롤러 레이어는 상기 ListenableFuture 클래스 오브젝트를 얻었다 달성 될 수있다 :

@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";
}


이 위의 코드에서 알 수있는 바와 같이, 객체 클래스 및 FailureCallback 이상 발생 인터페이스 성공적인 콜백 클래스의 목적을 달성하기 콜백 인터페이스 SuccessCallback 실패 비동기 처리의 비동기 처리를 달성하기 위해, 각각 두 개의 콜백 리턴 결과를 추가한다. 완료되면 ListenableFuture 인터페이스, 지원이 효과적으로 스레드 차단 문제를 방지 콜백 미래 인터페이스의 확장, 즉, 그것은 미래 인터페이스의 구현을 모니터링합니다, 그것은 비정상의 경우에, 치료 성공으로 onSuccess 메소드를 호출 , onFailure 방법은 예외 처리라고한다. 비교, 더 비동기 처리의 리턴 값을 가지고 ListenableFuture을 권장합니다. Java1.8를 들어, 사실, 더 많거나 구아바 ListenableFuture의 CompletableFuture을 추천, 관심있는 학생들은 심도있는 연구를 수행 할 수 있습니다, 그들은 핸들 비동기 더 강력한 기능이 될 것입니다
 

게시 48 개 원래 기사 · 원 찬양 26 ·은 70000 +를 볼

추천

출처blog.csdn.net/qq_38316721/article/details/104883281