关于spring boot项目使用@Async注解的坑,有以下几个注意点:
一、@EnableAsync开启异步支持
首先需要在启动类上加上@EnableAsync注解,开启异步支持。示例代码如下:
@SpringBootApplication
@EnableAsync
public class DemoApplication {
public static void main(String[] args) {
SpringApplication.run(DemoApplication.class);
}
}
二、@Async使用时需要注意的问题
使用@Async注解时需要注意以下几个问题:
1. 修饰方法必须是public
被@Async注解修饰的方法必须是public,否则会抛出异常。示例代码如下:
@Service
public class AsyncService {
@Async
private void asyncMethod() {
// ...
}
}
会抛出以下异常:
org.springframework.aop.framework.AopInvocationException:
Null return value from advice does not match primitive return type for:
public void com.example.demo.service.AsyncService.asyncMethod()
with params [] of [null]
将private改成public即可:
@Service
public class AsyncService {
@Async
public void asyncMethod() {
// ...
}
}
2. 异步方法不能和同步方法混淆
如果在同一个类中同时存在同步和异步方法,那么异步方法必须标注@Async,否则会导致同步方法变为异步方法。示例代码如下:
@Service
public class AsyncService {
public void syncMethod() {
// ...
}
@Async
public void asyncMethod() {
// ...
}
}
此时,如果调用syncMethod方法,就会变成异步方法,因为同一个类中已经存在异步方法了。要解决这个问题,只需将syncMethod标注为@Async(false)即可。示例代码如下:
@Service
public class AsyncService {
public void syncMethod() {
// ...
}
@Async
public void asyncMethod() {
// ...
}
}
三、示例代码
1. 注入方式问题
@Service
public class AsyncService {
public void syncMethod() {
// ...
}
@Async
public void asyncMethod() {
// ...
}
}
@Component
public class MyClass {
@Autowired
private AsyncService asyncService;
public void test() {
asyncService.asyncMethod();
}
}
这种写法有问题,因为异步方法是在另一个线程中执行的,而MyClass中的asyncService实例是被主线程创建的,如果直接在主线程中调用异步方法的话,就会引发异步任务被同步执行的问题。
正解是使用@Async注解来修饰类中的方法,因为使用@Async注解修饰的方法会被Spring AOP机制切入,并将其转化为异步执行。示例代码如下:
@Service
public class AsyncService {
public void syncMethod() {
// ...
}
@Async
public void asyncMethod() {
// ...
}
}
@Component
public class MyClass {
@Autowired
private AsyncService asyncService;
public void test() {
asyncService.asyncMethod();
}
}
这样就可以避免异步任务被同步执行的问题了。
2. 异步方法调用自身问题
异步方法调用自身是一个比较常见的问题,比如下面这样的代码会导致异步任务失效:
@Service
public class AsyncService {
@Async
public void test() {
test();
}
}
如果要在异步方法中实现循环调用,就需要使用另外一种异步调用的方式,即通过@Async和Future
@Service
public class AsyncService {
@Async
public Future<Void> test() {
// do something
return CompletableFuture.completedFuture(null);
}
public void init() {
test().get(); // 阻塞,等待异步任务执行完成
}
}
这样异步方法就可以实现自己的循环调用了。
最后总结一下,异步方法虽然在开发中能够提高效率,但需要注意一些细节问题。开发者需要充分理解异步方法的执行机制,并注意调用方式。如果掌握得当,就能够真正发挥异步方法的威力。
本站文章如无特殊说明,均为本站原创,如若转载,请注明出处:spring boot项目使用@Async注解的坑 - Python技术站