spring boot项目使用@Async注解的坑

yizhihongxing

关于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技术站

(0)
上一篇 2023年5月19日
下一篇 2023年5月19日

相关文章

  • mybatis简介与配置_动力节点Java学院整理

    下面我将介绍关于MyBatis的简介与配置,并附上两个示例供参考。 Mybatis简介 MyBatis是一个开源的Java持久化框架,它通过XML或注解实现了对SQL的映射,将程序中的Java对象自动映射到数据库中的对应表格。MyBatis可以很好地解决Java程序中数据的存取问题,同时它也提供了很好的扩展性。 MyBatis最初是iBATIS项目,2006…

    Java 2023年5月20日
    00
  • Java 使用IO流实现大文件的分割与合并实例详解

    Java 使用IO流实现大文件的分割与合并实例详解 前言 在现代应用程序中,经常需要处理非常大的文件。处理大文件的一种常见方法是将它们分成更小的文件,这有助于减少I/O操作的时间和资源消耗。在Java中,可以使用IO流来实现大文件的分割与合并。 分割文件 读取源文件 首先,我们需要通过使用Java IO API中的FileInputStream读取要分割的源…

    Java 2023年5月20日
    00
  • Java安全之Tomcat6 Filter内存马问题

    我们来讲一下Java安全之Tomcat6 Filter内存马问题的完整攻略。 什么是Tomcat6 Filter内存马问题 Tomcat6是一个流行的Web服务器,它使用过滤器(Filter)来处理HTTP请求。但是,Tomcat6过滤器存在一个安全漏洞,即攻击者可以创建恶意过滤器,将恶意代码注入内存并产生后门。这就是所谓的Tomcat6 Filter内存马…

    Java 2023年5月19日
    00
  • Spring Security实现两周内自动登录”记住我”功能

    以下是详细的Spring Security实现两周内自动登录的攻略。 1. 添加相关依赖 首先,在项目中添加Spring Security的依赖: <dependency> <groupId>org.springframework.security</groupId> <artifactId>spring-se…

    Java 2023年5月20日
    00
  • Spring Bean是如何初始化的详解

    当Spring应用启动时,Spring容器会初始化所有由用户定义的bean(也就是Spring应用上下文中的bean),并映射它们之间的依赖关系。那么Spring Bean是如何初始化的呢?下面详细介绍一下Spring Bean的初始化过程。 1. Spring Bean的加载 首先,Spring容器会扫描Bean配置文件,找到所有的Bean定义,并将其保存…

    Java 2023年5月27日
    00
  • Java之通过OutputStream写入文件与文件复制问题

    Java之通过OutputStream写入文件 1. 使用OutputStream写入文件 通过Java程序创建一个文件并往其中写入数据的方法之一就是使用java.io.OutputStream。下面是一个可以将一些文本写入到文件中的Java程序的示例代码: import java.io.File; import java.io.FileOutputStre…

    Java 2023年5月26日
    00
  • Spring security基于数据库中账户密码认证

    Spring Security是Spring框架中提供的一个安全权限框架。它将认证(Authentication)和授权(Authorization)抽象为一个独立的模块,可以快速地将安全性集成到应用程序中。Spring Security可以基于多种认证方式,包括基于数据库中账户密码的认证。 基于数据库中账户密码认证的Spring Security攻略如下:…

    Java 2023年5月20日
    00
  • sqlserver 文件数据库和关系数据库的比较

    SQL Server 文件数据库和关系数据库比较 概述 SQL Server 是一种关系型数据库管理系统(RDBMS),同时也支持文件数据库。在SQL Server中,关系数据库的存储是通过表的形式,将数据存储在多个表中,并通过各种关系将表连接在一起。而文件数据库则是通过文件系统在磁盘上存储数据。 区别 存储形式 关系数据库是将数据存储在一个或多个表中,通过…

    Java 2023年5月26日
    00
合作推广
合作推广
分享本页
返回顶部