alibaba / transmittable-thread-local

📌 a missing Java std lib(simple & 0-dependency) for framework/middleware, provide an enhanced InheritableThreadLocal that transmits values between threads even using thread pooling components.
https://github.com/alibaba/transmittable-thread-local
Apache License 2.0
7.59k stars 1.69k forks source link

TTL支持Spring的ThreadPoolTaskExecutor,如提供getTtlAsyncTaskExecutor #173

Closed liauraljl closed 2 years ago

liauraljl commented 4 years ago

我们在通过ThreadPoolTaskExecutor定义线程池时,想省去每次RunnableCallable传入线程池时的修饰。

能否提供类似getTtlExecutorServicegetTtlAsyncTaskExecutor方法呢?

oldratlee commented 4 years ago

你说的是指org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor,是吧?@liauraljl


目前没有直接支持SpringThreadPoolTaskExecutor

我思考一下

以发一个新版本支持。 💕 @liauraljl


先直接解决你问题的一个做法是:

可以自己先模仿 com.alibaba.ttl.threadpool.TtlExecutors.getTtlExecutor(),自己实现一个对应的工具方法:

https://github.com/alibaba/transmittable-thread-local/blob/dfca0564ae99b6d9a7f2ae5e24f5e627626e3c6b/library/src/main/java/com/alibaba/ttl/threadpool/TtlExecutors.java#L45-L50

照着实现,是比较简单的 :")

superbool commented 3 years ago

如果通过agent来增强的,是否就无需“每次Runnable和Callable传入线程池时的修饰”以及“getTtlAsyncTaskExecutor()方法“了? 看Spring的ThreadPoolTaskExecutor代码,最终还是调用的是JDK的Executor.execute。

oldratlee commented 3 years ago

如果通过agent来增强的,是否就无需“每次Runnable和Callable传入线程池时的修饰”以及“getTtlAsyncTaskExecutor()方法“了? 看Spring的ThreadPoolTaskExecutor代码,最终还是调用的是JDK的Executor.execute。

我做了一些简单测试:

Agent增强的使用方式下,SpringThreadPoolTaskExecutorTTL传递是 OK的。 @liauraljl # 原因就如 @superbool 所说,SpringThreadPoolTaskExecutor是基于JDKExecutor来实现的。

具体可以结合你的业务 再测试一下。 @liauraljl

liauraljl commented 3 years ago

@oldratlee 是的,一开始我们只用了api的方式,后面使用agent方式,是不需要改造的

liauraljl commented 3 years ago

@superbool 我说的这个问题就是在使用api的情况下,这个是前提哈;agent是兼容的,但是毕竟涉及到应用部署方式的改造,使用代价还是比较大的,可能有些开发人员希望仅通过引入依赖便可使用ttl的功能;

我们这边链路监控,灰度,服务治理等一些功能都是通过agent方式做的,已经有一个相对完善的agent管理系统了,所以已经弃用api方式

qipengfei0217 commented 2 years ago

我之前在项目里也遇到了类似的问题,然后自己根据ThreadPoolTaskExecutor,实现了一个TtlThreadPoolTaskExecutor。一开始想对ThreadPoolTaskExecutor底层的threadPoolExecutor进行包装,后来发现它并未对外暴露,这个想法不成立。那我们就着手在执行时进行包装,复写它的execute(),submit()等方法。这种方式,也不会干扰其它的方法,对内部线程池参数的修改。具体如下,实现起来很简单:

public class TtlThreadPoolTaskExecutor extends ThreadPoolTaskExecutor {

    /**
     * 错误提示语
     */
    private static final String ERROR_MESSAGE = "task不能为空";

    @Override
    public void execute(Runnable task) {
        super.execute(Objects.requireNonNull(TtlRunnable.get(task), ERROR_MESSAGE));
    }

    @Override
    public void execute(Runnable task, long startTimeout) {
        super.execute(Objects.requireNonNull(TtlRunnable.get(task), ERROR_MESSAGE), startTimeout);
    }

    @Override
    public Future<?> submit(Runnable task) {
        return super.submit(Objects.requireNonNull(TtlRunnable.get(task), ERROR_MESSAGE));
    }

    @Override
    public <T> Future<T> submit(Callable<T> task) {
        return super.submit(Objects.requireNonNull(TtlCallable.get(task), ERROR_MESSAGE));
    }

    @Override
    public ListenableFuture<?> submitListenable(Runnable task) {
        return super.submitListenable(Objects.requireNonNull(TtlRunnable.get(task), ERROR_MESSAGE));
    }

    @Override
    public <T> ListenableFuture<T> submitListenable(Callable<T> task) {
        return super.submitListenable(Objects.requireNonNull(TtlCallable.get(task), ERROR_MESSAGE));
    }
}

@oldratlee @liauraljl

oldratlee commented 2 years ago

目前看来Spring的ThreadPoolTaskExecutor可以不用额外的支持:

这个 Issue 先 close 了。

whaceyou commented 2 years ago

如果ThreadPoolTaskExecutor 不支持的话 下面的这个配置 在spring注入的时候 如果使用 ThreadPoolTaskExecutor 来引用启动就会报类型不匹配 image

oldratlee commented 2 years ago

@whaceyou 如果要注入ThreadPoolTaskExecutor类型,


master开发分支升级版本到v3.xTTL v3.x重点会是

TTL核心功能,v2已经是开放的,即

TTL项目中,扩大集成范围,可以优化大家平时常用场景开箱即用的使用体验。

其实,不少方便使用的TTL集成/增强,各个大厂是会有实现的,但并没开源出来;这些使用便利的地方值得进一步解决得更好。

f4cklangzi commented 1 year ago

如果ThreadPoolTaskExecutor 不支持的话 下面的这个配置 在spring注入的时候 如果使用 ThreadPoolTaskExecutor 来引用启动就会报类型不匹配 image

我试了好像这样可以

if (bean instanceof ThreadPoolTaskExecutor && !(bean instanceof TtlEnhanced)) {
        ThreadPoolTaskExecutor poolTaskExecutor = (ThreadPoolTaskExecutor) bean;
        poolTaskExecutor.setTaskDecorator(TtlRunnable::get);
        poolTaskExecutor.initialize();
        return poolTaskExecutor;
}