使用SpringBoot异步方法优化查询接口,提高接口响应速度

合理使用异步方法可以提高接口性能。异步方法适用于逻辑与逻辑之间可以相互分割互不影响的业务中。

SpringBoot 支持异步方法调用。具体用法:

  1. 在启动类添加@EnableAsync注解,声明开启异步方法
  2. 在异步方法添加@Async注解,被@Async注解修改的方法由SpringBoot默认线程池(SimpleAsyncTaskExecutor)执行。

注意:

  • 异步方法可以不使用默认线程池 SimpleAsyncTaskExecutor,可以自定义线程池执行。

  • 如果直接将需要异步操作的方法写到业务类中,业务类直接调用,异步方法会失效。因为@Async的调用涉及到动态代理,业务类直接调用的话,则执行逻辑不会走到代理类。因此需要将 @Async 注解的方法单独拿出来封装到一个类中,再将这个类注入到业务类中,业务类通过这个类来调用异步方法

  • 如果要获取异步方法的返回值,需要使用Future类及其子类来接收异步方法返回值,推荐使用 CompletableFuture

自定义线程池执行异步方法

1.新增线程池配置类

package com.study.config;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor;

import java.util.concurrent.Executor;
import java.util.concurrent.ThreadPoolExecutor;

/**
 * 线程池配置类
 */
@Configuration
public class TaskThreadPoolConfig {

    private static final Logger logger = LoggerFactory.getLogger(TaskThreadPoolConfig.class);

    @Value("${task.execution.pool.core-size}")
    private int corePoolSize;
    @Value("${task.execution.pool.max-size}")
    private int maxPoolSize;
    @Value("${task.execution.pool.queue-capacity}")
    private int queueCapacity;
    @Value("${task.execution.pool.keep-alive}")
    private int keepAliveSeconds;
    @Value("${task.execution.pool.name-prefix}")
    private String namePrefix;


    @Bean("executeService")
    public Executor asyncServiceExecutor() {
        logger.info("start asyncServiceExecutor");
        //ThreadPoolTaskExecutor是Spring提供的线程池,底层也是使用JDK的ThreadPoolExecutor实现的。
        ThreadPoolTaskExecutor threadPoolTaskExecutor = new ThreadPoolTaskExecutor();
        //配置核心线程数
        threadPoolTaskExecutor.setCorePoolSize(corePoolSize);
        //配置最大线程数
        threadPoolTaskExecutor.setMaxPoolSize(maxPoolSize);
        //配置队列大小
        threadPoolTaskExecutor.setQueueCapacity(queueCapacity);
        //当线程数大于核心线程数,终止多余线程等待新任务的最长时间
        threadPoolTaskExecutor.setKeepAliveSeconds(keepAliveSeconds);
        //配置线程池中的线程的名称前缀
        threadPoolTaskExecutor.setThreadNamePrefix(namePrefix);
        //配置线程的饱和策略。CALLER_RUNS:不在新线程中执行任务,而是有调用者所在的线程来执行
        threadPoolTaskExecutor.setRejectedExecutionHandler(new ThreadPoolExecutor.CallerRunsPolicy());
        //执行初始化
        threadPoolTaskExecutor.initialize();
        return threadPoolTaskExecutor;
    }
}

2.在Async注解指定使用的线程池

@Async("executeService")

使用CompletableFuture获取异步方法返回值

比如:在业务类要异步(method1和method2)获取信息组合到infoMap集合并返回数据。

// 数据1 
CompletableFuture<String> data1 = this.testService.method1();

// 数据2
CompletableFuture<String> data2 = this.testService.method2();

//allOf() 方法会等到所有的 CompletableFuture 都运行完成之后再返回.调用 join() 可以让程序等所有CompletableFuture都运行完了之后再继续执行。
CompletableFuture.allOf(data1, data2).join();
        
infoMap.put("data1", data1.get());
infoMap.put("data2", data2.get());

参考资料

posted @ 2023-03-31 14:24  享受生活2023  阅读(411)  评论(0编辑  收藏  举报