当前位置: 首页 > wzjs >正文

太原网站建设质量推荐零售客户电商网站

太原网站建设质量推荐,零售客户电商网站,亚马逊网站怎么做,服务器维护教程文章目录 前言正文一、实现原理二、项目环境三、项目代码3.1 pom.xml3.2 TtlMDCAdapter3.3 ThreadLocalMapOfStacks3.4 StaticMDCBinder3.5 启动类& 线程池配置3.6 logback-spring.xml 四、测试4.1 TestController4.2 调拥接口,观察日志 前言 有这样一个场景&am…

文章目录

  • 前言
  • 正文
    • 一、实现原理
    • 二、项目环境
    • 三、项目代码
      • 3.1 pom.xml
      • 3.2 TtlMDCAdapter
      • 3.3 ThreadLocalMapOfStacks
      • 3.4 StaticMDCBinder
      • 3.5 启动类& 线程池配置
      • 3.6 logback-spring.xml
    • 四、测试
      • 4.1 TestController
      • 4.2 调拥接口,观察日志

前言

有这样一个场景:
在一个springboot项目中,使用了 logback进行日志输出。但是项目中有部分功能使用了线程池,使用MDC进行日志ID的输出。

而默认的 LogbackMDCAdapter 无法传递参数到线程池中。因为它本身的实现是依赖于ThreadLocal进行数据传递的。

本文就将解决这个参数传递的问题,使用阿里巴巴开源的TransmittableThreadLocal 来重新实现一个MDCAdapter

PS:有了解过 ThreadLocal 原理 以及 TTL 的朋友肯定知道,TTL 可以进行线程池级别的参数传递。这里不做过多描述。

正文

一、实现原理

为了实现在线程池中,可以传递 logid ,我们需要做两个操作:

  1. 自定义MDCAdapter,使用 TTL 替换原先的 ThreadLocal
  2. 在自己项目中,创建 “同包同名” 的org.slf4j.impl.StaticMDCBinder,并指定 MDCAdapter 是自己自定义的实现;

二、项目环境

  • Java版本:Java 1.8
  • SpringBoot版本: 2.7.18
  • TTL 版本:2.14.2

三、项目代码

3.1 pom.xml

<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"><modelVersion>4.0.0</modelVersion><groupId>org.example</groupId><artifactId>pine-mdc-ttl</artifactId><version>1.0-SNAPSHOT</version><packaging>jar</packaging><name>pine-mdc-ttl</name><url>http://maven.apache.org</url><properties><java.version>1.8</java.version><java.compiler.source>${java.version}</java.compiler.source><java.compiler.target>${java.version}</java.compiler.target><project.build.sourceEncoding>UTF-8</project.build.sourceEncoding><project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding><spring-boot.version>2.7.18</spring-boot.version><ttl.version>2.14.2</ttl.version><lombok.version>1.18.34</lombok.version></properties><dependencies><dependency><groupId>org.projectlombok</groupId><artifactId>lombok</artifactId></dependency><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-web</artifactId></dependency><dependency><groupId>com.alibaba</groupId><artifactId>transmittable-thread-local</artifactId></dependency><!--日志颜色--><dependency><groupId>org.fusesource.jansi</groupId><artifactId>jansi</artifactId><version>2.4.0</version></dependency></dependencies><build><plugins><plugin><groupId>org.apache.maven.plugins</groupId><artifactId>maven-compiler-plugin</artifactId><configuration><source>1.8</source><target>1.8</target><encoding>UTF-8</encoding></configuration></plugin><plugin><groupId>org.springframework.boot</groupId><artifactId>spring-boot-maven-plugin</artifactId><version>${spring-boot.version}</version><configuration><mainClass>org.BootDemoApplication</mainClass><skip>true</skip></configuration><executions><execution><id>repackage</id><goals><goal>repackage</goal></goals></execution></executions></plugin></plugins></build><dependencyManagement><dependencies><dependency><groupId>com.alibaba</groupId><artifactId>transmittable-thread-local</artifactId><version>${ttl.version}</version></dependency><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter</artifactId><version>${spring-boot.version}</version></dependency><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-web</artifactId><version>${spring-boot.version}</version></dependency><dependency><groupId>org.projectlombok</groupId><artifactId>lombok</artifactId><version>${lombok.version}</version><scope>provided</scope><optional>true</optional></dependency></dependencies></dependencyManagement>
</project>

3.2 TtlMDCAdapter

package org.pine.mdcttl;import com.alibaba.ttl.TransmittableThreadLocal;
import org.slf4j.spi.MDCAdapter;import java.util.Deque;
import java.util.HashMap;
import java.util.Map;/*** 自定义MDC适配器:与TransmittableThreadLocal结合使用*/
public class TtlMDCAdapter implements MDCAdapter {private final ThreadLocalMapOfStacks threadLocalMapOfDeques = new ThreadLocalMapOfStacks();private final ThreadLocal<Map<String, String>> context = new TransmittableThreadLocal<Map<String, String>>() {@Overrideprotected Map<String, String> initialValue() {return new HashMap<>();}@Overridepublic Map<String, String> copy(Map<String, String> parentValue) {return parentValue != null ? new HashMap<>(parentValue) : null;}};@Overridepublic void put(String key, String val) {context.get().put(key, val);}@Overridepublic String get(String key) {return context.get().get(key);}@Overridepublic void remove(String key) {context.get().remove(key);}@Overridepublic void clear() {context.get().clear();context.remove();}@Overridepublic Map<String, String> getCopyOfContextMap() {return new HashMap<>(context.get());}@Overridepublic void setContextMap(Map<String, String> contextMap) {context.set(new HashMap<>(contextMap));}public void pushByKey(String key, String value) {this.threadLocalMapOfDeques.pushByKey(key, value);}public String popByKey(String key) {return this.threadLocalMapOfDeques.popByKey(key);}public Deque<String> getCopyOfDequeByKey(String key) {return this.threadLocalMapOfDeques.getCopyOfDequeByKey(key);}public void clearDequeByKey(String key) {this.threadLocalMapOfDeques.clearDequeByKey(key);}
}

3.3 ThreadLocalMapOfStacks

//
// Source code recreated from a .class file by IntelliJ IDEA
// (powered by FernFlower decompiler)
//package org.pine.mdcttl;import com.alibaba.ttl.TransmittableThreadLocal;import java.util.ArrayDeque;
import java.util.Deque;
import java.util.HashMap;
import java.util.Map;public class ThreadLocalMapOfStacks {final ThreadLocal<Map<String, Deque<String>>> tlMapOfStacks = new TransmittableThreadLocal<>();public ThreadLocalMapOfStacks() {}public void pushByKey(String key, String value) {if (key != null) {Map<String, Deque<String>> map = (Map)this.tlMapOfStacks.get();if (map == null) {map = new HashMap();this.tlMapOfStacks.set(map);}Deque<String> deque = (Deque)((Map)map).get(key);if (deque == null) {deque = new ArrayDeque();}((Deque)deque).push(value);((Map)map).put(key, deque);}}public String popByKey(String key) {if (key == null) {return null;} else {Map<String, Deque<String>> map = (Map)this.tlMapOfStacks.get();if (map == null) {return null;} else {Deque<String> deque = (Deque)map.get(key);return deque == null ? null : (String)deque.pop();}}}public Deque<String> getCopyOfDequeByKey(String key) {if (key == null) {return null;} else {Map<String, Deque<String>> map = (Map)this.tlMapOfStacks.get();if (map == null) {return null;} else {Deque<String> deque = (Deque)map.get(key);return deque == null ? null : new ArrayDeque(deque);}}}public void clearDequeByKey(String key) {if (key != null) {Map<String, Deque<String>> map = (Map)this.tlMapOfStacks.get();if (map != null) {Deque<String> deque = (Deque)map.get(key);if (deque != null) {deque.clear();}}}}
}

3.4 StaticMDCBinder

package org.slf4j.impl;import org.pine.mdcttl.TtlMDCAdapter;
import org.slf4j.spi.MDCAdapter;/*** 自定义MDC绑定器实现:* 1. 绑定自定义的ttl-MDC适配器* 2. 覆盖原先的org.slf4j.impl.StaticMDCBinder,使自定义的ttl-mdc适配器生效*/
public class StaticMDCBinder {public static final StaticMDCBinder SINGLETON = new StaticMDCBinder();public MDCAdapter getMDCA() {return new TtlMDCAdapter();}public String getMDCAdapterClassStr() {return TtlMDCAdapter.class.getName();}
}

3.5 启动类& 线程池配置

package org.pine;import com.alibaba.ttl.threadpool.TtlExecutors;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.context.annotation.Bean;
import org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor;import java.util.concurrent.ExecutorService;@SpringBootApplication
public class BootDemoApplication {public static void main(String[] args) {SpringApplication.run(BootDemoApplication.class, args);}@Bean(name = "ttlExecutorService")public ExecutorService ttlExecutorService() {ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor();executor.setCorePoolSize(10);executor.setMaxPoolSize(100);executor.initialize();// 关键步骤:用TTL包装线程池return TtlExecutors.getTtlExecutorService(executor.getThreadPoolExecutor());}
}

3.6 logback-spring.xml

<?xml version="1.0" encoding="UTF-8" ?>
<configuration debug="false"><!-- 启用ANSI颜色支持(需要Jansi库) --><conversionRule conversionWord="clr" converterClass="org.springframework.boot.logging.logback.ColorConverter"/><conversionRule conversionWord="wex" converterClass="org.springframework.boot.logging.logback.WhitespaceThrowableProxyConverter"/><appender name="STDOUT" class="ch.qos.logback.core.ConsoleAppender"><encoder><!-- 带颜色的日志格式 --><!-- 格式化输出: %d表示日期, %thread表示线程名, %-5level: 级别从左显示5个字符宽度 %msg:日志消息, %n是换行符 %logger{0}:表示类名不进行任何缩写,输出完整的类名,%logger{50}:表示类名的最大长度为50个字符,超过的部分会被截断。--><!-- %clr(...){color}是Spring Boot对Logback的扩展,用于输出带颜色的日志。 颜色名称支持:black, red, green, yellow, blue, magenta, cyan, white等--><pattern>[%clr(%d{yyyy-MM-dd HH:mm:ss.SSS}){green}] %clr([%thread]){faint} %clr([logid=%X{logid:-system}]){red} %highlight(%-5level) %cyan(%logger{50}) - %msg%n</pattern></encoder></appender><!-- 日志输出级别 --><root level="INFO"><appender-ref ref="STDOUT"/></root>
</configuration>

四、测试

4.1 TestController

package org.pine.testcontroller;import lombok.extern.slf4j.Slf4j;
import org.slf4j.MDC;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;import javax.annotation.Resource;
import java.util.UUID;
import java.util.concurrent.ExecutorService;@RestController
@Slf4j
@RequestMapping("/test")
public class TestController {@Resource(name = "ttlExecutorService")private ExecutorService executorService;@RequestMapping("/test1")public String test() {String logId = UUID.randomUUID().toString();MDC.put("logid",logId );log.info("logId:{}", logId);executorService.submit(() -> {log.info("executorService-logId:{}", MDC.get("logid"));});return "test";}
}

4.2 调拥接口,观察日志

访问:http://localhost:8080/test/test1

观察到的日志结果:

[2025-03-14 14:54:10.304] [http-nio-8080-exec-1] [logid=a5610ff9-f250-4c3f-81f5-15c36d1a6278] INFO  org.pine.testcontroller.TestController - logId:a5610ff9-f250-4c3f-81f5-15c36d1a6278
[2025-03-14 14:54:10.317] [ThreadPoolTaskExecutor-1] [logid=a5610ff9-f250-4c3f-81f5-15c36d1a6278] INFO  org.pine.testcontroller.TestController - executorService-logId:a5610ff9-f250-4c3f-81f5-15c36d1a6278

可以看到线程池中输出的结果中,拼接了与其主线程相同的logid。这也是本文需要实现的效果。

http://www.dtcms.com/wzjs/55447.html

相关文章:

  • 自学网网站外包公司怎么赚钱
  • 那个网站做旅游规划好app拉新怎么做
  • 怎样自己做电影网站色盲色弱测试
  • 宁乡网站开发公司推荐google优化排名
  • 日本可以自己做网站吗?好搜搜索
  • 无为县建设局网站模板建站流程
  • 怎么建设属于自己的网站中国新闻
  • 定制版网站建设费用360网站seo手机优化软件
  • 平面设计平台有哪些seo实战密码电子版
  • 长沙做旅游网站多少钱深圳优化公司义高粱seo
  • 网站建设日程表个人如何在百度上做广告
  • 下列哪些属于营销型网站的基础建设如何推广普通话
  • asp.net+制作网站开发深圳博惠seo
  • 一级a做爰片软件网站山西太原网络推广
  • 日喀则市住房和城乡建设局网站crm客户管理系统
  • 莱芜建设网站2023网络营销成功案例
  • 好的企业网站建设上海整站seo
  • wordpress安装中文seo软件哪个好
  • 施工企业工作环境关键词自动优化
  • 做网站基本教程百度seo软件优化
  • 番禺网站建设公司百度推广怎么做步骤
  • 算命网站建设开发深圳推广平台深圳网络推广
  • 泰安网站制作湖南关键词网络科技有限公司
  • 找个人合伙做网站高清网站推广免费下载
  • 网站域名查询网址关键词排名关键词快速排名
  • 彩票网站怎么做推广北京网站seo费用
  • 自己有网站怎么做点卡?今日最新的新闻
  • 怎样做支付网站高质量网站外链平台
  • php做网站切换语言扬州百度推广公司
  • 成都企业网站开发公司常用的营销方法和手段