让你的 Spring Boot 应用飞起来!@Async 异步编程魔法

这篇文章是用来详细讲解 @Async 注解,它解决的问题,以及使用方法,并提供由易到难的实例,最后用大白话总结,方面各位理解。

一、@Async 是什么?解决了什么问题?

  • @Async 是什么: @Async 是 Spring 框架提供的一个注解,用于将方法标记为异步执行。简单来说,就是让这个方法在另一个线程中执行,而不是在调用它的线程中执行。

  • 解决了什么问题:

    • 提高响应速度: 当一个方法执行时间较长时,如果同步执行,会导致调用它的线程阻塞,影响程序的响应速度。使用 @Async 可以将这个方法放到另一个线程中执行,让调用线程可以继续执行其他任务,从而提高程序的响应速度。
    • 提高并发能力: 当需要同时执行多个耗时任务时,可以使用 @Async 将这些任务放到不同的线程中执行,从而提高程序的并发能力。
    • 避免阻塞主线程: 在 Web 应用中,如果某个请求处理需要执行耗时操作,可以使用 @Async 将这个操作放到另一个线程中执行,避免阻塞主线程,从而提高 Web 应用的吞吐量。

二、@Async 的使用方法

  1. 开启异步支持: 在 Spring Boot 应用的主类上添加 @EnableAsync 注解,开启异步支持。

  2. 标记异步方法: 在需要异步执行的方法上添加 @Async 注解。

三、@Async 实例 (由易到难)

1. 简单示例:异步发送邮件

  • 需求: 用户注册成功后,异步发送一封欢迎邮件。

  • 步骤:

    1. 创建 Spring Boot 应用:

      • 使用 Spring Initializr 创建一个 Spring Boot 应用。
      • 添加 spring-boot-starter-web 依赖。
    2. 开启异步支持:

      • MyApplication.java (或者你的主类) 中添加 @EnableAsync 注解:

        import org.springframework.boot.SpringApplication;
        import org.springframework.boot.autoconfigure.SpringBootApplication;
        import org.springframework.scheduling.annotation.EnableAsync;
        
        @SpringBootApplication
        @EnableAsync // 开启异步支持
        public class MyApplication {
        
            public static void main(String[] args) {
                SpringApplication.run(MyApplication.class, args);
            }
        }
        
    3. 创建邮件发送服务:

      import org.springframework.scheduling.annotation.Async;
      import org.springframework.stereotype.Service;
      
      @Service
      public class EmailService {
      
          @Async // 标记为异步方法
          public void sendWelcomeEmail(String email) {
              // 模拟发送邮件,耗时 5 秒
              System.out.println("Sending welcome email to " + email + "...");
              try {
                  Thread.sleep(5000);
              } catch (InterruptedException e) {
                  e.printStackTrace();
              }
              System.out.println("Welcome email sent to " + email);
          }
      }
      
      • 解释:
        • @Async:将 sendWelcomeEmail() 方法标记为异步方法。
        • Thread.sleep(5000):模拟发送邮件的耗时操作。
    4. 创建用户注册服务:

      import org.springframework.beans.factory.annotation.Autowired;
      import org.springframework.stereotype.Service;
      
      @Service
      public class UserService {
      
          @Autowired
          private EmailService emailService;
      
          public void registerUser(String email) {
              // 模拟用户注册
              System.out.println("Registering user with email: " + email);
      
              // 异步发送欢迎邮件
              emailService.sendWelcomeEmail(email);
      
              System.out.println("User registered successfully.");
          }
      }
      
      • 解释:
        • emailService.sendWelcomeEmail(email):调用 EmailServicesendWelcomeEmail() 方法发送邮件。
    5. 创建 Controller:

      import org.springframework.beans.factory.annotation.Autowired;
      import org.springframework.web.bind.annotation.GetMapping;
      import org.springframework.web.bind.annotation.RequestParam;
      import org.springframework.web.bind.annotation.RestController;
      
      @RestController
      public class UserController {
      
          @Autowired
          private UserService userService;
      
          @GetMapping("/register")
          public String register(@RequestParam("email") String email) {
              userService.registerUser(email);
              return "User registration initiated.  Check console for async email sending.";
          }
      }
      
    6. 运行应用:

      • 运行 MyApplication 类。
    7. 测试 API:

      • 在浏览器或使用 curl 命令访问以下 URL:

        http://localhost:8080/register?email=test@example.com
        
      • 你应该会看到 "User registration initiated." 的响应,并且在控制台中会看到异步发送邮件的日志。

  • 代码: (完整代码)

    // MyApplication.java
    package com.example;
    
    import org.springframework.boot.SpringApplication;
    import org.springframework.boot.autoconfigure.SpringBootApplication;
    import org.springframework.scheduling.annotation.EnableAsync;
    
    @SpringBootApplication
    @EnableAsync
    public class MyApplication {
    
        public static void main(String[] args) {
            SpringApplication.run(MyApplication.class, args);
        }
    }
    
    // EmailService.java
    package com.example;
    
    import org.springframework.scheduling.annotation.Async;
    import org.springframework.stereotype.Service;
    
    @Service
    public class EmailService {
    
        @Async
        public void sendWelcomeEmail(String email) {
            System.out.println("Sending welcome email to " + email + "...");
            try {
                Thread.sleep(5000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            System.out.println("Welcome email sent to " + email);
        }
    }
    
    // UserService.java
    package com.example;
    
    import org.springframework.beans.factory.annotation.Autowired;
    import org.springframework.stereotype.Service;
    
    @Service
    public class UserService {
    
        @Autowired
        private EmailService emailService;
    
        public void registerUser(String email) {
            System.out.println("Registering user with email: " + email);
            emailService.sendWelcomeEmail(email);
            System.out.println("User registered successfully.");
        }
    }
    
    // UserController.java
    package com.example;
    
    import org.springframework.beans.factory.annotation.Autowired;
    import org.springframework.web.bind.annotation.GetMapping;
    import org.springframework.web.bind.annotation.RequestParam;
    import org.springframework.web.bind.annotation.RestController;
    
    @RestController
    public class UserController {
    
        @Autowired
        private UserService userService;
    
        @GetMapping("/register")
        public String register(@RequestParam("email") String email) {
            userService.registerUser(email);
            return "User registration initiated.  Check console for async email sending.";
        }
    }
    

2. 中级示例:自定义线程池

  • 需求: 使用自定义的线程池来执行异步任务。

  • 步骤:

    1. 创建线程池配置类:

      import org.springframework.context.annotation.Bean;
      import org.springframework.context.annotation.Configuration;
      import org.springframework.scheduling.annotation.EnableAsync;
      import org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor;
      
      import java.util.concurrent.Executor;
      
      @Configuration
      @EnableAsync
      public class AsyncConfig {
      
          @Bean(name = "taskExecutor") // 指定线程池的名称
          public Executor taskExecutor() {
              ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor();
              executor.setCorePoolSize(5); // 核心线程数
              executor.setMaxPoolSize(10); // 最大线程数
              executor.setQueueCapacity(25); // 队列容量
              executor.setThreadNamePrefix("MyAsyncThread-"); // 线程名称前缀
              executor.initialize();
              return executor;
          }
      }
      
      • 解释:
        • @Configuration:将 AsyncConfig 类标记为一个配置类。
        • @EnableAsync:开启异步支持。
        • @Bean(name = "taskExecutor"):创建一个名为 taskExecutor 的 Bean,类型为 Executor
        • ThreadPoolTaskExecutor:Spring 提供的线程池实现。
        • setCorePoolSize():设置核心线程数。
        • setMaxPoolSize():设置最大线程数。
        • setQueueCapacity():设置队列容量。
        • setThreadNamePrefix():设置线程名称前缀。
    2. 指定使用的线程池:

      import org.springframework.scheduling.annotation.Async;
      import org.springframework.stereotype.Service;
      
      @Service
      public class EmailService {
      
          @Async("taskExecutor") // 指定使用的线程池名称
          public void sendWelcomeEmail(String email) {
              System.out.println("Sending welcome email to " + email + "...");
              try {
                  Thread.sleep(5000);
              } catch (InterruptedException e) {
                  e.printStackTrace();
              }
              System.out.println("Welcome email sent to " + email);
          }
      }
      
      • 解释:
        • @Async("taskExecutor"):指定使用名为 taskExecutor 的线程池来执行 sendWelcomeEmail() 方法。

3. 高级示例:异步任务的异常处理

  • 需求: 捕获异步任务中发生的异常,并进行处理。

  • 步骤:

    1. 实现 AsyncConfigurer 接口:

      import org.springframework.aop.interceptor.AsyncUncaughtExceptionHandler;
      import org.springframework.context.annotation.Configuration;
      import org.springframework.scheduling.annotation.AsyncConfigurer;
      import org.springframework.scheduling.annotation.EnableAsync;
      
      import java.lang.reflect.Method;
      import java.util.concurrent.Executor;
      
      @Configuration
      @EnableAsync
      public class AsyncConfig implements AsyncConfigurer {
      
          @Override
          public Executor getAsyncExecutor() {
              // 可以自定义线程池
              return null;
          }
      
          @Override
          public AsyncUncaughtExceptionHandler getAsyncUncaughtExceptionHandler() {
              return new MyAsyncExceptionHandler();
          }
      }
      
      • 解释:
        • AsyncConfigurer:Spring 提供的接口,用于配置异步任务。
        • getAsyncExecutor():可以自定义线程池。
        • getAsyncUncaughtExceptionHandler():用于指定异步任务的异常处理器。
    2. 创建异常处理器:

      import org.springframework.aop.interceptor.AsyncUncaughtExceptionHandler;
      
      import java.lang.reflect.Method;
      
      public class MyAsyncExceptionHandler implements AsyncUncaughtExceptionHandler {
      
          @Override
          public void handleUncaughtException(Throwable ex, Method method, Object... params) {
              System.err.println("Async method has uncaught exception:");
              System.err.println("Method: " + method.getName());
              System.err.println("Exception message: " + ex.getMessage());
          }
      }
      
      • 解释:
        • AsyncUncaughtExceptionHandler:Spring 提供的接口,用于处理异步任务中发生的未捕获异常。
        • handleUncaughtException():处理异常的方法。

四、大白话总结

  • @Async 就像请了一个 "临时工",帮你干一些比较慢的活,这样你就不用一直等着,可以先去干其他的事情。
  • @EnableAsync 告诉 Spring "我要用临时工了!"
  • 线程池: 就像一个 "临时工管理中心",可以管理多个 "临时工",让他们更有效率地工作。
  • 异常处理: 就像给 "临时工" 买了保险,万一他们出了什么问题,也能及时处理。

更简洁的总结:

  • @Async 让方法异步执行,就像请了个临时工。
  • @EnableAsync 开启异步支持,告诉 Spring 可以用临时工了。
  • 可以自定义线程池,管理临时工。
  • 可以进行异常处理,给临时工买保险。

希望这篇文章能够帮助你理解 @Async 注解!

posted @   Redemptions  阅读(15)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· DeepSeek “源神”启动!「GitHub 热点速览」
· 我与微信审核的“相爱相杀”看个人小程序副业
· 微软正式发布.NET 10 Preview 1:开启下一代开发框架新篇章
· C# 集成 DeepSeek 模型实现 AI 私有化(本地部署与 API 调用教程)
· spring官宣接入deepseek,真的太香了~
点击右上角即可分享
微信分享提示