标签搜索

目 录CONTENT

文章目录

SpringBoot异步接口编码新姿势

陈铭
2023-04-22 / 0 评论 / 0 点赞 / 156 阅读 / 682 字 / 正在检测是否收录...

最近写的业务接口由于底层再次调了数仓的接口(DataWorks),接口很慢。而对于同个浏览器和同个请求地址来说,多次访问接口,SpringBoot也只会在单线程执行接口的业务逻辑(当然,用别的接口或者换个地址去调,Controller是多线程去处理的)。因此,这边准备改造成异步接口

异步接口模块

这边创建了一个子模块rycem-common_async_api,主要定义了一些异步注解和配置类

pom

    <dependencies>
        <!-- SpringBoot Web -->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>

        <!-- lombak-->
        <dependency>
            <groupId>org.projectlombok</groupId>
            <artifactId>lombok</artifactId>
        </dependency>
        <dependency>
            <groupId>io.springfox</groupId>
            <artifactId>springfox-core</artifactId>
            <version>3.0.0</version>
            <scope>compile</scope>
        </dependency>
    </dependencies>

注解

@AsyncRycemApi

到时候要用在Service层的方法上,本质上就是包装了 @Async

package com.rycem.async_api.annotation;

import org.springframework.scheduling.annotation.Async;

import java.lang.annotation.*;

/**
 * @ClassName AsyncRycemApi
 * @Author 陈铭
 * @Date 16:12 2023/4/21
 * @Version 1.0
 **/
@Target({ElementType.TYPE, ElementType.METHOD})
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Inherited
@Async
public @interface AsyncRycemApi {
}

@EnableAsyncRycemApi

包装了 @EnableAsync

package com.rycem.async_api.annotation;

import org.springframework.scheduling.annotation.EnableAsync;

import java.lang.annotation.*;

/**
 * @ClassName EnableAsyncRycemApi
 * @Author 陈铭
 * @Date 16:12 2023/4/21
 * @Version 1.0
 **/
@Target({ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Inherited
@EnableAsync
public @interface EnableAsyncRycemApi {
}

配置类

package com.rycem.async_api.config;

import com.rycem.async_api.annotation.EnableAsyncRycemApi;
import lombok.extern.slf4j.Slf4j;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.core.task.TaskExecutor;
import org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor;

/**
 * @ClassName ExecutorPoolConfig
 * @Author 陈铭
 * @Date 16:11 2023/4/21
 * @Version 1.0
 **/
@Slf4j
@EnableAsyncRycemApi
@Configuration
public class ExecutorPoolConfig {

    public static final Integer CORE_THREAD_NUM = 15;
    public static final Integer MAX_THREAD_NUM = 100;
    public static final Integer MAX_QUEUE_NUM = 1000;

    @Bean
    public TaskExecutor getTaskExecutor() {
        ThreadPoolTaskExecutor pool = new ThreadPoolTaskExecutor();
        pool.setCorePoolSize(CORE_THREAD_NUM); //核心线程数
        pool.setMaxPoolSize(MAX_THREAD_NUM); //最大线程数
        pool.setQueueCapacity(MAX_QUEUE_NUM); //线程队列
        pool.initialize(); //线程初始化
        log.info("【异步API线程池加载完毕】");
        return pool;
    }
}

使用异步接口注解

pom

在需要使用异步接口的模块pom中,加入依赖

        <dependency>
            <groupId>cn.com.ruijie.rycem</groupId>
            <artifactId>rycem-common_async_api</artifactId>
        </dependency>

使用@AsyncRycemApi

在service层的对应方法加上注解即可

@Service
@RequiredArgsConstructor
public class CasesysServiceImpl implements CasesysService {

    @AsyncRycemApi
    public Future<ResultBody<CustomerOrderListBody>> getCustomerOrderList(CustomerOrderListApiQuery customerOrderListQuery) {
        ResultBody<CustomerOrderListBody> body=xxx;
        return AsyncResult.forValue(body);
    }
}

而Futrue包装的结果可以在Controller层拿出
@PrometheusMetrics、@RycemApiExceptionListen是我自己实现得AOP,输出Prometheus监控和处理RycemApiException异常得

    @GetMapping("xxxx")
    @PrometheusMetrics
    @RycemApiExceptionListen
    public ResultBody<CustomerOrderListBody> getCustomerOrderList(@Validated CustomerOrderListApiQuery customerOrderListQuery) {
        try {
            return casesysOrderService.getCustomerOrderList(customerOrderListQuery).get();
        } catch (InterruptedException | ExecutionException e) {
            throw RycemApiException.getAsyncException();
        }
    }
0

评论区