在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