Если положить RequestId / userId / traceId в ThreadLocal и передать задачу в ExecutorService в итоге значение пропадёт. InheritableThreadLocal помогает только при явном создании потока, но не при переиспользовании из пула.
Alibaba решили это ещё в 2013 году, а библиотека до сих пор активно поддерживается → TransmittableThreadLocal (TTL).
🔹 Подключается:
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>transmittable-thread-local</artifactId>
<version>2.14.5</version>
</dependency>
🔹 Используется как обычный ThreadLocal, только умнее:
TransmittableThreadLocal<String> traceId = new TransmittableThreadLocal<>();
traceId.set("req-123");
ExecutorService pool = TtlExecutors.getTtlExecutorService(
Executors.newFixedThreadPool(4)
);
pool.submit(() -> {
// "req-123" — доступен здесь, в потоке из пула
System.out.println(traceId.get());
});
🔹 Три способа интеграции
→ Обернуть Runnable/Callable — TtlRunnable.get(task)
→ Обернуть пул — TtlExecutors.getTtlExecutorService(pool)
→ Java Agent — вообще без изменений в коде:
-javaagent:transmittable-thread-local.jarАгентовый режим особенно полезен, когда нужно прозрачно встроить TTL в легаси-проект или сторонний фреймворк — он патчит JDK-классы пулов на уровне байткода.
0 зависимостей. Работает с виртуальными потоками (Project Loom). Поддерживает кастомный TtlCopier для глубокого копирования значений при передаче в дочерний поток.
Актуально везде, где есть distributed tracing, MDC, tenant isolation или любой per-request контекст в многопоточке.
⚠️ README встретит иероглифами, не пугайся, английская версия лежит в README-EN.md.
🔗 Репозиторий на GitHub
══════ Навигация ══════
Вакансии • Задачи • Собесы
🐸 Библиотека джависта
#Enterprise