在Spring中存在一個AsyncConfigurer接口,它是一個可以配置異步線程池的接口,實現源碼如下:
package org.springframework.scheduling.annotation;
import java.util.concurrent.Executor;
import org.springframework.aop.interceptor.AsyncUncaughtExceptionHandler;
import org.springframework.lang.Nullable;
public interface AsyncConfigurer {
/**
* The {@link Executor} instance to be used when processing async
* method invocations.
*/
@Nullable
default Executor getAsyncExecutor() {
return null;
}
/**
* The {@link AsyncUncaughtExceptionHandler} instance to be used
* when an exception is thrown during an asynchronous method execution
* with {@code void} return type.
*/
@Nullable
default AsyncUncaughtExceptionHandler getAsyncUncaughtExceptionHandler() {
return null;
}
}
代碼比較簡單,其中getAsyncExecutor方法返回的是一個自定義線程池,這樣在開啓異步時,線程池就會提供空閒線程來執行異步任務。因爲線程中的業務邏輯可能拋出異常,所以還有一個處理異常的處理器方法。爲了使得異步可用,Spring還提供了註解@EnableAsync,如果Java配置文件標註它,那麼Spring就會開啓異步可用,這樣就可以使用註解@Async驅動Spring使用異步調用。下面我們看一下異步實例的實現代碼:
package com.martin.config.other.async;
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: martin
* @date: 2020/2/5
*/
@Configuration
@EnableAsync
public class AsyncConfig implements AsyncConfigurer {
//定義線程池
@Override
public Executor getAsyncExecutor() {
ThreadPoolTaskExecutor poolExecutor = new ThreadPoolTaskExecutor();
//核心線程數
poolExecutor.setCorePoolSize(10);
//線程池最大線程數
poolExecutor.setMaxPoolSize(30);
//線程隊列最大線程數
poolExecutor.setQueueCapacity(2000);
//初始化
poolExecutor.initialize();
return poolExecutor;
}
}
代碼中註解@EnableAsync表示開啓Spring異步,並通過覆蓋getAsyncExecutor方法,自定義一個線程池。這樣就可以在業務代碼中通過@Async註解使用該線程池執行異步操作。下面定義一個異步服務接口:
package com.martin.config.other.async;
/**
* @author: martin
* @date: 2020/2/5
*/
public interface AsyncService {
void generateReport();
}
package com.martin.config.other.async;
import lombok.extern.slf4j.Slf4j;
import org.springframework.scheduling.annotation.Async;
import org.springframework.stereotype.Service;
/**
* @author: martin
* @date: 2020/2/5
*/
@Service
@Slf4j
public class AsyncServiceImpl implements AsyncService {
@Override
@Async //聲明使用異步調用
public void generateReport() {
log.error("報表生成線程名稱:{}", Thread.currentThread().getName());
}
}
這個方法比較簡單,打印出了當前運行線程的名稱,以便後續驗證。需要注意的是這裏使用了@Async註解,這樣改方法在被調用的時候,它就會使用線程池的線程去執行它。啓動服務後,日誌打印如下:
報表生成線程名稱:ThreadPoolTaskExecutor-3
報表生成線程名稱:ThreadPoolTaskExecutor-4