🔧 功能🎨 需求场景👥 User Guide🔌 Java API Docs� Maven�赖🔨 关于编译构建与IDE开�� FAQ✨ 使用TTL的好处与必�性🗿 更多文档📚 相关资料� Who used👷 Contributors
🔧 功能
TransmittableThreadLocal(TTL)ï¼šåœ¨ä½¿ç”¨çº¿ç¨‹æ± ç‰ä¼šæ± 化å¤?用线程的执行组件情况下,æ??ä¾›ThreadLocalå€¼çš„ä¼ é€’åŠŸèƒ½ï¼Œè§£å†³å¼‚æ¥æ‰§è¡Œæ—¶ä¸Šä¸‹æ–‡ä¼ 递的问题。一个Javaæ ‡å‡†åº“æœ¬åº”ä¸ºæ¡†æž¶/ä¸é—´ä»¶è®¾æ–½å¼€å?‘æ??ä¾›çš„æ ‡é…?能力,本库功能è?šç„¦ & 0ä¾?赖,支æŒ?Java 17/16/15/14/13/12/11/10/9/8/7/6。
JDKçš„InheritableThreadLocalç±»å?¯ä»¥å®Œæˆ?父线程到å?çº¿ç¨‹çš„å€¼ä¼ é€’ã€‚ä½†å¯¹äºŽä½¿ç”¨çº¿ç¨‹æ± ç‰ä¼šæ± 化å¤?ç”¨çº¿ç¨‹çš„æ‰§è¡Œç»„ä»¶çš„æƒ…å†µï¼Œçº¿ç¨‹ç”±çº¿ç¨‹æ± åˆ›å»ºå¥½ï¼Œå¹¶ä¸”çº¿ç¨‹æ˜¯æ± åŒ–èµ·æ?¥å??å¤?使用的;这时父å?线程关系的ThreadLocalå€¼ä¼ é€’å·²ç»?没有æ„?义,应用需è¦?的实际上是把 任务æ??äº¤ç»™çº¿ç¨‹æ± æ—¶çš„ThreadLocalå€¼ä¼ é€’åˆ° 任务执行时。
本库æ??供的TransmittableThreadLocalç±»ç»§æ‰¿å¹¶åŠ å¼ºInheritableThreadLocal类,解决上述的问题,使用详è§? User Guide。
整个TransmittableThreadLocalåº“çš„æ ¸å¿ƒåŠŸèƒ½ï¼ˆç”¨æˆ·API与框架/ä¸é—´ä»¶çš„集æˆ?APIã€?çº¿ç¨‹æ± ExecutorService/ForkJoinPool/TimerTaskå?Šå…¶çº¿ç¨‹å·¥åŽ‚çš„Wrapper),å?ªæœ‰ ~1000 SLOC代ç ?行,é?žå¸¸ç²¾å°?。
欢迎
- 建议和æ??问,æ??交 Issue
- 贡献和改进,Fork å?Žæ??通过 Pull Request 贡献代ç ?
🎨 需求场景
ThreadLocal的需求场景å?³TransmittableThreadLocalçš„æ½œåœ¨éœ€æ±‚åœºæ™¯ï¼Œå¦‚æžœä½ çš„ä¸šåŠ¡éœ€è¦?ã€Žåœ¨ä½¿ç”¨çº¿ç¨‹æ± ç‰ä¼šæ± 化å¤?ç”¨çº¿ç¨‹çš„æ‰§è¡Œç»„ä»¶æƒ…å†µä¸‹ä¼ é€’ThreadLocal值ã€?则是TransmittableThreadLocalç›®æ ‡åœºæ™¯ã€‚
下é?¢æ˜¯å‡ 个典型场景例å?。
- 分布å¼?跟踪系统 或 全链路压测(å?³é“¾è·¯æ‰“æ ‡ï¼‰
- 日志收集记录系统上下文
Session级Cache- 应用容器或上层框架跨应用代ç ?给下层
SDKä¼ é€’ä¿¡æ?¯
å?„个场景的展开说明å?‚è§?å?文档 需求场景。
👥 User Guide
使用类TransmittableThreadLocalæ?¥ä¿?å˜å€¼ï¼Œå¹¶è·¨çº¿ç¨‹æ± ä¼ é€’ã€‚
TransmittableThreadLocal继承InheritableThreadLocal,使用方å¼?也类似。相比InheritableThreadLocalï¼Œæ·»åŠ äº†
copy方法
用于定制 任务æ??äº¤ç»™çº¿ç¨‹æ± æ—¶ çš„ThreadLocalå€¼ä¼ é€’åˆ° 任务执行时 的拷è´?行为,缺çœ?是简å?•çš„èµ‹å€¼ä¼ é€’ã€‚- 注æ„?ï¼šå¦‚æžœä¼ é€’çš„æ˜¯ä¸€ä¸ªå¯¹è±¡ï¼ˆå¼•ç”¨ç±»åž‹ï¼‰ä¸”æ²¡æœ‰å?šæ·±æ‹·è´?ï¼Œå¦‚ç›´æŽ¥ä¼ é€’å¼•ç”¨æˆ–æ˜¯æµ…æ‹·è´?,那么
- è·¨çº¿ç¨‹ä¼ é€’è€Œä¸?å†?有线程å°?é—ï¼Œä¼ é€’å¯¹è±¡åœ¨å¤šä¸ªçº¿ç¨‹ä¹‹é—´æ˜¯æœ‰å…±äº«çš„ï¼›
- 与
InheritableThreadLocal.childValueä¸€æ ·ï¼Œä½¿ç”¨è€…/业务逻辑è¦?注æ„?ä¼ é€’å¯¹è±¡çš„çº¿ç¨‹å®‰å…¨ã€‚
- 注æ„?ï¼šå¦‚æžœä¼ é€’çš„æ˜¯ä¸€ä¸ªå¯¹è±¡ï¼ˆå¼•ç”¨ç±»åž‹ï¼‰ä¸”æ²¡æœ‰å?šæ·±æ‹·è´?ï¼Œå¦‚ç›´æŽ¥ä¼ é€’å¼•ç”¨æˆ–æ˜¯æµ…æ‹·è´?,那么
protected的beforeExecute/afterExecute方法
执行任务(Runnable/Callable)的�/�的生命周期回调,缺�是空�作。
关于
copy方法 的 展开说明
ä¸¥è°¨åœ°è¯´ï¼Œåº”è¯¥æ˜¯ã€Žä¼ é€’è¡Œä¸ºã€?,而ä¸?是『拷è´?行为ã€?;相应的,这个方法应该命å??æˆ?
transmiteeValue,与InheritableThreadLocal.childValue方法有一致的命å??é£Žæ ¼ã€‚ä½†å¤šæ•°æƒ…å†µä¸‹ï¼Œä¼ é€’çš„æ˜¯ä¸€ä¸ªå¤?æ?‚çš„å¯¹è±¡ï¼Œä¹ æƒ¯ä¸Šä¼šå…ˆæƒ³åˆ°çš„æ˜¯å¦‚ä½•å?šæ‹·è´?,如深拷è´?ã€?æµ…æ‹·è´?;命å??æˆ?
copyå??而更容易ç?†è§£è¿™ä¸ªè¿‡ç¨‹ä¸Žè¡Œä¸ºäº†ã€‚😂 关于构è¯?å?Žç¼€
er与ee的说明:
transmit是动è¯?ä¼ é€’ï¼Œtransmitter动作的执行者/主动方,而transmitee动作的接收者/被动方。er与eeå?Žç¼€çš„常è§?è¯?是employer(雇主)/employee(雇员)ã€?caller(调用者)/callee(被调用者)。
具体使用方��下�的说明。
1. 简�使用
父线程给å?çº¿ç¨‹ä¼ é€’å€¼ã€‚
示例代ç ?:
TransmittableThreadLocal<String> context = new TransmittableThreadLocal<>();
// =====================================================
// 在父线程ä¸è®¾ç½®
context.set("value-set-in-parent");
// =====================================================
// 在å?线程ä¸å?¯ä»¥è¯»å?–,值是"value-set-in-parent"
String value = context.get();# 完整å?¯è¿?行的Demo代ç ?å?‚è§?SimpleDemo.kt。
这其实是InheritableThreadLocal的功能,应该使用InheritableThreadLocal�完�。
ä½†å¯¹äºŽä½¿ç”¨çº¿ç¨‹æ± ç‰ä¼šæ± 化å¤?ç”¨çº¿ç¨‹çš„æ‰§è¡Œç»„ä»¶çš„æƒ…å†µï¼Œçº¿ç¨‹ç”±çº¿ç¨‹æ± åˆ›å»ºå¥½ï¼Œå¹¶ä¸”çº¿ç¨‹æ˜¯æ± åŒ–èµ·æ?¥å??å¤?使用的;这时父å?线程关系的ThreadLocalå€¼ä¼ é€’å·²ç»?没有æ„?义,应用需è¦?的实际上是把 任务æ??äº¤ç»™çº¿ç¨‹æ± æ—¶çš„ThreadLocalå€¼ä¼ é€’åˆ° 任务执行时。
解决方法å?‚è§?下é?¢çš„è¿™å‡ ç§?用法。
2. ä¿?è¯?çº¿ç¨‹æ± ä¸ä¼ 递值
2.1 修饰Runnable和Callable
使用TtlRunnableå’ŒTtlCallableæ?¥ä¿®é¥°ä¼ å…¥çº¿ç¨‹æ± çš„Runnableå’ŒCallable。
示例代ç ?:
TransmittableThreadLocal<String> context = new TransmittableThreadLocal<>();
// =====================================================
// 在父线程ä¸è®¾ç½®
context.set("value-set-in-parent");
Runnable task = new RunnableTask();
// �外的处�,生�修饰了的对象ttlRunnable
Runnable ttlRunnable = TtlRunnable.get(task);
executorService.submit(ttlRunnable);
// =====================================================
// Taskä¸å?¯ä»¥è¯»å?–,值是"value-set-in-parent"
String value = context.get();注�:
å?³ä½¿æ˜¯å?Œä¸€ä¸ªRunnable任务多次æ??äº¤åˆ°çº¿ç¨‹æ± æ—¶ï¼Œæ¯?次æ??交时都需è¦?通过修饰æ“?作(å?³TtlRunnable.get(task))以抓å?–这次æ??交时的TransmittableThreadLocal上下文的值;å?³å¦‚æžœå?Œä¸€ä¸ªä»»åŠ¡ä¸‹ä¸€æ¬¡æ??交时ä¸?执行修饰而ä»?然使用上一次的TtlRunnable,则æ??交的任务è¿?行时会是之å‰?修饰æ“?作所抓å?–的上下文。示例代ç ?如下:
// 第一次æ??交
Runnable task = new RunnableTask();
executorService.submit(TtlRunnable.get(task));
// ...业务逻辑代ç ?,
// 并且修改了 TransmittableThreadLocal上下文 ...
// context.set("value-modified-in-parent");
// å†?次æ??交
// é‡?æ–°æ‰§è¡Œä¿®é¥°ï¼Œä»¥ä¼ é€’ä¿®æ”¹äº†çš„ TransmittableThreadLocal上下文
executorService.submit(TtlRunnable.get(task));上�演示了Runnable,Callable的处�类似
TransmittableThreadLocal<String> context = new TransmittableThreadLocal<>();
// =====================================================
// 在父线程ä¸è®¾ç½®
context.set("value-set-in-parent");
Callable call = new CallableTask();
// �外的处�,生�修饰了的对象ttlCallable
Callable ttlCallable = TtlCallable.get(call);
executorService.submit(ttlCallable);
// =====================================================
// Callä¸å?¯ä»¥è¯»å?–,值是"value-set-in-parent"
String value = context.get();# 完整å?¯è¿?行的Demo代ç ?å?‚è§?TtlWrapperDemo.kt。
整个过程的完整时�图
2.2 修饰线程æ±
çœ?去æ¯?次Runnableå’ŒCallableä¼ å…¥çº¿ç¨‹æ± æ—¶çš„ä¿®é¥°ï¼Œè¿™ä¸ªé€»è¾‘å?¯ä»¥åœ¨çº¿ç¨‹æ± ä¸å®Œæˆ?。
通过工具类com.alibaba.ttl.threadpool.TtlExecutors完�,有下�的方法:
getTtlExecutor:修饰接�ExecutorgetTtlExecutorService:修饰接�ExecutorServicegetTtlScheduledExecutorService:修饰接�ScheduledExecutorService
示例代ç ?:
ExecutorService executorService = ...
// �外的处�,生�修饰了的对象executorService
executorService = TtlExecutors.getTtlExecutorService(executorService);
TransmittableThreadLocal<String> context = new TransmittableThreadLocal<>();
// =====================================================
// 在父线程ä¸è®¾ç½®
context.set("value-set-in-parent");
Runnable task = new RunnableTask();
Callable call = new CallableTask();
executorService.submit(task);
executorService.submit(call);
// =====================================================
// Task或是Callä¸å?¯ä»¥è¯»å?–,值是"value-set-in-parent"
String value = context.get();# 完整å?¯è¿?行的Demo代ç ?å?‚è§?TtlExecutorWrapperDemo.kt。
2.3 使用Java Agentæ?¥ä¿®é¥°JDKçº¿ç¨‹æ± å®žçŽ°ç±»
è¿™ç§?æ–¹å¼?ï¼Œå®žçŽ°çº¿ç¨‹æ± çš„ä¼ é€’æ˜¯é€?明的,业务代ç ?䏿²¡æœ‰ä¿®é¥°Runnableæˆ–æ˜¯çº¿ç¨‹æ± çš„ä»£ç ?。å?³å?¯ä»¥å?šåˆ°åº”用代ç ? æ— ä¾µå…¥ã€‚
# 关于 æ— ä¾µå…¥ 的更多说明å?‚è§?文档Java Agentæ–¹å¼?对应用代ç ?æ— ä¾µå…¥ã€‚
示例代ç ?:
// ## 1. 框架上层逻辑,å?Žç»æµ?程框架调用业务 ##
TransmittableThreadLocal<String> context = new TransmittableThreadLocal<>();
context.set("value-set-in-parent");
// ## 2. 应用逻辑,å?Žç»æµ?程业务调用框架下层逻辑 ##
ExecutorService executorService = Executors.newFixedThreadPool(3);
Runnable task = new RunnableTask();
Callable call = new CallableTask();
executorService.submit(task);
executorService.submit(call);
// ## 3. 框架下层逻辑 ##
// Task或是Callä¸å?¯ä»¥è¯»å?–,值是"value-set-in-parent"
String value = context.get();Demo��AgentDemo.kt。执行工程下的脚本scripts/run-agent-demo.sh���行Demo。
ç›®å‰?TTL Agentä¸ï¼Œä¿®é¥°äº†çš„JDK执行器组件(å?³å¦‚çº¿ç¨‹æ± ï¼‰å¦‚ä¸‹ï¼š
java.util.concurrent.ThreadPoolExecutorå’Œjava.util.concurrent.ScheduledThreadPoolExecutor- 修饰实现代ç ?在
JdkExecutorTtlTransformlet.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:false
- 更多关于
TTL Agent�数的�置说明详�TtlAgent.java的JavaDoc。
- 修饰实现代ç ?在
关于
java.util.TimerTask/java.util.Timer的 展开说明
Timer是JDK 1.3çš„è€?类,ä¸?推è??使用Timer类。推è??用
ScheduledExecutorService。
ScheduledThreadPoolExecutor实现更强壮,并且功能更丰富。 如支æŒ?é…?ç½®çº¿ç¨‹æ± çš„å¤§å°?(Timerå?ªæœ‰ä¸€ä¸ªçº¿ç¨‹ï¼‰ï¼›Timer在Runnableä¸æŠ›å‡ºå¼‚å¸¸ä¼šä¸æ¢å®šæ—¶æ‰§è¡Œã€‚更多说明å?‚è§? 10. Mandatory Run multiple TimeTask by using ScheduledExecutorService rather than Timer because Timer will kill all running threads in case of failing to catch exceptions. - Alibaba Java Coding Guidelines。
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 -javaagent:path/to/transmittable-thread-local-2.x.y.jar \
-cp classes \
com.alibaba.demo.ttl.agent.AgentDemo
# 如果修改了TTL jar文件å?? 或 TTL版本是 2.6.0 之å‰?
# 则还需�显�设置 -Xbootclasspath �数
java -javaagent:path/to/ttl-foo-name-changed.jar \
-Xbootclasspath/a:path/to/ttl-foo-name-changed.jar \
-cp classes \
com.alibaba.demo.ttl.agent.AgentDemo
java -javaagent:path/to/transmittable-thread-local-2.5.1.jar \
-Xbootclasspath/a:path/to/transmittable-thread-local-2.5.1.jar \
-cp classes \
com.alibaba.demo.ttl.agent.AgentDemo关于
boot class path的 展开说明
å› ä¸ºä¿®é¥°äº†
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-PathA 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.
更多详�
🔌 Java API Docs
当�版本的Java API文档地�: https://alibaba.github.io/transmittable-thread-local/apidocs/
� Maven�赖
示例:
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>transmittable-thread-local</artifactId>
<version>2.12.6</version>
</dependency>�以在 search.maven.org 查看�用的版本。
🔨 关于编译构建与IDE开�
编译构建的环境�求: JDK 8~11;用Maven常规的方�执行编译构建��:
# 在工程ä¸å·²ç»?包å?«äº†ç¬¦å?ˆç‰ˆæœ¬è¦?求的Maven,直接è¿?行 å·¥ç¨‹æ ¹ç›®å½•ä¸‹çš„mvnw;并ä¸?需è¦?先手动自己安装好Maven。
# �行测试Case
./mvnw test
# 编译打包
./mvnw package
# �行测试Case�编译打包�安装TTL库到Maven本地
./mvnw install
#####################################################
# å¦‚æžœä½¿ç”¨ä½ è‡ªå·±å®‰è£…çš„ maven,版本è¦?求:maven 3.3.9+
mvn install如何用IDE�开�时注�点,更多说明�� 文档 如何用IDE开� - Developer Guide。
â?“ FAQ
Q1. TTL Agent与其它Agent(如Skywalking�Promethues)��使用时�生效?
�置TTL Agent在最�的�置,�以��与其它其它Agent��使用时,TTL Agent�能的�生效问题。�置示例:
java -javaagent:path/to/transmittable-thread-local-2.x.y.jar \
-javaagent:path/to/skywalking-agent.jar \
-jar your-app.jaråŽŸå› æ˜¯ï¼š
- �
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的好处与必�性
注:ä¸?读这一节,并ä¸?会影å“?ä½ ä½¿ç”¨
TTLæ?¥è§£å†³ä½ 碰到的问题,å?¯ä»¥æ”¾å¿ƒè·³è¿‡ï¼›è¯»äº† User Guide å°±å?¯ä»¥å¿«é€Ÿç”¨èµ·æ?¥äº†ï½žðŸ˜„ 这一节信æ?¯å¯†åº¦è¾ƒé«˜ä¸?易读。
好处:é€?明且自动完æˆ?æ‰€æœ‰å¼‚æ¥æ‰§è¡Œä¸Šä¸‹æ–‡çš„å?¯å®šåˆ¶ã€?规范化的æ?•æ?‰ä¸Žä¼ 递。
这个好处也是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🎓 Developer Guide☔ 性能测试
📚 相关资料
JDK Core Classes
� Who used
使用了TTL的一部分开�项目:
- ä¸é—´ä»¶
sofastack/sofa-rpc
SOFARPC is a high-performance, high-extensibility, production-level Java RPC frameworkdromara/hmily
Distributed transaction solutionsacmenlt/dynamic-threadpool
强大的动æ€?çº¿ç¨‹æ± ï¼Œé™„å¸¦ç›‘æŽ§æŠ¥è¦åŠŸèƒ½ï¼ˆæ²¡æœ‰ä¾?èµ–ä¸é—´ä»¶ï¼‰ï¼Œå®Œå…¨é?µå¾ªé˜¿é‡Œå·´å·´ç¼–ç ?规范lyh200/dynamic-tp
è½»é‡?级动æ€?çº¿ç¨‹æ± ï¼Œå†…ç½®ç›‘æŽ§å‘Šè¦åŠŸèƒ½ï¼Œæ”¯æŒ?çº¿ç¨‹æ± ä¸Šä¸‹æ–‡ä¼ é€’ï¼ŒåŸºäºŽä¸»æµ?é…?ç½®ä¸å¿ƒï¼ˆå·²æ”¯æŒ?Nacosã€?Apollo,Zookeeper,å?¯é€šè¿‡SPI自定义实现)siaorg/sia-gateway
微�务路由网关(zuul-plus)ZTO-Express/zms
ZTO Message Servicetuya/connector
The connector framework maps cloud APIs to local APIs based on simple configurations and flexible extension mechanisms.
- ä¸é—´ä»¶/æ•°æ?®
ppdaicorp/das
数�库访问框架(data access service),包括数�库控制�das console,数�库客户端das client和数�库�务端das server三部分SimonAlong/Neo
Orm框架:基于ActiveRecord�想开�的至简化且功能很全的Orm框架didi/ALITA
a layer-based data analysis tooldidi/daedalus
实现快速创建数æ?®æž„é€ æµ?程,数æ?®æž„é€ æµ?程的å?¯è§†åŒ–ã€?线上化ã€?æŒ?久化ã€?æ ‡å‡†åŒ–aiwenmo/DataLink
a new open source solution to bring Flink development to data center
- ä¸é—´ä»¶/æµ?程引擎
dromara/liteflow
a lightweight and practical micro-process frameworkalibaba/bulbasaur
A pluggable, scalable process engine
- ä¸é—´ä»¶/日志
dromara/TLog
Lightweight distributed log label tracking frameworkfayechenlong/plumelog
一个java分布�日志组件,支�百亿级别minbox-projects/minbox-logging
分布å¼?零侵入å¼?ã€?链路å¼?请求日志分æž?框架。æ??ä¾›Admin端点进行采集日志ã€?分æž?日志ã€?日志告è¦é€šçŸ¥ã€?æœ?务性能分æž?ç‰ã€‚通过Admin Uiå?¯æŸ¥çœ‹å®žæ—¶é“¾è·¯æ—¥å¿—ä¿¡æ?¯ã€?在线业务æœ?务列表minbox-projects/api-boot
为接��务而生的,基于“ SpringBoot�完�扩展和自动�置,内部�装了一系列的开箱�用Starters
ofpay/logback-mdc-ttl
logback扩展,集æˆ?transmittable-thread-local支æŒ?è·¨çº¿ç¨‹æ± çš„mdc跟踪oldratlee/log4j2-ttl-thread-context-map
Log4j2 TTL ThreadContextMap, Log4j2 extension integrated TransmittableThreadLocal to MDC
- ä¸é—´ä»¶/å—节ç ?
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 APIsJoolun/JooLun-wx
JooLun微信商城yangzongzhuan/RuoYi-Cloud
基于Spring Boot�Spring Cloud & Alibaba的分布�微�务架构��管�系统somowhere/albedo
基于 Spring Boot �Spring Security�Mybatis 的RBAC��管�系统tengshe789/SpringCloud-miaosha
一个基于spring cloud Greenwich的简å?•ç§’æ?€ç”µå?商城项目
- 工具产�
ssssssss-team/spider-flow
新一代爬虫平å?°ï¼Œä»¥å›¾å½¢åŒ–æ–¹å¼?定义爬虫æµ?程,ä¸?写代ç ?å?³å?¯å®Œæˆ?爬虫nekolr/slime
� 一个�视化的爬虫平�zjcscut/octopus
长链接压缩为çŸé“¾æŽ¥çš„æœ?务xggz/mqr
茉莉QQ机器人(简称MQR),采用miraiçš„Androidå??议实现的QQ机器人æœ?务,通过web控制机器人的å?¯å?œå’Œé…?ç½®
- 测试解决方案或工具
alibaba/jvm-sandbox-repeater
A Java server-side recording and playback solution based on JVM-Sandbox, 录制/回放通用解决方案alibaba/testable-mock
���路写Mock,让�元测试更简�shulieTech/Takin
全链路压测平�,measure online environmental performance test for full-links, Especially for microservicesshulieTech/LinkAgent
a Java-based open-source agent designed to collect data and control Functions for Java applications through JVM bytecode, without modifying applications codes
alibaba/virtual-environment
Route isolation with service sharing, 阿里测试环境�务隔离和�调机制的Kubernetes版实现
Spring Cloud/Spring Boot的框架方案/脚手架zlt2000/microservices-platform
基于SpringBoot2.x�SpringCloud和SpringCloudAlibaba并采用��端分离的�业级微�务多租户系统架构zuihou/lamp-cloud
基于Jdk11 + SpringCloud + SpringBoot 的微æœ?务快速开å?‘å¹³å?°ï¼Œå…¶ä¸çš„å?¯é…?置的SaaS功能尤其闪耀, 具备RBAC功能ã€?网关统一鉴æ?ƒã€?Xss防跨站攻击ã€?自动代ç ?生æˆ?ã€?多ç§?å˜å‚¨ç³»ç»Ÿã€?分布å¼?事务ã€?分布å¼?定时任务ç‰å¤šä¸ªæ¨¡å?—,支æŒ?多业务系统并行开å?‘, 支æŒ?多æœ?务并行开å?‘,å?¯ä»¥ä½œä¸ºå?Žç«¯æœ?务的开å?‘脚手架zuihou/lamp-util
æ‰“é€ ä¸€å¥—å…¼é¡¾ SpringBoot å’Œ SpringCloud 项目的公共工具类
YunaiV/ruoyi-vue-pro
一套全部开æº?çš„ä¼?业级的快速开å?‘å¹³å?°ã€‚基于 Spring Boot + MyBatis Plus + Vue & Element 实现的å?Žå?°ç®¡ç?†ç³»ç»Ÿ + 微信å°?程åº?,支æŒ? RBAC 动æ€?æ?ƒé™?ã€?æ•°æ?®æ?ƒé™?ã€?SaaS 多租户ã€?Activiti + Flowable 工作æµ?ã€?三方登录ã€?支付ã€?çŸä¿¡ã€?商城ç‰åŠŸèƒ½ã€‚matevip/matecloud
一款基于Spring Cloud Alibaba的微�务架构gavenwangcn/vole
SpringCloud 微�务业务脚手架liuweijw/fw-cloud-framework
基于springcloud全家桶开å?‘分布å¼?框架(支æŒ?oauth2认è¯?授æ?ƒã€?SSO登录ã€?统一下å?•ã€?微信公众å?·æœ?务ã€?Shardingdbc分库分表ã€?常è§?æœ?务监控ã€?链路监控ã€?å¼‚æ¥æ—¥å¿—ã€?redis缓å˜ç‰åŠŸèƒ½ï¼‰ï¼Œå®žçŽ°åŸºäºŽVue全家桶ç‰å‰?å?Žç«¯åˆ†ç¦»é¡¹ç›®å·¥ç¨‹liuht777/Taroco
æ•´å?ˆNacosã€?Spring Cloud Alibaba,æ??供了一系列starter组件, å?Œæ—¶æ??ä¾›æœ?务治ç?†ã€?æœ?务监控ã€?OAuth2æ?ƒé™?认è¯?,支æŒ?æœ?务é™?级/熔æ–ã€?æœ?务æ?ƒé‡?mingyang66/spring-parent
æ•°æ?®åº“多数æ?®æº?ã€?Redis多数æ?®æº?ã€?日志组件ã€?全链路日志追踪ã€?埋点扩展点ã€?Nettyã€?å¾®æœ?务ã€?å¼€å?‘基础框架支æŒ?ã€?异常统一处ç?†ã€?返回值ã€?跨域ã€?API路由ã€?监控ç‰yzcheng90/ms
一个å‰?å?Žåˆ†ç¦»çš„分布å¼? spring cloud 框架(全家桶),这里有统一认è¯?,统一网关ç‰ç‰åŠŸèƒ½ï¼Œæ˜¯ä¸€ä¸ªé?žå¸¸ç®€æ´?的微æœ?务脚手架fafeidou/fast-cloud-nacos
è‡´åŠ›äºŽæ‰“é€ ä¸€ä¸ªåŸºäºŽnacos为注册ä¸å¿ƒï¼Œç»“å?ˆä¼?业开å?‘ä¹ æƒ¯ï¼Œæ€»ç»“çš„ä¸€äº›åŸºæœ¬çš„å®žçŽ°æ–¹å¼?HongZhaoHua/jstarcraft-core
ç›®æ ‡æ˜¯æ??供一个通用的Javaæ ¸å¿ƒç¼–ç¨‹æ¡†æž¶,作为æ?建其它框架或者项目的基础. è®©ç›¸å…³é¢†åŸŸçš„ç ”å?‘人员能够专注高层设计而ä¸?用关注底层实现. 涵盖了缓å˜,ç¼–è§£ç ?,通讯,事件,输入/输出,监控,å˜å‚¨,é…?ç½®,脚本和事务10个方é?¢budwk/budwk
BudWk原å??NutzWk,基于国产框架 nutz å?Š nutzboot å¼€å?‘的开æº?Web基础项目,集æ?ƒé™?体系ã€?系统å?‚æ•°ã€?æ•°æ?®å—å…¸ã€?站内消æ?¯ã€?定时任务ã€?CMSã€?å¾®ä¿¡ç‰æœ€å¸¸ç”¨åŠŸèƒ½ï¼Œä¸?庞æ?‚ã€?ä¸?é?¢é?¢ä¿±åˆ°ï¼Œä½¿å…¶å…·æœ‰ä¸Šæ‰‹å®¹æ˜“ã€?å¼€å?‘便æ?·ã€?扩展ç?µæ´»ç‰ç‰¹æ€§ï¼Œç‰¹åˆ«é€‚å?ˆå?„类大ä¸å°?型定制化项目需求
yinjihuan/spring-cloud
《Spring Cloudå¾®æœ?务-å…¨æ ˆæŠ€æœ¯ä¸Žæ¡ˆä¾‹è§£æž?》和《Spring Cloudå¾®æœ?务 入门 实战与进阶》é…?套æº?ç ?louyanfeng25/ddd-demo
《深入浅出DDD》讲解的演示项目,为了能够更好的ç?†è§£Demoä¸çš„分层与逻辑处ç?†ï¼Œæˆ‘å¼ºçƒˆå»ºè®®ä½ é…?å?ˆå°?册æ?¥æ·±å…¥äº†è§£DDD。
更多使用TTL的开�项目 ��
👷 Contributors
- Jerry Lee <oldratlee at gmail dot com> @oldratlee
- Yang Fang <snoop.fy at gmail dot com> @driventokill
- Zava Xu <zava.kid at gmail dot com> @zavakid
- wuwen <wuwen.55 at aliyun dot com> @wuwen5
- Xiaowei Shi <179969622 at qq dot com> @xwshiustc
- David Dai <351450944 at qq dot com> @LNAmp
- Your name here :-)

