异步处理:Spring @Async 注解深度剖析!

开发
Spring @Async 注解提供了一个非常简单而且强大的机制来支持异步方法的执行。这篇文章,我们来深度剖析 Spring @Async 的工作原理!

Spring @Async 注解提供了一个非常简单而且强大的机制来支持异步方法的执行。如果将方法标记为@Async,Spring会在后台线程中异步执行该方法,而不会阻塞调用该方法的线程。这对于提高应用程序的响应性和性能是非常有用的,尤其是在处理I/O密集型操作时。这篇文章,我们来深度剖析 Spring @Async 的工作原理!

1. 原理概述

使用@Async注解时,Spring 借助 AOP(面向切面编程)实现异步执行,具体来说,@Async的工作原理主要包括以下几个步骤:

  • 代理对象创建:Spring 使用动态代理创建被注解方法的代理对象。只有与代理对象交互时,@Async 注解才会起作用。
  • 线程池配置:异步方法调用通过 Spring 提供的 TaskExecutor(如 SimpleAsyncTaskExecutor, ThreadPoolTaskExecutor 等)来实现多线程处理。开发者可以自定义线程池设置,以适应不同的使用场景。
  • 方法执行:当调用被 @Async 注解的方法时,Spring 将检测到这个注解,然后将方法的调用委托给一个线程池中的线程。在这个线程执行完成后,控制权就会返回到调用线程,不会被阻塞。

2. 核心代码分析

下面我们深入探讨@Async的几个核心类的实现细节。

(1) @Async 注解

@Async注解的定义非常简单,位于org.springframework.scheduling.annotation包中:

@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
public @interface Async {
    String value() default "";
}

通过上面的源码可以看出:@Async注解只支持放在方法上,并可以指定一个可选的线程池名称。

(2) AsyncConfiguration类

要启用异步处理功能,我们需要有一个配置类或在Spring Boot应用程序中使用@EnableAsync注解。这个注解会触发 Spring的异步支持机制。

@Configuration
@EnableAsync
public class AsyncConfig extends AsyncConfigurerSupport {
    @Override
    public Executor getAsyncExecutor() {
        ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor();
        executor.setCorePoolSize(5);
        executor.setMaxPoolSize(10);
        executor.setQueueCapacity(25);
        executor.initialize();
        return executor;
    }
}

在这个示例中,我们扩展了AsyncConfigurerSupport类,并重写了getAsyncExecutor方法来提供自定义的线程池。

(3) Proxy 生成

Spring 通过 AOP 动态代理机制处理 @Async 注解。具体过程如下:

  • Spring 在创建代理对象时,检查被注解的方法。
  • 如果发现方法上有 @Async 注解,Spring 将为这个方法生成一个增强版本,以确保调用被转发到线程池中的一个工作线程。

通常,Spring 会使用 JDK 动态代理或者 CGLIB 代理。JDK 代理基于接口创建代理实例,而 CGLIB 可以基于类创建代理实例。

(4) 异步方法的调用

以下是 @Async 方法的简单示例:

@Service
public class MyAsyncService {
    @Async
    public void asyncMethod() {
        System.out.println("Executing in " + Thread.currentThread().getName());
    }
}

调用 asyncMethod() 方法时,控制将立即返回,不会阻塞。实际方法将在其他线程中执行。

(5) AsyncExecutionInterceptor

AsyncExecutionInterceptor 类是 Spring 处理异步执行的核心部分。它实现了 MethodInterceptor 接口,能够拦截方法调用,进行异步执行处理。

public class AsyncExecutionInterceptor extends AbstractAsyncExecutionInterceptor {
    @Override
    public Object invoke(MethodInvocation invocation) throws Throwable {
        return doInvoke(invocation);
    }
}

在 invoke 方法中,doInvoke 方法会被调用,负责具体的执行逻辑。

3.示例

为了更好地理解 @Async 的使用,我们通过一个完整的示例来演示如何使用 Spring @Async 注解实现异步方法调用,示例将包含以下部分:

  • Spring Boot 项目结构。
  • @Async 注解的实现和配置。
  • 异步方法的调用示例。
  • 运行时的输出示例。

(1) 创建 Spring Boot 项目

假设你使用 Spring Boot 创建项目,可以创建一个新的 Gradle 或 Maven 项目,添加以下依赖项到 pom.xml(如果使用 Maven):

<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter</artifactId>
</dependency>
<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-aop</artifactId>
</dependency>

(2) 配置异步支持

创建一个配置类来启用异步支持,使用 @EnableAsync 注解。

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(2);
        executor.setMaxPoolSize(5);
        executor.setQueueCapacity(10);
        executor.setThreadNamePrefix("Async-");
        executor.initialize();
        return executor;
    }
}

(3) 创建异步服务类

接下来,创建一个服务类,其中将包含异步方法。该方法将模拟一些耗时的操作。

import org.springframework.scheduling.annotation.Async;
import org.springframework.stereotype.Service;

@Service
public class MyAsyncService {

    @Async("taskExecutor")
    public void asyncMethod() {
        System.out.println("Executing async method: " + Thread.currentThread().getName());
        try {
            // 模拟耗时的操作
            Thread.sleep(3000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        System.out.println("Async method execution finished: " + Thread.currentThread().getName());
    }
}

(4) 创建控制器类

创建一个控制器类,调用异步服务中的方法:

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;

@RestController
public class MyAsyncController {

    @Autowired
    private MyAsyncService myAsyncService;

    @GetMapping("/asyncTest")
    public String callAsync() {
        System.out.println("Calling async method");
        myAsyncService.asyncMethod();
        return "Async method called!";
    }
}

(5) 主应用程序类

创建 Spring Boot 启动类,用于启动应用程序:

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;

@SpringBootApplication
public class AsyncApplication {

    public static void main(String[] args) {
        SpringApplication.run(AsyncApplication.class, args);
    }
}

(6) 运行应用程序

启动 Spring Boot 应用程序,在浏览器中访问以下 URL:http://localhost:8080/asyncTest

输出结果为:

Calling async method
Executing async method: Async-1
Async method execution finished: Async-1

在浏览器中,页面将返回 “Async method called!” 的信息,而不会等待 asyncMethod 完成执行。这表示 asyncMethod 在另一个线程上异步执行。

4. 总结

通过以上分析,我们可以看到 Spring 的@Async提供了异步编程的简便机制。它的实现依赖于 AOP代理,以及可配置的线程池。透过这些机制,Spring 能够将对异步方法的调用转发到后台线程中执行,同时保证主线程不会被阻塞。

责任编辑:赵宁宁 来源: 猿java
相关推荐

2024-06-13 00:54:19

2021-08-04 17:20:30

阿里巴巴AsyncJava

2024-05-07 08:23:03

Spring@Async配置

2024-08-22 10:39:50

@Async注解代理

2017-04-19 08:47:42

AsyncJavascript异步代码

2018-09-18 16:20:08

Asyncjavascript前端

2018-06-21 14:46:03

Spring Boot异步调用

2022-09-27 18:56:28

ArrayList数组源代码

2024-02-05 19:06:04

DartVMGC流程

2010-01-13 13:42:55

C++编译器

2024-07-12 14:46:20

2024-07-11 08:17:00

2021-11-11 15:25:28

@AsyncJava线程池

2024-03-28 12:51:00

Spring异步多线程

2010-03-05 16:38:30

2010-02-04 15:38:39

Android 手机

2010-02-02 15:25:35

Python语法

2010-02-03 16:56:24

Python包

2010-02-01 13:34:59

Python 脚本

2020-04-01 10:28:12

Apache HBas数据结构算法
点赞
收藏

51CTO技术栈公众号