学习在 @Async
和 @EnableAsync
注释的帮助下在 Spring 框架中创建异步方法,这些注释在 Java $$$ 之上使用线程池
框架。
Spring 带有 @EnableAsync
注释,可以应用于 @Configuration 类以实现异步行为。 @EnableAsync
注释将查找标有 @Async
注释的方法并在后台线程池中运行它们。
@Async
注释方法在单独的线程中执行并返回 CompletableFuture
以保存异步计算的结果。
要在 spring 中启用异步配置,请按照下列步骤操作:
@Configuration
@EnableAsync
public class AsynchConfiguration
{
@Bean(name = "asyncExecutor")
public Executor asyncExecutor()
{
ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor();
executor.setCorePoolSize(3);
executor.setMaxPoolSize(3);
executor.setQueueCapacity(100);
executor.setThreadNamePrefix("AsynchThread-");
executor.initialize();
return executor;
}
}
@Async("asyncExecutor")
public CompletableFuture<EmployeeNames> methodOne() throws InterruptedException {
//code
}
CompletableFuture.allOf(methodOne, methodTwo, methodThree).join();
在此演示中,我们将创建一个 REST API,它将异步地从三个远程服务获取数据,并在所有 3 个服务的响应都可用时聚合响应。
EmployeeName
APIEmployeeAddress
APIEmployeePhone
API以下是异步 REST 控制器在聚合数据并返回结果之前必须使用的远程 API,
@RestController public class EmployeeDataController { @RequestMapping(value = "/addresses", method = RequestMethod.GET) public EmployeeAddresses getAddresses() { //... } @RequestMapping(value = "/phones", method = RequestMethod.GET) public EmployeePhone getPhoneNumbers() { //... } @RequestMapping(value = "/names", method = RequestMethod.GET) public EmployeeNames getEmployeeName() { //... } }
这些服务方法将从远程 API 或数据库中提取数据,并且必须在单独的线程中并行运行以加快处理速度。
@Service public class AsyncService { private static Logger log = LoggerFactory.getLogger(AsyncService.class); @Autowired private RestTemplate restTemplate; @Bean public RestTemplate restTemplate() { return new RestTemplate(); } @Async public CompletableFuture<EmployeeNames> getEmployeeName() throws InterruptedException { log.info("getEmployeeName starts"); EmployeeNames employeeNameData = restTemplate.getForObject("http://localhost:8080/name", EmployeeNames.class); log.info("employeeNameData, {}", employeeNameData); Thread.sleep(1000L); //Intentional delay log.info("employeeNameData completed"); return CompletableFuture.completedFuture(employeeNameData); } @Async public CompletableFuture<EmployeeAddresses> getEmployeeAddress() throws InterruptedException { log.info("getEmployeeAddress starts"); EmployeeAddresses employeeAddressData = restTemplate.getForObject("http://localhost:8080/address", EmployeeAddresses.class); log.info("employeeAddressData, {}", employeeAddressData); Thread.sleep(1000L); //Intentional delay log.info("employeeAddressData completed"); return CompletableFuture.completedFuture(employeeAddressData); } @Async public CompletableFuture<EmployeePhone> getEmployeePhone() throws InterruptedException { log.info("getEmployeePhone starts"); EmployeePhone employeePhoneData = restTemplate.getForObject("http://localhost:8080/phone", EmployeePhone.class); log.info("employeePhoneData, {}", employeePhoneData); Thread.sleep(1000L); //Intentional delay log.info("employeePhoneData completed"); return CompletableFuture.completedFuture(employeePhoneData); } }
这是调用异步方法、使用和聚合它们的响应并返回给客户端的主要 API。
@RestController public class AsyncController { private static Logger log = LoggerFactory.getLogger(AsyncController.class); @Autowired private AsyncService service; @RequestMapping(value = "/testAsynch", method = RequestMethod.GET) public void testAsynch() throws InterruptedException, ExecutionException { log.info("testAsynch Start"); CompletableFuture<EmployeeAddresses> employeeAddress = service.getEmployeeAddress(); CompletableFuture<EmployeeNames> employeeName = service.getEmployeeName(); CompletableFuture<EmployeePhone> employeePhone = service.getEmployeePhone(); // Wait until they are all done CompletableFuture.allOf(employeeAddress, employeeName, employeePhone).join(); log.info("EmployeeAddress--> " + employeeAddress.get()); log.info("EmployeeName--> " + employeeName.get()); log.info("EmployeePhone--> " + employeePhone.get()); } }
当方法返回类型是 Future 时,Future.get() 方法将抛出异常,我们应该使用 try-catch 块来在聚合结果之前捕获并处理异常。
问题是如果异步方法不返回任何值,那么很难知道在方法执行时是否发生了异常。我们可以使用 AsyncUncaughtExceptionHandler 实现来捕获和处理此类异常。
@Configuration
@EnableAsync
public class AsyncConfig extends AsyncConfigurerSupport {
@Override
public AsyncUncaughtExceptionHandler getAsyncUncaughtExceptionHandler() {
return new AsyncExceptionHandler();
}
}
public class AsyncExceptionHandler implements AsyncUncaughtExceptionHandler {
private final Logger logger = LoggerFactory.getLogger(AsyncExceptionHandler.class);
@Override
public void handleUncaughtException(Throwable ex, Method method, Object... params) {
logger.error("Unexpected asynchronous exception at : "
+ method.getDeclaringClass().getName() + "." + method.getName(), ex);
}
}
下载并启动这两个应用程序。点击 API:http://localhost:8081/testAsynch
。观察控制台中的输出。
源代码下载链接1和链接2
将有关创建 spring boot 非阻塞 rest api 的问题告诉我。
快乐学习!!
地址:https://www.cundage.com/article/enableasync-async-controller.html