Spring 的异步任务执行机制
1. 基本概念
Spring 的异步任务执行机制允许应用程序中的方法在单独的线程中执行,而不是在调用线程中同步执行。这样可以提高应用程序的响应性能,特别是在处理一些耗时的操作时,如网络请求、文件读写等。
2. 启用异步支持
要在 Spring 项目中使用异步任务执行机制,需要在配置类上添加 @EnableAsync
注解。如果是 Spring Boot 项目,可以在主应用类上添加该注解。
import org.springframework.context.annotation.Configuration;
import org.springframework.scheduling.annotation.EnableAsync;
@Configuration
@EnableAsync
public class AsyncConfig {
// 可以在这里进行更多的异步配置
}
3. 定义异步方法
在需要异步执行的方法上添加 @Async
注解。通常,这些方法应该返回 void
或者 CompletableFuture
。
import org.springframework.scheduling.annotation.Async;
import org.springframework.stereotype.Service;
import java.util.concurrent.CompletableFuture;
@Service
public class AsyncService {
@Async
public void asyncMethodWithVoidReturnType() {
System.out.println("异步方法执行,当前线程: " + Thread.currentThread().getName());
}
@Async
public CompletableFuture<String> asyncMethodWithReturnType() {
System.out.println("异步方法执行,当前线程: " + Thread.currentThread().getName());
try {
Thread.sleep(5000); // 模拟耗时操作
} catch (InterruptedException e) {
e.printStackTrace();
}
return CompletableFuture.completedFuture("异步方法执行完成");
}
}
4. 调用异步方法
在需要调用异步方法的地方,直接调用即可。Spring 会自动将方法的执行放到异步线程中。
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.CommandLineRunner;
import org.springframework.stereotype.Component;
import java.util.concurrent.ExecutionException;
@Component
public class AsyncTaskRunner implements CommandLineRunner {
@Autowired
private AsyncService asyncService;
@Override
public void run(String... args) throws Exception {
// 调用无返回值的异步方法
asyncService.asyncMethodWithVoidReturnType();
// 调用有返回值的异步方法
CompletableFuture<String> future = asyncService.asyncMethodWithReturnType();
try {
String result = future.get();
System.out.println("异步方法返回结果: " + result);
} catch (InterruptedException | ExecutionException e) {
e.printStackTrace();
}
}
}
处理异步任务的异常
1. 对于返回 void
的异步方法
对于返回 void
的异步方法,Spring 提供了 AsyncUncaughtExceptionHandler
接口来处理异常。需要创建一个实现该接口的类,并在配置类中进行配置。
import org.springframework.aop.interceptor.AsyncUncaughtExceptionHandler;
import org.springframework.stereotype.Component;
import java.lang.reflect.Method;
@Component
public class CustomAsyncExceptionHandler implements AsyncUncaughtExceptionHandler {
@Override
public void handleUncaughtException(Throwable throwable, Method method, Object... objects) {
System.out.println("异步方法 " + method.getName() + " 抛出异常: " + throwable.getMessage());
// 可以在这里进行更多的异常处理逻辑,如记录日志等
}
}
在配置类中配置异常处理器:
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.scheduling.annotation.AsyncConfigurer;
import org.springframework.scheduling.annotation.EnableAsync;
import java.util.concurrent.Executor;
import java.util.concurrent.Executors;
@Configuration
@EnableAsync
public class AsyncConfig implements AsyncConfigurer {
@Override
public Executor getAsyncExecutor() {
return Executors.newFixedThreadPool(10);
}
@Bean
public CustomAsyncExceptionHandler asyncExceptionHandler() {
return new CustomAsyncExceptionHandler();
}
@Override
public AsyncUncaughtExceptionHandler getAsyncUncaughtExceptionHandler() {
return asyncExceptionHandler();
}
}
2. 对于返回 CompletableFuture
的异步方法
对于返回 CompletableFuture
的异步方法,可以使用 CompletableFuture
的 exceptionally
方法来处理异常。
import org.springframework.scheduling.annotation.Async;
import org.springframework.stereotype.Service;
import java.util.concurrent.CompletableFuture;
@Service
public class AsyncService {
@Async
public CompletableFuture<String> asyncMethodWithReturnType() {
return CompletableFuture.supplyAsync(() -> {
System.out.println("异步方法执行,当前线程: " + Thread.currentThread().getName());
try {
// 模拟异常
throw new RuntimeException("异步方法抛出异常");
} catch (Exception e) {
// 抛出异常
throw new RuntimeException(e);
}
}).exceptionally(ex -> {
System.out.println("异步方法处理异常: " + ex.getMessage());
return "处理异常后的结果";
});
}
}
下面是完整的代码示例,以 doubaocanvas
的形式展示:
AsyncConfig.java
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.scheduling.annotation.AsyncConfigurer;
import org.springframework.scheduling.annotation.EnableAsync;
import java.util.concurrent.Executor;
import java.util.concurrent.Executors;
@Configuration
@EnableAsync
public class AsyncConfig implements AsyncConfigurer {
@Override
public Executor getAsyncExecutor() {
return Executors.newFixedThreadPool(10);
}
@Bean
public CustomAsyncExceptionHandler asyncExceptionHandler() {
return new CustomAsyncExceptionHandler();
}
@Override
public AsyncUncaughtExceptionHandler getAsyncUncaughtExceptionHandler() {
return asyncExceptionHandler();
}
}
AsyncService.java
import org.springframework.scheduling.annotation.Async;
import org.springframework.stereotype.Service;
import java.util.concurrent.CompletableFuture;
@Service
public class AsyncService {
@Async
public void asyncMethodWithVoidReturnType() {
System.out.println("异步方法执行,当前线程: " + Thread.currentThread().getName());
}
@Async
public CompletableFuture<String> asyncMethodWithReturnType() {
return CompletableFuture.supplyAsync(() -> {
System.out.println("异步方法执行,当前线程: " + Thread.currentThread().getName());
try {
// 模拟异常
throw new RuntimeException("异步方法抛出异常");
} catch (Exception e) {
// 抛出异常
throw new RuntimeException(e);
}
}).exceptionally(ex -> {
System.out.println("异步方法处理异常: " + ex.getMessage());
return "处理异常后的结果";
});
}
}
AsyncTaskRunner.java
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.CommandLineRunner;
import org.springframework.stereotype.Component;
import java.util.concurrent.ExecutionException;
@Component
public class AsyncTaskRunner implements CommandLineRunner {
@Autowired
private AsyncService asyncService;
@Override
public void run(String... args) throws Exception {
// 调用无返回值的异步方法
asyncService.asyncMethodWithVoidReturnType();
// 调用有返回值的异步方法
CompletableFuture<String> future = asyncService.asyncMethodWithReturnType();
try {
String result = future.get();
System.out.println("异步方法返回结果: " + result);
} catch (InterruptedException | ExecutionException e) {
e.printStackTrace();
}
}
}
CustomAsyncExceptionHandler.java
import org.springframework.aop.interceptor.AsyncUncaughtExceptionHandler;
import org.springframework.stereotype.Component;
import java.lang.reflect.Method;
@Component
public class CustomAsyncExceptionHandler implements AsyncUncaughtExceptionHandler {
@Override
public void handleUncaughtException(Throwable throwable, Method method, Object... objects) {
System.out.println("异步方法 " + method.getName() + " 抛出异常: " + throwable.getMessage());
// 可以在这里进行更多的异常处理逻辑,如记录日志等
}
}
通过以上步骤,你可以在 Spring 项目中使用异步任务执行机制,并有效地处理异步任务中可能出现的异常。