Spring Boot 异步编程

文章目录

    • 一、异步方法的使用
      • 1. 开启异步支持
      • 2. 定义异步方法
      • 3. 调用异步方法
      • 踩坑记录
      • 心得体会
    • 二、线程池配置
      • 1. 自定义线程池
      • 2. 使用自定义线程池
      • 踩坑记录
      • 心得体会
    • 三、异步任务的监控与管理
      • 1. 日志记录
      • 2. 异常处理
      • 3. 线程池监控
      • 踩坑记录
      • 心得体会

在现代应用程序开发中,异步编程是提升系统性能和响应能力的重要手段。Spring Boot 提供了便捷的方式来实现异步编程,下面将详细介绍异步方法的使用、线程池配置以及异步任务的监控与管理。

一、异步方法的使用

1. 开启异步支持

在 Spring Boot 主应用类上添加 @EnableAsync 注解,开启 Spring 的异步方法执行功能。

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.scheduling.annotation.EnableAsync;

@SpringBootApplication
@EnableAsync
public class AsyncApp {
    public static void main(String[] args) {
        SpringApplication.run(AsyncApp.class, args);
    }
}

2. 定义异步方法

在需要异步执行的方法上添加 @Async 注解。

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

import java.util.concurrent.CompletableFuture;

@Service
public class AsyncService {

    @Async
    public CompletableFuture<String> asyncTask() {
        try {
            // 模拟耗时操作
            Thread.sleep(2000);
        } catch (InterruptedException e) {
            Thread.currentThread().interrupt();
        }
        return CompletableFuture.completedFuture("异步任务执行完成");
    }
}

3. 调用异步方法

在控制器或者其他服务类中注入包含异步方法的服务类,并调用异步方法。

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

import java.util.concurrent.CompletableFuture;
import java.util.concurrent.ExecutionException;

@RestController
public class AsyncController {

    @Autowired
    private AsyncService asyncService;

    @GetMapping("/async")
    public String asyncCall() throws InterruptedException, ExecutionException {
        CompletableFuture<String> future = asyncService.asyncTask();
        // 可以在此处执行其他操作
        // 等待异步任务完成并获取结果
        return future.get();
    }
}

踩坑记录

  • 注解未生效:若 @EnableAsync 未添加到主应用类,或者异步方法所在类未被 Spring 管理(如未加 @Service 等注解),@Async 注解将不生效。此外,若在同一类中直接调用异步方法,而非通过 Spring 代理对象调用,也不会异步执行,因为 Spring 的 AOP 代理机制基于代理对象。
  • 返回值处理不当:有返回值的异步方法需用 CompletableFuture 包装,若直接返回普通类型,调用 get() 方法获取结果时可能阻塞或抛异常。

心得体会

要深刻理解 Spring 的 AOP 代理机制对 @Async 注解的影响,设计代码时尽量通过依赖注入和代理对象调用异步方法。同时,对于有返回值的异步方法,务必使用 CompletableFuture 包装,并妥善处理 get() 方法可能抛出的异常。

二、线程池配置

1. 自定义线程池

默认情况下,Spring Boot 使用简单线程池执行异步任务。可通过创建配置类,使用 ThreadPoolTaskExecutor 自定义线程池。

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 = "customAsyncExecutor")
    public Executor asyncExecutor() {
        ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor();
        // 核心线程数
        executor.setCorePoolSize(5);
        // 最大线程数
        executor.setMaxPoolSize(10);
        // 队列容量
        executor.setQueueCapacity(25);
        // 线程名前缀
        executor.setThreadNamePrefix("CustomAsyncThread-");
        // 线程池关闭时等待所有任务完成
        executor.setWaitForTasksToCompleteOnShutdown(true);
        // 等待任务完成的时间
        executor.setAwaitTerminationSeconds(60);
        // 初始化线程池
        executor.initialize();
        return executor;
    }
}

2. 使用自定义线程池

@Async 注解中指定使用自定义线程池的名称。

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

import java.util.concurrent.CompletableFuture;

@Service
public class AsyncService {

    @Async("customAsyncExecutor")
    public CompletableFuture<String> asyncTask() {
        try {
            Thread.sleep(2000);
        } catch (InterruptedException e) {
            Thread.currentThread().interrupt();
        }
        return CompletableFuture.completedFuture("异步任务执行完成");
    }
}

踩坑记录

  • 参数设置不合理:核心线程数、最大线程数和队列容量设置需根据业务场景调整。核心线程数过小,任务处理不及时;最大线程数过大,占用过多系统资源。队列容量过小,新任务可能被拒绝;过大则可能导致任务堆积,影响系统响应时间。
  • 未正确初始化:配置线程池时,若忘记调用 executor.initialize() 方法,线程池可能无法正常工作,导致异步任务无法执行或执行过程中出现异常。

心得体会

配置线程池时,要充分考虑业务特点和系统资源情况。对于 I/O 密集型任务,可适当增大核心线程数;对于 CPU 密集型任务,核心线程数可相对较小。同时,务必确保调用 initialize() 方法初始化线程池。

三、异步任务的监控与管理

1. 日志记录

在异步方法中添加日志记录,跟踪任务执行过程。

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.scheduling.annotation.Async;
import org.springframework.stereotype.Service;

import java.util.concurrent.CompletableFuture;

@Service
public class AsyncService {
    private static final Logger logger = LoggerFactory.getLogger(AsyncService.class);

    @Async("customAsyncExecutor")
    public CompletableFuture<String> asyncTask() {
        logger.info("异步任务开始执行");
        try {
            Thread.sleep(2000);
        } catch (InterruptedException e) {
            logger.error("异步任务被中断", e);
            Thread.currentThread().interrupt();
        }
        logger.info("异步任务执行完成");
        return CompletableFuture.completedFuture("异步任务执行完成");
    }
}

2. 异常处理

实现 AsyncUncaughtExceptionHandler 接口处理异步方法中抛出的未捕获异常。

import org.springframework.aop.interceptor.AsyncUncaughtExceptionHandler;
import org.springframework.stereotype.Component;

import java.lang.reflect.Method;

@Component
public class CustomAsyncExceptionHandler implements AsyncUncaughtExceptionHandler {

    @Override
    public void handleUncaughtException(Throwable throwable, Method method, Object... objects) {
        System.err.println("异步方法 " + method.getName() + " 抛出未捕获异常");
        for (Object param : objects) {
            System.err.println("参数: " + param);
        }
        throwable.printStackTrace();
    }
}

在配置类中配置异常处理器:

import org.springframework.aop.interceptor.AsyncUncaughtExceptionHandler;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.scheduling.annotation.AsyncConfigurer;
import org.springframework.scheduling.annotation.EnableAsync;
import org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor;

import java.util.concurrent.Executor;

@Configuration
@EnableAsync
public class AsyncConfig implements AsyncConfigurer {

    @Bean(name = "customAsyncExecutor")
    public Executor asyncExecutor() {
        ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor();
        executor.setCorePoolSize(5);
        executor.setMaxPoolSize(10);
        executor.setQueueCapacity(25);
        executor.setThreadNamePrefix("CustomAsyncThread-");
        executor.setWaitForTasksToCompleteOnShutdown(true);
        executor.setAwaitTerminationSeconds(60);
        executor.initialize();
        return executor;
    }

    @Override
    public AsyncUncaughtExceptionHandler getAsyncUncaughtExceptionHandler() {
        return new CustomAsyncExceptionHandler();
    }
}

3. 线程池监控

通过 ThreadPoolTaskExecutor 提供的方法获取线程池状态信息。

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor;
import org.springframework.stereotype.Service;

@Service
public class ThreadPoolMonitorService {
    @Autowired
    private ThreadPoolTaskExecutor customAsyncExecutor;

    public int getActiveThreadCount() {
        return customAsyncExecutor.getActiveCount();
    }

    public int getQueueSize() {
        return customAsyncExecutor.getThreadPoolExecutor().getQueue().size();
    }
}

踩坑记录

  • 日志记录不详细:若日志信息不够详细,排查问题时会遇到困难。例如,只记录任务开始和结束信息,未记录关键步骤执行情况和异常信息,难以定位问题。
  • 异常处理不全面:实现 AsyncUncaughtExceptionHandler 接口时,若未全面处理异常,可能导致部分异常信息丢失。

心得体会

在异步方法中添加详细日志记录,包括任务开始、关键步骤、异常信息等,以便出现问题时能快速定位。实现异常处理器时,要尽可能全面记录异常信息,为问题排查和修复提供有力支持。

总之,Spring Boot 异步编程能显著提升系统性能和响应能力,但实际使用中需注意各种细节,避免踩坑。通过不断实践和总结经验,才能更好地掌握异步编程技巧。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值