XXJ-JOB 执行器 在线程池内日志输出错乱的问题

问题:最近在使用 xxl-job 时,执行器使用异步线程处理任务时,发现日志输出存错乱。第一次的日志能够正常打印到对应的log文件中,后面每次都会打印到最开始的日志文件中如下

 分析XxlJobHelper 源码:

 XxlJobContext 源码 :

XxlJobContext  使用InheritableThreadLocal, InheritableThreadLocal主要用于子线程创建时,需要自动继承父线程的ThreadLocal变量,方便必要信息的进一步传递。 但对于使用线程池等会池化复用线程的执行组件的情况,线程由线程池创建好,并且线程是池化起来反复使用的;这时父子线程关系的ThreadLocal值传递已经没有意义,应用需要的实际上是把 任务提交给线程池时的ThreadLocal值传递到任务执行时。

解决方案:

使用阿里巴巴TransmittableThreadLocal 替换 XxlJobContext 内的 InheritableThreadLocal

  1. xxl-job-core pom 文件映入maven 依赖:

    <dependency>
        <groupId>com.alibaba</groupId>
        <artifactId>transmittable-thread-local</artifactId>
        <version>2.14.0</version>
    </dependency>
  2. 修改XxlJobContext InheritableThreadLocal 为TransmittableThreadLocal

     // TransmittableThreadLocal(TTL):
     // 在使用线程池等会池化复用线程的执行组件情况下,提供ThreadLocal值的传递功能,解决异步执行时上下文传递的问题
     // @Link https://github.com/alibaba/transmittable-thread-local
     private static TransmittableThreadLocal<XxlJobContext> contextHolder = new TransmittableThreadLocal<XxlJobContext>(); // support for child thread of job handler)
  3. 重新打包编译

    客户端使用

  4. 修改@Async 默认线程池

    @Configuration
    @EnableAsync
    public class AsyncConfig implements AsyncConfigurer {
        @Override
        public Executor getAsyncExecutor() {
    
            ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor();
            //配置核心线程数
            executor.setCorePoolSize(5);
            //配置最大线程数
            executor.setMaxPoolSize(20);
            //配置队列大小
            executor.setQueueCapacity(1000000);
            //线程池维护线程所允许的空闲时间
            executor.setKeepAliveSeconds(30);
            //配置线程池中的线程的名称前缀
            executor.setThreadNamePrefix("Async-Thread-");
            //设置线程池关闭的时候等待所有任务都完成再继续销毁其他的Bean
            executor.setWaitForTasksToCompleteOnShutdown(true);
            //设置线程池中任务的等待时间,如果超过这个时候还没有销毁就强制销毁,以确保应用最后能够被关闭,而不是阻塞住
            executor.setAwaitTerminationSeconds(60);
            // rejection-policy:当pool已经达到max size的时候,如何处理新任务
            // CALLER_RUNS:不在新线程中执行任务,而是由调用者所在的线程来执行
            executor.setRejectedExecutionHandler(new ThreadPoolExecutor.CallerRunsPolicy());
            //执行初始化
            executor.initialize();
            // 使用TtlExecutors 修饰线程池
            return TtlExecutors.getTtlExecutorService(executor.getThreadPoolExecutor());
        }
    
        @Override
        public AsyncUncaughtExceptionHandler getAsyncUncaughtExceptionHandler() {
            return null;
        }
    }
  5. 修改后日志输出正常

        

 

参考博客

### 若依框架集成 XXL-JOB 实现方法 #### 1. Maven 依赖引入 为了在若依框架中集成 XXL-JOB 调度功能,首先需要在项目的 `pom.xml` 文件中添加 XXL-JOB 的核心库依赖。 ```xml <dependency> <groupId>com.xuxueli</groupId> <artifactId>xxl-job-core</artifactId> <version>2.4.1-SNAPSHOT</version> </dependency> ``` 此操作确保项目能够访问到 XXL-JOB 提供的功能接口和工具类[^1]。 #### 2. 配置文件设置 接着,在 Spring Boot 应用序的配置文件 (`application.yml`) 中定义必要的参数来连接至 XXL-JOB 调度中心: ```yaml xxl: job: admin: addresses: http://localhost:8080/xxl-job-admin # 调度中心地址 executor: appname: ruoyi-executor-sample # 执行器名称 ip: # 自动获取本机IP,默认为空字符串 port: 9999 # 执行器端口 logpath: /data/applogs/xxl-job/jobhandler # 日志路径 logfileRetentionDays: 30 # 日志保留天数 ``` 这些属性用于指定执行器的应用名、监听端口号以及其他运行时所需的环境变量[^3]。 #### 3. 创建自定义 Job 类 基于业务需求编写具体的任务处理器 (Job Handler),并使用 `@XxlJob` 注解标记该方法作为可被调度的任务入口点。下面给出一个简单的例子展示如何创建这样的组件: ```java import com.xxl.job.core.handler.annotation.XxlJob; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.stereotype.Component; @Component public class CustomTask { private static final Logger LOGGER = LoggerFactory.getLogger(CustomTask.class); @XxlJob("customTaskHandler") public void execute() throws Exception { LOGGER.info("Custom Task is running..."); // Add your business logic here. } } ``` 这段代码展示了怎样利用 Spring Bean 来注册一个新的任务处理函数,并将其暴露给 XXL-JOB 进行管理和触发[^5]。 #### 4. 启动应用与验证 完成上述步骤之后,重启应用序使新的配置生效。此时应该可以在 XXL-JOB 控制台上看到新加入的执行节点及其关联的任务列表项。通过 Web UI 可以方便地管理各个作业的状态、查看历史记录等信息[^4]。 ---
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值