TaskExecutor和ExecutorService的简单整合

news2024/11/15 19:52:02

文章目录

    • 一、遇到问题
    • 二、达成目的
    • 三、开始调研
      • 1、使用@Async获取线程池流程
      • 2、查看中间件线程池工具类
      • 3、观察AsyncConfigurer接口
      • 4、查看TaskExecutorAdapter源码
    • 四、复盘总结



一、遇到问题

自己负责的项目想通过引入一个中间件,达到在业务场景维度的全链路日志监控。当接入相关中间件后,发现如果在业务中开启了多线程,链路日志就会缺失。当然,该中间件官方给出了解决办法,那就是使用中间件提供的工具类对线程池包装一下(TrackTraceHelper.wrappedExecutorService(executorService))就可以解决。当然这个问题确实解决了,但我们还存在以下几个问题:

问题一:项目原本使用的线程池是Spring的ThreadPoolTaskExecutor,在其setTaskDecorator方法中有进行corp租户信息的传递。功能是否还生效?

问题二:项目有使用@Aync注解开启异步任务。异步注解能否获取到包装后的线程池?




二、达成目的

查看该中间件的源码,发现corp租户信息上下的传递在其底层已经实现,所以这算不是一个问题。在使用@Aync开启异步任务的时候,我们是可以指定线程池的名称的,所以问题二也不是问题。

虽然问题解决了,但是每次使用异步注解都需要去显式的指定名称,感觉这种做法并不友好。有没有一种办法能够在开发者无感知的情况下,实现@Async开启异步线程是、ThreadPoolTaskExecutor线程池的统一,并且这个线程池还是被中间件工具类包装后的,达到既要又要。




三、开始调研

查看Spring源码中异步任务相关的源码,从@EnableAsync注解往下点就完事

1、使用@Async获取线程池流程

根据源码可得出,使用@Async后,异步任务使用线程池流程为:

  1. 我们给显式给@Async指定了线程池
  2. 首先判定有没有实现AsyncConfigurer接口的线程池;
  3. 其次判定有没有TaskExecutor(比如Spring中的ThreadPoolTaskExecutor)类型的线程池Bean;
  4. 再然后就是判定有没有Executor类型的线程池Bean;
  5. 最后,如果都没有,那就使用兜底逻辑,Spring自己创建一个SimpleAsyncTaskExecutor线程池。

在我们已知的情况下,方案1(不友好)和5(无法被中间件工具类包装)肯定也不行,所以只剩下方案2、3、4



2、查看中间件线程池工具类

进入中间件线程池工具类源码,我们不难发现中间件包装的线程池类型,是一个ExecutorService,并且内部有直接调用submit方法。所以方案4,使用Executor类型的线程池肯定会报错。方案3中的TaskExecutor是隶属于Spring的线程池体系,它和Java中的线程池相交的点,只有顶层接口Executor,所以方案3也不行。只剩方案2了。


3、观察AsyncConfigurer接口

我发现getAsyncExecutor方法返回的线程池是一个Executor类型的,这必然也不满足我们的要求,因为我们想要的类型是ExecutorService,所以方案2也不行。

可我还想试试看,万一还有希望呢?既然这里需要返回的类型是Executor,我要是返回一个它的子类ExecutorService,编译肯定是没问题的,并且理论上子类比父类更强大,用起来也不会有问题。但是为了保险,还是继续跟下源码。


4、查看TaskExecutorAdapter源码

继续向下跟Spring异步任务线程池调用的源码,这里不得不称赞Spring源码的兼容性

最终我们会进入到TaskExecutorAdapter内部,这里以submit方法为例:

使用线程池调用submit方法时:

  1. 判断当前线程池是否为ExecutorService类型,如果是则直接强转后调用submit方法
  2. 如果是其它类型,则将任务封装为一个FutureTask,然后调用Executor的execute方法,最后将返回值get出来返回
    即,方案2的做法是可行的。最终线程池的配置代码如下所示:
@Configuration
@ConfigurationProperties(prefix = "spring.task.execution")
public class SpringTaskConfig  implements AsyncConfigurer {
    private final TaskExecutionProperties.Pool pool = new TaskExecutionProperties.Pool();

    /**
     * 使用中间件包装后的线程池
     */
    @Bean
    @Override
    public ExecutorService getAsyncExecutor() {
        ExecutorService executorService = new ThreadPoolExecutor(
                pool.getCoreSize(),
                pool.getMaxSize(),
                pool.getKeepAlive().getSeconds(), TimeUnit.SECONDS,
                new LinkedBlockingQueue<>(pool.getQueueCapacity()),
                new ThreadPoolExecutor.CallerRunsPolicy());
        return TrackTraceHelper.wrappedExecutorService(executorService);
    }
}




四、复盘总结

回头再理一下方案2为什么能成功。

其实Spring自始自终都没有使用Java中ExecutorService这个线程池,而是使用Executor线程池,并且自定义了一个TaskExecutor线程池来替代ExecutorService。AbstractExecutorService中相关的功能也都分别转交给了TaskExecutor的各个子类。

而今天我们的做法,相当于将ExecutorService以Executor子类,但是非TaskExecutor子类的身份进行传递,原本这种做法是有问题,巧在Spring在真正执行的时候,有一个兼容的逻辑判定,而正是这个兼容逻辑的存在完成了我们的目的。

至此,我们就可以在开发成员无感知的情况下,实现线程池的统一了。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/758577.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

【【51单片机的蜂鸣器-11】】

51单片机的蜂鸣器 DS1302我一直有问题搁置了几百天了 先来看看蜂鸣器 搞了一个礼拜verilog然后出去吃饭 估计自己得有10多天没看c语言和51单片机了 现在先处理一下蜂鸣器的问题 蜂鸣器 蜂鸣器分为有源蜂鸣器和无源蜂鸣器 有源内部自带震荡源&#xff0c;将正负极接上直流电压…

类之间的关系

1. 关系强弱顺序&#xff08;由强到弱&#xff09; 泛化实现组合聚合关联依赖 图中&#xff0c;组合和聚合标错了 2. 依赖 虚线箭头&#xff0c;箭头指向被依赖类依赖关系描述了两个类之间的临时关系。通常不会持续整个对象的生命周期&#xff0c;而是创建一个临时的关系以满…

string【1】介绍与使用(超详解哦)

string的介绍与使用 引言string类常用接口构造函数容量操作size与lengthcapacityresizereserveclearempty 元素访问迭代器访问beginendrbeginrend范围for 下标访问 字符串修改insertappendpush_backoperatorpop_backerase 字符串查找findrfind 非成员函数operator>>opera…

光场成像2.0——聚焦型光场相机

光场2.0 1. 发展历程 由于光场1.0从结构上子图像的分辨率严重依赖MLA子透镜的数量&#xff0c;因此分辨率一直受限&#xff0c;限制了光场1.0结构的广泛应用。针对此不足&#xff0c;在2008年&#xff0c;又一篇伟大的论文出现了&#xff0c;该论文提出了全分辨率光场渲染的概…

CS拒绝连接,Cobalt Strike连接失败,Cobalt Strike使用方法(一)

拒绝连接 connection refused:connect。 kali端&#xff08;服务器端&#xff09;和本地端win10。看看端口开启状态 先启动服务器端 查看端口开启状态&#xff0c;确定50050端口开启&#xff0c;可以参阅本文章点击跳转 没问题再往下看。 使用步骤 chmod 777 ./teamserver…

【运维工程师学习】Centos中MySQL替换MariaDB

【运维工程师学习】Centos8中MySQL替换MariaDB 1、查看已有的mysql2、MySQL官网tar包下载3、找到下载路径解压4、移动解压后的文件夹到/usr/local/mysql5、创建data文件夹&#xff0c;一般用于存放数据库文件数据6、创建用户组7、更改用户文件夹权限8、生成my.cnf文件9、编辑my…

排序子序列,倒置字符串讲解(图文并茂)

目录 1.排序子序列 2.倒置字符串 1.排序子序列 排序子序列_牛客笔试题_牛客网 (nowcoder.com) 首先题干中提到非递增序列和非递减序列&#xff0c;那么我们就要先弄明白什么是上述2种序列&#xff1a; 非递增序列&#xff1a;a[i] > a[i1] 如&#xff1a;3 2 1 或者 3 3 …

运动控制-达妙C#开源USB2CAN例程

C# Can总线资料不多, 达妙USB2CAN入口 http://www.dmbot.cn/forum.php?modviewthread&tid328&extrapage%3D1

怎么自学网络安全?遇到问题该怎么解决?

趁着今天下班&#xff0c;我花了几个小时整理了下&#xff0c;非常不易&#xff0c;希望大家可以点赞收藏支持一波&#xff0c;谢谢。 我的经历&#xff1a; 我 19 年毕业&#xff0c;大学专业是物联网工程&#xff0c;我相信很多人在象牙塔里都很迷茫&#xff0c;到了大三大…

帝国cms如何判断首页高亮显示

通过简单的代码判断当前页面是否为首页并且进行高亮的代码如下&#xff1a; 判断逻辑是获取当前栏目id&#xff0c;如果为空则为首页。 条件判断代码&#xff1a; <?php if(empty($GLOBALS[navclassid])){echo class"active";}?> 需要特别说明的此判断会…

二进制文件的Python写入与读取

二进制文件的Python编写 这么基础的东西&#xff0c;必然用内置的就好 二进制文件的Python读写 重要提示 p.s. 1 >>> bHello World.decode() "Hello World" True >>> example import struct with open(binary_file.bin, wb) as file:data b…

【华为机试】HJ17 坐标移动详解+完整源代码示例

忙碌了一周&#xff0c;一直没时间更新&#xff0c;趁着周末来更新第二个题目。 题目 题目解析 这个题目相比于上一个题目来说&#xff0c;会简单一些&#xff0c;不涉及到那些复杂的算法&#xff0c;就是对于字符串的处理。 算法步骤 输入一个字符串根据分号&#xff0c;将…

uniapp 集成七牛云,上传图片

1 创建项目 我是可视化创建项目的 &#xff0c;cli创建的项目可以直接使用npm安装七牛云。 2 拷贝qiniuUploader.js到项目&#xff0c;下面的回复 放了qiniuUploader.js百度云链接。 3 在需要使用qiniuUploader的vue文件 引入。 4 相册选择照片&#xff0c;或者拍照后&#xff…

Redis-持久化、主从集群、哨兵模式、分片集群、分布式缓存

文章目录 高级篇 - 分布式缓存 Redis集群0、单节点Redis的问题一、Redis持久化1.1 RDB 持久化1.1.1 基本介绍1.1.2 RDB的fork原理1.2.3 总结 1.2 AOF持久化1.3 RDB与AOF对比 二、Redis主从集群2.1 介绍2.2 搭建主从集群2.2.1 准备实例、配置2.2.2 启动2.2.3 开启主从关系2.2.4 …

快速而简单的视频格式转换方法

在数字时代&#xff0c;我们经常需要将视频文件从一种格式转换为另一种格式。无论是因为兼容性问题&#xff0c;还是为了在特定设备上播放视频&#xff0c;视频格式转换是一项非常常见的任务。本文将介绍视频格式转换的基本知识和步骤。 首先&#xff0c;了解不同的视频格式非常…

8.3 非正弦波发生电路

在实用电路中除了常见的正弦波外&#xff0c;还有矩形波、三角波、锯齿波、尖顶波和阶梯波&#xff0c;如图8.3.1所示。 一、矩形波发生电路 矩形波发生电路是其它非正弦波发生电路的基础&#xff0c;例如&#xff0c;若方波电压加在积分运算电路的输入端&#xff0c;则输出就…

数学建模-相关系数

excel基本操作&#xff1a;ctrl右&#xff0c;ctrl左&#xff0c;ctrlshift下/右&#xff0c;ctrlshift空格 题目里有数据&#xff0c;给出描述性统计是比较好的习惯 excel描述性统计&#xff1a;数据-数据分析-描述统计 MATLAB要做散点图C62个 SPSS可以直接画出两两之间的散…

华为OD机试真题 Java 实现【最小循环子数组】【2023 B卷 100分】,附详细解题思路

目录 专栏导读一、题目描述二、输入描述三、输出描述四、备注五、Java算法源码六、效果展示1、输入2、输出 专栏导读 本专栏收录于《华为OD机试&#xff08;JAVA&#xff09;真题&#xff08;A卷B卷&#xff09;》。 刷的越多&#xff0c;抽中的概率越大&#xff0c;每一题都有…

koa初体验———swagger使用

学习完koa框架和mysql&#xff0c;写了一个小demo&#xff0c;选课管理系统&#xff0c;其中包含权限验证&#xff0c;登录注册&#xff0c;用户管理和选课管理。写这个项目目的一方面是为了自己练手&#xff0c;另一方面是为了我们在学习新技术的时候能够有接口供我们使用去测…

Cilium基础架构

Cilium作为一款Kubernetes CNI插件&#xff0c;从一开始就是为大规模和高度动态的容器环境而设计&#xff0c;并且带来了API级别感知的网络安全管理功能&#xff0c;通过使用基于Linux内核特性的新技术——BPF&#xff0c;提供了基于service/pod/container作为标识&#xff0c;…