Spring中@Async用法详解及简单实例

当我们需要在Spring应用中增加异步任务支持时,可以使用@Async注解来标示异步方法。@Async注解可以标识在任何方法上面,表示该方法会异步执行。本篇攻略将从以下几个方面介绍Spring中@Async的用法,包括:

  1. 开启异步支持
  2. 使用@Async注解实现异步方法
  3. 使用Future返回异步结果
  4. 示例1:异步方法的实现
  5. 示例2:带参数的异步方法

开启异步支持

首先,我们需要在Spring应用中开启异步支持。在XML配置中,可以通过在中添加元素来开启异步支持。

<task:annotation-driven>
    <task:executor id="myThreadPoolExecutor" pool-size="5"/>
    <task:executor id="secondThreadPoolExecutor" pool-size="10"/>
    <task:executor id="customAsyncExecutor" pool-size="20"/>
    <task:async-method-executor task-executor="customAsyncExecutor"/>
    <async/>
</task:annotation-driven>

Java Config中,可以通过使用@EnableAsync注解开启异步支持。

@Configuration
@EnableAsync
public class AppConfig {
    //其他配置
}

使用@Async注解实现异步方法

有了异步支持后,我们就可以在方法上添加@Async注解来实现异步方法。@Async注解发挥作用的前提是方法必须是public类型方法。

@Service
public class UserService{

    @Async
    public void longTimeOper(){
        //xxxxxx
    }
    //其他代码
}

使用Future返回异步结果

如果需要获取异步方法的返回结果,可以在方法的返回类型上使用Java的Future类型。

@Service
public class UserService{

    @Async
    public Future<String> longTimeOperWithResult(){
        //xxxxxx
        return new AsyncResult<String>("result");
    }
    //其他代码
}

示例1:异步方法的实现

假设我们需要批量处理用户信息,并返回处理成功的用户数。首先,我们定义一个UserService:

@Service
public class UserService {

    private static final Logger log = LoggerFactory.getLogger(UserService.class);

    private static final Random random= new Random();

    public int batchSaveUserList(List<User> users) throws InterruptedException {
        for (User user : users) {
            saveUser(user);
        }
        Thread.sleep(5000);//模拟保存数据需要5秒
        return users.size();
    }

    @Async
    public Future<Integer> batchSaveUserListAsync(List<User> users) throws InterruptedException {
        return new AsyncResult<>(batchSaveUserList(users));
    }

    public void saveUser(User user) throws InterruptedException {
        log.info("save user: {}", user);
        Thread.sleep(random.nextInt(1000));
    }
}

UserService中包含了两个方法batchSaveUserList和batchSaveUserListAsync,前者是同步方法,后者是异步方法。batchSaveUserList方法模拟需要花费5秒的数据保存操作,而saveUser方法模拟插入单个用户时的操作。

接下来,我们编写测试代码:

@RunWith(SpringRunner.class)
@SpringBootTest(classes = Application.class)
public class UserServiceTest {

    private static final Logger log = LoggerFactory.getLogger(UserServiceTest.class);

    @Autowired
    private UserService userService;

    @Test
    public void batchSaveUserTest() throws InterruptedException {
        List<User> users = new ArrayList<>(10);
        for (int i = 0; i < 10; i++) {
            User user = new User();
            user.setName("name_" + i);
            user.setAge(20 + i);
            users.add(user);
        }
        int size = userService.batchSaveUserList(users);
        log.info("batchSaveUserList saved: {} records", size);
    }

    @Test
    public void batchSaveUserAsyncTest() throws InterruptedException, ExecutionException {
        List<User> users = new ArrayList<>(10);
        for (int i = 0; i < 10; i++) {
            User user = new User();
            user.setName("name_" + i);
            user.setAge(20 + i);
            users.add(user);
        }
        Future<Integer> future = userService.batchSaveUserListAsync(users);
        int size = future.get();
        log.info("batchSaveUserAsync saved: {} records", size);
    }
}

在测试代码中,我们分别调用了同步方法batchSaveUserList和异步方法batchSaveUserListAsync。执行结果表明异步方法可以提前返回,不必等到数据保存完成。

示例2:带参数的异步方法

为了更好地说明带参数的异步方法,我们假设初始化一个User对象需要5秒。此时,我们就可以使用异步方法initUser来异步初始化一个User对象:

@Service
public class UserService {

    private static final Logger log = LoggerFactory.getLogger(UserService.class);

    private static final Random random= new Random();

    public User initUser() throws InterruptedException {
        Thread.sleep(5000);//模拟初始化User需要5秒
        User user = new User();
        user.setName("user");
        user.setAge(18);
        return user;
    }

    @Async
    public Future<User> initUserAsync() throws InterruptedException {
        User user = initUser();
        return new AsyncResult<>(user);
    }

    public void saveUser(User user) throws InterruptedException {
        log.info("save user: {}", user);
        Thread.sleep(random.nextInt(1000));
    }
}

使用方式如下:

@RunWith(SpringRunner.class)
@SpringBootTest(classes = Application.class)
public class UserServiceTest {

    private static final Logger log = LoggerFactory.getLogger(UserServiceTest.class);

    @Autowired
    private UserService userService;

    @Test
    public void initUserTest() throws InterruptedException {
        User user = userService.initUser();
        userService.saveUser(user);
    }

    @Test
    public void initUserAsyncTest() throws ExecutionException, InterruptedException {
        Future<User> future = userService.initUserAsync();
        User user = future.get();
        userService.saveUser(user);
    }
}

执行结果表明异步方法可以提前返回,不必等到User对象初始化完成。

至此,我们已经对Spring中的@Async用法进行了详细的讲解,并提供了两个实际应用的示例,相信能够帮助读者更好地理解和使用@Async注解。

本站文章如无特殊说明,均为本站原创,如若转载,请注明出处:Spring中@Async用法详解及简单实例 - Python技术站

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

相关文章

  • 微信小程序 websocket 实现SpringMVC+Spring+Mybatis

    下面是实现“微信小程序 websocket 实现SpringMVC+Spring+Mybatis”的完整攻略: 1. 确定小程序基本环境和websocket环境 首先,要开发微信小程序,需要选择对应的开发环境和工具,例如开发者工具、微信web开发者工具等等。同时还需要了解微信小程序开发的基本要求和技术规范。 对于websocket环境,则需要了解websoc…

    Java 2023年5月23日
    00
  • Java基础-Java的体系结构

    Java的体系结构 Java的体系结构包含三个核心部分:JVM、JRE和JDK。其中JDK是对JRE的扩展,而JRE又是对JVM的扩展。 JVM JVM,即Java虚拟机,是Java平台的最核心部分。它是Java的运行环境,其作用是将Java字节码文件解释成能够在特定操作系统中运行的机器语言,并将其加载到内存中。 Java语言的跨平台特性正是由JVM所实现的…

    Java 2023年5月19日
    00
  • 关于JavaScript作用域你想知道的一切

    关于JavaScript作用域你想知道的一切 什么是作用域? 在介绍作用域之前,我们先来看一下变量的定义。在JavaScript中,我们可以通过var、let或const三个关键字来声明变量。 var a = 1; // 使用var声明的变量 let b = 2; // 使用let声明的变量 const c = 3; // 使用const声明的变量 那么,作…

    Java 2023年6月16日
    00
  • java中ArrayList和LinkedList的区别详解

    Java 中 ArrayList 和 LinkedList 的区别详解 在 Java 中,ArrayList 和 LinkedList 均为常见的集合类,两者在实现以及使用场景上有一些区别。接下来将详细讲解这两种数据结构的区别。 ArrayList ArrayList 是 List 接口的实现类,底层是一个数组,因为是数组实现,所以支持快速随机访问,根据下标…

    Java 2023年5月26日
    00
  • Java 中运行字符串表达式的方法

    要在Java中运行字符串表达式,需要使用Java中的反射机制。下面是一个完整的步骤: 步骤一:准备字符串表达式 首先需要准备一个字符串表达式用于运行。例如: String expression = "2*3+4"; 步骤二:获取对应函数对象 使用Java反射机制,可以通过字符串获取表达式对应的函数对象,例如: Class mathClas…

    Java 2023年5月26日
    00
  • 基于Listener监听器生命周期(详解)

    基于Listener监听器生命周期(详解) 在Java Web应用中,我们可以通过监听器(Listener)来监听 Web应用中的事件,如ServletContext的创建与销毁、HttpSession的创建与销毁、ServletRequest的创建与销毁等等。本文将详细介绍Listener的生命周期。 1. Listener简介和分类 Listener(监…

    Java 2023年6月15日
    00
  • JVM处理未捕获异常的方法详解

    JVM处理未捕获异常的方法详解 Java虚拟机(JVM)是一种执行Java字节码的虚拟机,它是Java应用程序必须运行的平台。在Java程序中,JVM可以处理未捕获异常(Uncaught Exception)来保证程序的正常运行。本文将详细讲解JVM处理未捕获异常的方法。 何为未捕获异常 在Java程序中,异常分为已检查异常(Checked Exceptio…

    Java 2023年5月27日
    00
  • 目前最全的python的就业方向

    当谈到Python就业方向时,受众人群极为广泛。无论您是新手,依靠Python技能入行,还是跨专业发展、想要转行为Python工程师,或是已经加入工程师界,希望扩大技能栈,这些适用于每个等级的就业方向,对于Python开发人员来说都是有用的。 以下是目前最全的Python的就业方向的攻略: 1. Web开发 Web开发是目前Python领域中的主要就业方向之…

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