因为修饰了JDK标准库的类,标准库由bootstrap class loader加载;修饰后的JDK类引用了TTL的代码,所以Java Agent使用方式下TTL Jar文件需要配置到boot class path上。
TTL从v2.6.0开始,加载TTL Agent时会自动设置TTL Jar到boot class path上。 注意:不能修改从Maven库下载的TTL Jar文件名(形如transmittable-thread-local-2.x.y.jar)。
如果修改了,则需要自己手动通过-Xbootclasspath JVM参数来显式配置(就像TTL之前的版本的做法一样)。
自动设置TTL Jar到boot class path的实现是通过指定TTL Java Agent Jar文件里manifest文件(META-INF/MANIFEST.MF)的Boot-Class-Path属性:
Boot-Class-Path
A list of paths to be searched by the bootstrap class loader. Paths represent directories or libraries (commonly referred to as JAR or zip libraries on many platforms).
These paths are searched by the bootstrap class loader after the platform specific mechanisms of locating a class have failed. Paths are searched in the order listed.
foldright/cffu 🦝 Java CompletableFuture Fu, aka. CF-Fu, pronounced “Shifu”; include best practice/traps guide and a tiny sidekick library to improve user experience and reduce misuse.
tuya/connector The connector framework maps cloud APIs to local APIs based on simple configurations and flexible extension mechanisms
中间件/数据处理
apache/shardingsphere Ecosystem to transform any database into a distributed database system, and enhance it with sharding, elastic scaling, encryption features & more
apache/kylin A unified and powerful OLAP platform for Hadoop and Cloud.
ymm-tech/easy-byte-coder Easy-byte-coder is a non-invasive bytecode injection framework based on JVM
业务服务或平台应用
OpenBankProject/OBP-API An open source RESTful API platform for banks that supports Open Banking, XS2A and PSD2 through access to accounts, transactions, counterparties, payments, entitlements and metadata - plus a host of internal banking and management APIs
shulieTech/Takin 全链路压测平台,measure online environmental performance test for full-links, Especially for microservices
shulieTech/LinkAgent a Java-based open-source agent designed to collect data and control Functions for Java applications through JVM bytecode, without modifying applications codes
📖 English Documentation | 📖 中文文档
Runnable和CallableJava Agent来修饰JDK线程池实现类Java Agent的启动参数配置TTL的好处与必要性🔧 功能
👉
TransmittableThreadLocal(TTL):在使用线程池等会池化复用线程的执行组件情况下,提供ThreadLocal值的传递功能,解决异步执行时上下文传递的问题。一个Java标准库本应为框架/中间件设施开发提供的标配能力,本库功能聚焦 & 0依赖,支持Java 6~21。JDK的InheritableThreadLocal类可以完成父线程到子线程的值传递。但对于使用线程池等会池化复用线程的执行组件的情况,线程由线程池创建好,并且线程是池化起来反复使用的;这时父子线程关系的ThreadLocal值传递已经没有意义,应用需要的实际上是把 任务提交给线程池时的ThreadLocal值传递到 任务执行时。本库提供的
TransmittableThreadLocal类继承并加强InheritableThreadLocal类,解决上述的问题,使用详见 User Guide。整个
TransmittableThreadLocal库的核心功能(用户API、线程池ExecutorService/ForkJoinPool/TimerTask及其线程工厂的Wrapper;开发者API、框架/中间件的集成API),只有 **_~1000SLOC代码行_**,非常精小。欢迎 👏
🎨 需求场景
ThreadLocal的需求场景即TransmittableThreadLocal的潜在需求场景,如果你的业务需要『在使用线程池等会池化复用线程的执行组件情况下传递ThreadLocal值』则是TransmittableThreadLocal目标场景。下面是几个典型场景例子。
Request级CacheSDK传递信息各个场景的展开说明参见子文档 需求场景。
👥 User Guide
使用类
TransmittableThreadLocal来保存值,并跨线程池传递。TransmittableThreadLocal继承InheritableThreadLocal,使用方式也类似。相比InheritableThreadLocal,添加了protected的transmitteeValue()方法,用于定制 任务提交给线程池时 的ThreadLocal值传递到 任务执行时 的传递方式,缺省是简单的赋值传递。注意:如果传递的对象(引用类型)会被修改,且没有做深拷贝(如直接传递引用或是浅拷贝),那么
JDK的InheritableThreadLocal.childValue()一样,需要使用者/业务逻辑注意保证传递对象的线程安全。具体使用方式见下面的说明。
1. 简单使用
父线程给子线程传递值。
示例代码:
# 完整可运行的Demo代码参见
SimpleDemo.kt。这其实是
InheritableThreadLocal的功能,应该使用InheritableThreadLocal来完成。但对于使用线程池等会池化复用线程的执行组件的情况,线程由线程池创建好,并且线程是池化起来反复使用的;这时父子线程关系的
ThreadLocal值传递已经没有意义,应用需要的实际上是把 任务提交给线程池时的ThreadLocal值传递到 任务执行时。解决方法参见下面的这几种用法。
2. 保证线程池中传递值
2.1 修饰
Runnable和Callable使用
TtlRunnable和TtlCallable来修饰传入线程池的Runnable和Callable。示例代码:
**注意**:
即使是同一个
Runnable任务多次提交到线程池时,每次提交时都需要通过修饰操作(即TtlRunnable.get(task))以抓取这次提交时的TransmittableThreadLocal上下文的值;即如果同一个任务下一次提交时不执行修饰而仍然使用上一次的TtlRunnable,则提交的任务运行时会是之前修饰操作所抓取的上下文。示例代码如下:上面演示了
Runnable,Callable的处理类似# 完整可运行的Demo代码参见
TtlWrapperDemo.kt。整个过程的完整时序图
2.2 修饰线程池
省去每次
Runnable和Callable传入线程池时的修饰,这个逻辑可以在线程池中完成。通过工具类
TtlExecutors完成,有下面的方法:getTtlExecutor:修饰接口ExecutorgetTtlExecutorService:修饰接口ExecutorServicegetTtlScheduledExecutorService:修饰接口ScheduledExecutorService示例代码:
# 完整可运行的Demo代码参见
TtlExecutorWrapperDemo.kt。2.3 使用
Java Agent来修饰JDK线程池实现类这种方式,实现线程池的传递是透明的,业务代码中没有修饰
Runnable或是线程池的代码。即可以做到应用代码 无侵入。# 关于 无侵入 的更多说明参见文档
Java Agent方式对应用代码无侵入。示例代码:
Demo参见
AgentDemo.kt。执行工程下的脚本scripts/run-agent-demo.sh即可运行Demo。目前
TTL Agent中,修饰了的JDK执行器组件(即如线程池)如下:java.util.concurrent.ThreadPoolExecutor和java.util.concurrent.ScheduledThreadPoolExecutorJdkExecutorTtlTransformlet.java。java.util.concurrent.ForkJoinTask(对应的执行器组件是java.util.concurrent.ForkJoinPool)ForkJoinTtlTransformlet.java。从版本2.5.1开始支持。Java 8引入的CompletableFuture与(并行执行的)Stream底层是通过ForkJoinPool来执行,所以支持ForkJoinPool后,TTL也就透明支持了CompletableFuture与Stream。🎉java.util.TimerTask的子类(对应的执行器组件是java.util.Timer)TimerTaskTtlTransformlet.java。从版本2.7.0开始支持。2.11.2版本开始缺省开启TimerTask的修饰(因为保证正确性是第一位,而不是最佳实践『不推荐使用TimerTask』:);2.11.1版本及其之前的版本没有缺省开启TimerTask的修饰。Agent参数ttl.agent.enable.timer.task开启/关闭TimerTask的修饰:-javaagent:path/to/transmittable-thread-local-2.x.y.jar=ttl.agent.enable.timer.task:true-javaagent:path/to/transmittable-thread-local-2.x.y.jar=ttl.agent.enable.timer.task:falseTTL Agent参数的配置说明详见TtlAgent.java的JavaDoc。Java Agent的启动参数配置在
Java的启动参数加上:-javaagent:path/to/transmittable-thread-local-2.x.y.jar。**注意**:
TTL的Jar的文件名(transmittable-thread-local-2.x.y.jar),则需要自己手动通过-Xbootclasspath JVM参数来显式配置。比如修改文件名成
ttl-foo-name-changed.jar,则还需要加上Java的启动参数:-Xbootclasspath/a:path/to/ttl-foo-name-changed.jar。v2.6.0之前的版本(如v2.5.1),则也需要自己手动通过-Xbootclasspath JVM参数来显式配置(就像TTL之前的版本的做法一样)。加上
Java的启动参数:-Xbootclasspath/a:path/to/transmittable-thread-local-2.5.1.jar。Java命令行示例如下:🔌 Java API Docs
当前版本的Java API文档地址: https://alibaba.github.io/transmittable-thread-local/apidocs/
🍪 Maven依赖
示例:
可以在 maven.org 查看可用的版本。
🔨 关于编译构建
编译构建的环境要求: **_
JDK 8+_**;用Maven常规的方式执行编译构建即可:# 在工程中已经包含了符合版本要求的
Maven,直接运行 **工程根目录下的mvnw**;并不需要先手动自己安装好Maven。❓ FAQ
Q1.
TTL Agent与其它Agent(如Skywalking、Promethues)配合使用时不生效?配置
TTL Agent在最前的位置,可以避免与其它其它Agent配合使用时,TTL Agent可能的不生效问题。配置示例:原因是:
Skywalking这样的Agent的入口逻辑(premain)包含了线程池的启动。Agent配置在前面,到了TTL Agent(的premain)时,TTL需要加强的线程池类已经加载(load)了。TTL Agent的TtlTransformer是在类加载时触发类的增强;如果类已经加载了会跳过TTL Agent的增强逻辑。更多讨论参见 Issue:
TTL agent与其他Agent的兼容性问题 #226。Q2.
MacOS下,使用Java Agent,可能会报JavaLaunchHelper的出错信息JDK Bug: https://bugs.java.com/bugdatabase/view_bug.do?bug_id=8021205
可以换一个版本的
JDK。我的开发机上1.7.0_40有这个问题,1.6.0_51、1.7.0_45可以运行。#
1.7.0_45还是有JavaLaunchHelper的出错信息,但不影响运行。✨ 使用
TTL的好处与必要性好处:透明且自动完成所有异步执行上下文的可定制、规范化的捕捉与传递。
这个好处也是
TransmittableThreadLocal的目标。必要性:随着应用的分布式微服务化并使用各种中间件,越来越多的功能与组件会涉及不同的上下文,逻辑流程也越来越长;上下文问题实际上是个大的易错的架构问题,需要统一的对业务透明的解决方案。
使用
ThreadLocal作为业务上下文传递的经典技术手段在中间件、技术与业务框架中广泛大量使用。而对于生产应用,几乎一定会使用线程池等异步执行组件,以高效支撑线上大流量。但使用ThreadLocal及其set/remove的上下文传递模式,在使用线程池等异步执行组件时,存在多方面的问题:1. 从业务使用者角度来看
ThreadLocal上下文各自的获取的逻辑或类。RPC的上下文(如Dubbo的RpcContext)、全链路跟踪的上下文(如SkyWalking的ContextManager)、不同业务模块中的业务流程上下文,等等。2. 从整体流程实现角度来看
关注的是 上下文传递流程的规范化。上下文传递到了子线程要做好 清理(或更准确地说是要 恢复 成之前的上下文),需要业务逻辑去处理好。如果业务逻辑对清理的处理不正确,比如:
上面的问题,在业务开发中引发的
Bug真是屡见不鲜 !本质原因是:**_ThreadLocal的set/remove的上下文传递模式_** 在使用线程池等异步执行组件的情况下不再是有效的。常见的典型例子:RejectedExecutionHandler使用的是CallerRunsPolicy时,提交到线程池的任务会在提交线程中直接执行,ThreadLocal.remove操作清理提交线程的上下文导致上下文丢失。ForkJoinPool(包含并行执行Stream与CompletableFuture,底层使用ForkJoinPool)的场景,展开的ForkJoinTask会在任务提交线程中直接执行。同样导致上下文丢失。怎么设计一个『上下文传递流程』方案(即上下文的生命周期),以保证没有上面的问题?
期望:上下文生命周期的操作从业务逻辑中分离出来。业务逻辑不涉及生命周期,就不会有业务代码如疏忽清理而引发的问题了。整个上下文的传递流程或说生命周期可以规范化成:捕捉、回放和恢复这3个操作,即
CRR(capture/replay/restore)模式。更多讨论参见 Issue:能在详细讲解一下replay、restore的设计理念吗?#201。总结上面的说明:在生产应用(几乎一定会使用线程池等异步执行组件)中,使用
ThreadLocal及其set/remove的上下文传递模式几乎一定是有问题的,**只是在等一个出Bug的机会**。更多
TTL好处与必要性的展开讨论参见 Issue:这个库带来怎样的好处和优势? #128,欢迎继续讨论 ♥️🗿 更多文档
TTL使用场景 与 设计实现解析的文章(写得都很好!) - Issue #123📚 相关资料
JDK Core Classes
💗 Who Used
使用了
TTL的一部分开源项目:sofastack/sofa-rpcSOFARPC is a high-performance, high-extensibility, production-level Java RPC framework
trpc-group/trpc-javaA pluggable, high-performance RPC framework written in java
tencentmusic/supersonicSuperSonic is an out-of-the-box yet highly extensible framework for building ChatBI
dromara/hmilyDistributed transaction solutions
dromara/gobrs-async一款功能强大、配置灵活、带有全链路异常回调、内存优化、异常状态管理于一身的高性能异步编排框架。为企业提供在复杂应用场景下动态任务编排的能力。 针对于复杂场景下,异步线程复杂性、任务依赖性、异常状态难控制性
dromara/dynamic-tp轻量级动态线程池,内置监控告警功能,支持线程池上下文传递,基于主流配置中心(已支持Nacos、Apollo,Zookeeper,可通过SPI自定义实现)
opengoofy/hippo4j动态线程池框架,附带监控报警功能,支持 JDK、Tomcat、Jetty、Undertow 线程池;Apache RocketMQ、Dubbo、RabbitMQ、Hystrix 消费等线程池。内置两种使用模式:轻量级依赖配置中心以及无中间件依赖版本
siaorg/sia-gateway微服务路由网关(zuul-plus)
huaweicloud/SermantSermant, a proxyless service mesh solution based on Javaagent
ZTO-Express/zmsZTO Message Service
lxchinesszz/tomato一款专门为SpringBoot项目设计的幂等组件
ytyht226/taskflow一款轻量、简单易用、可灵活扩展的通用任务编排框架,基于有向无环图(DAG)的方式实现,框架提供了组件复用、同步/异步编排、条件判断、分支选择等能力,可以根据不同的业务场景对任意的业务流程进行编排
foldright/cffu🦝 Java CompletableFuture Fu, aka. CF-Fu, pronounced “Shifu”; include best practice/traps guide and a tiny sidekick library to improve user experience and reduce misuse.
tuya/connectorThe connector framework maps cloud APIs to local APIs based on simple configurations and flexible extension mechanisms
apache/shardingsphereEcosystem to transform any database into a distributed database system, and enhance it with sharding, elastic scaling, encryption features & more
apache/kylinA unified and powerful OLAP platform for Hadoop and Cloud.
mybatis-flex/mybatis-flexmybatis-flex is an elegant Mybatis Enhancement Framework
basicai/xtreme1The Next GEN Platform for Multisensory Training Data. #3D annotation, lidar-camera annotation and image annotation tools are supported
oceanbase/odcAn open-source, enterprise-grade database tool for collaborative development
sagframe/sagacity-sqltoyJava真正智慧的ORM框架
dromara/stream-query允许完全摆脱Mapper的mybatis-plus体验;可以使用类似“工具类”这样的静态函数进行数据库操作
luo-zhan/TransformerTransformer可能是最简单,但最强大的字段转换插件,一个注解搞定任意转换,让开发变得更加丝滑
SimonAlong/NeoOrm框架:基于ActiveRecord思想开发的至简化且功能很全的Orm框架
ppdaicorp/das数据库访问框架(data access service),包括数据库控制台das console,数据库客户端das client和数据库服务端das server三部分
didi/ALITAa layer-based data analysis tool
didi/daedalus实现快速创建数据构造流程,数据构造流程的可视化、线上化、持久化、标准化
dromara/liteflowa lightweight and practical micro-process framework
alibaba/bulbasaurA pluggable, scalable process engine
dromara/TLogLightweight distributed log label tracking framework
fayechenlong/plumelog一个java分布式日志组件,支持百亿级别
minbox-projects/minbox-logging分布式零侵入式、链路式请求日志分析框架。提供Admin端点进行采集日志、分析日志、日志告警通知、服务性能分析等。通过Admin Ui可查看实时链路日志信息、在线业务服务列表
minbox-projects/api-boot为接口服务而生的,基于“ SpringBoot”完成扩展和自动配置,内部封装了一系列的开箱即用Starters
ofpay/logback-mdc-ttllogback扩展,集成transmittable-thread-local支持跨线程池的mdc跟踪
oldratlee/log4j2-ttl-thread-context-mapLog4j2 TTL ThreadContextMap, Log4j2 extension integrated TransmittableThreadLocal to MDC
qqxx6661/log-recordymm-tech/easy-byte-coderEasy-byte-coder is a non-invasive bytecode injection framework based on JVM
OpenBankProject/OBP-APIAn open source RESTful API platform for banks that supports Open Banking, XS2A and PSD2 through access to accounts, transactions, counterparties, payments, entitlements and metadata - plus a host of internal banking and management APIs
gz-yami/mall4j电商商城 java电商商城系统 uniapp商城 多用户商城
Joolun/JooLun-wxJooLun微信商城
HummerRisk/HummerRisk云原生安全平台,包括混合云安全治理和容器云安全检测
XiaoMi/moneMone以微服务为核心的一站式企业协同研发平台。支持公共云、专有云和混合云多种部署形态;提供从“项目创建->开发->部署->治理->应用观测”端到端的研发全流程服务;通过云原生新技术和研发新模式,打造“双敏”,敏捷研发和敏捷组织,保障小米-中国区高复杂业务、大规模团队的敏捷研发协同,实现多倍效能提升。yangzongzhuan/RuoYi-Cloud基于Spring Boot、Spring Cloud & Alibaba的分布式微服务架构权限管理系统
somowhere/albedo基于 Spring Boot 、Spring Security、Mybatis 的RBAC权限管理系统
qwdigital/LinkWechat基于企业微信的开源 SCRM 系统,采用主流的 Java 微服务架构,是企业私域流量管理与营销的综合解决方案,助力企业提高客户运营效率,强化营销能力,拓展盈利空间
fushengqian/fuintfuint会员营销系统是一套开源的实体店铺会员管理和营销系统
hiparker/opsli-boot一款的低代码快速平台,零代码开发,致力于做更简洁的后台管理系统
topiam/eiamEIAM(Employee Identity and Access Management Program)企业级开源IAM平台,实现用户全生命周期的管理、统一认证和单点登录、为数字身份安全赋能
Newspiral/newspiral-business联盟区块链底层平台
ssssssss-team/spider-flow新一代爬虫平台,以图形化方式定义爬虫流程,不写代码即可完成爬虫
nekolr/slime🍰 一个可视化的爬虫平台
Jackson0714/PassJava-Platform一款面试刷题的 Spring Cloud 开源系统。零碎时间利用小程序查看常见面试题,夯实Java基础。 该项目可以教会你如何搭建SpringBoot项目,Spring Cloud项目。 采用流行的技术,如 SpringBoot、MyBatis、Redis、 MySql、 MongoDB、 RabbitMQ、Elasticsearch,采用Docker容器化部署
martin-chips/DimpleBlog基于
SpringBoot2搭建的个人博客系统zjcscut/octopus长链接压缩为短链接的服务
xggz/mqr茉莉QQ机器人(简称MQR),采用mirai的Android协议实现的QQ机器人服务,通过web控制机器人的启停和配置
alibaba/jvm-sandbox-repeaterA Java server-side recording and playback solution based on JVM-Sandbox, 录制/回放通用解决方案
vivo/MoonBoxMoonbox(月光宝盒)是JVM-Sandbox生态下的,基于jvm-sandbox-repeater重新开发的,一款流量回放平台产品。相较于jvm-sandbox-repeater,Moonbox功能更加丰富、数据可靠性更高,同时便于快速线上部署和使用
alibaba/testable-mock换种思路写Mock,让单元测试更简单
shulieTech/Takin全链路压测平台,measure online environmental performance test for full-links, Especially for microservices
shulieTech/LinkAgenta Java-based open-source agent designed to collect data and control Functions for Java applications through JVM bytecode, without modifying applications codes
alibaba/virtual-environmentRoute isolation with service sharing, 阿里测试环境服务隔离和联调机制的
Kubernetes版实现Spring Cloud/Spring Boot的框架方案/脚手架YunaiV/ruoyi-vue-pro一套全部开源的企业级的快速开发平台。基于 Spring Boot + MyBatis Plus + Vue & Element 实现的后台管理系统 + 微信小程序,支持 RBAC 动态权限、数据权限、SaaS 多租户、Activiti + Flowable 工作流、三方登录、支付、短信、商城等功能
YunaiV/yudao-cloudRuoYi-Vue 全新 Cloud 版本,优化重构所有功能。基于 Spring Cloud Alibaba + MyBatis Plus + Vue & Element 实现的后台管理系统 + 用户小程序,支持 RBAC 动态权限、多租户、数据权限、工作流、三方登录、支付、短信、商城等功能
zlt2000/microservices-platform基于SpringBoot2.x、SpringCloud和SpringCloudAlibaba并采用前后端分离的企业级微服务多租户系统架构
dromara/lamp-cloud基于Jdk11 + SpringCloud + SpringBoot 的微服务快速开发平台,其中的可配置的SaaS功能尤其闪耀, 具备RBAC功能、网关统一鉴权、Xss防跨站攻击、自动代码生成、多种存储系统、分布式事务、分布式定时任务等多个模块,支持多业务系统并行开发, 支持多服务并行开发,可以作为后端服务的开发脚手架
zuihou/lamp-util打造一套兼顾 SpringBoot 和 SpringCloud 项目的公共工具类
matevip/matecloud一款基于Spring Cloud Alibaba的微服务架构
gavenwangcn/voleSpringCloud 微服务业务脚手架
liuweijw/fw-cloud-framework基于springcloud全家桶开发分布式框架(支持oauth2认证授权、SSO登录、统一下单、微信公众号服务、Shardingdbc分库分表、常见服务监控、链路监控、异步日志、redis缓存等功能),实现基于Vue全家桶等前后端分离项目工程
liuht777/Taroco整合Nacos、Spring Cloud Alibaba,提供了一系列starter组件, 同时提供服务治理、服务监控、OAuth2权限认证,支持服务降级/熔断、服务权重
mingyang66/spring-parent数据库多数据源、Redis多数据源、日志组件、全链路日志追踪、埋点扩展点、Netty、微服务、开发基础框架支持、异常统一处理、返回值、跨域、API路由、监控等
budwk/budwkBudWk原名NutzWkyinjihuan/spring-cloud《Spring Cloud微服务-全栈技术与案例解析》和《Spring Cloud微服务 入门 实战与进阶》配套源码
louyanfeng25/ddd-demo《深入浅出DDD》讲解的演示项目,为了能够更好的理解Demo中的分层与逻辑处理,我强烈建议你配合小册来深入了解DDD
nageoffer/1230612306 铁路购票服务是与大家生活和出行相关的关键系统,包括会员、购票、订单、支付和网关等服务。
更多使用
TTL的开源项目 参见👷 Contributors