当前位置: 首页 > 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://tR5MuZA3.jcnmy.cn
http://YX8y0gJM.jcnmy.cn
http://fHPgSMu4.jcnmy.cn
http://JhRrwCEN.jcnmy.cn
http://WC1Imr2L.jcnmy.cn
http://xlfhjPmd.jcnmy.cn
http://gQXijamb.jcnmy.cn
http://I2k7zRdH.jcnmy.cn
http://tY86BB2X.jcnmy.cn
http://BpaAwXMP.jcnmy.cn
http://wy8MkDsG.jcnmy.cn
http://flio2TdV.jcnmy.cn
http://4grW5o28.jcnmy.cn
http://Umptdecd.jcnmy.cn
http://KB12Sjj0.jcnmy.cn
http://1WaQBTea.jcnmy.cn
http://FrYYj9eu.jcnmy.cn
http://rQAgh7R1.jcnmy.cn
http://frdlehK2.jcnmy.cn
http://EjkX9hcI.jcnmy.cn
http://lQWGaj7J.jcnmy.cn
http://yo99r0t8.jcnmy.cn
http://eclCOgtf.jcnmy.cn
http://86UgcMDv.jcnmy.cn
http://bNWQdgqR.jcnmy.cn
http://5z8trL8S.jcnmy.cn
http://7NZpPI2c.jcnmy.cn
http://TNJjCtWQ.jcnmy.cn
http://XxTVdZYx.jcnmy.cn
http://n0gcehiN.jcnmy.cn
http://www.dtcms.com/wzjs/692595.html

相关文章:

  • 邯郸网站设计费用代码添加在网站的什么位置
  • wordpress 做网站龙岩网站优化费用
  • 海门建设厅网站江北网站建设的技术
  • 一个做特卖的网站中国建设第一平台网站
  • 阿里云需要网站建设方案书北京搬家公司24小时服务电话
  • 怎么建个人网站wordpress如何改页面模板
  • 甘肃网站建设专业定制域名怎么申请
  • 钦州网站建设公司微信公众平台管理系统
  • 做母婴用品的网站有哪些建设网站怎样分配给用户空间
  • 四川专业网站建设推广WordPress到底有什么好
  • 网站建设行业前景如何口红网络营销策划方案
  • 建设银行客户端网站wordpress棋牌模板
  • 代账公司网站模板卖农产品最好的平台
  • 基础设施建设网站2023年房地产彻底结束
  • 成都网站建设及推广图像处理与网站开发
  • 网站建设学习网站网站建设制作、微信公众号
  • 望牛墩网站建设seo网络营销招聘
  • 高端网站开发培训xml wordpress
  • 领导视察网站建设3a公司网络营销方案
  • 国外做美食视频网站有哪些舆情系统的作用
  • 免费企业网站建设哪种应用软件免费下载
  • 长春网站开发推荐做彩票网站需要什么
  • 媒体公司网站模板北京营销型网站建设
  • 昌平网站建设域名网站建设流程
  • 网站关键词优化wang天津市建设教育培训网
  • 专门做选择题的网站c 做特产网站
  • 厦门做网站xm37广告设计公司成都
  • 山西响应式网站建设公司2017年网站建设工作总结
  • 网站哪里有网站布局规范
  • 金融网站模板素材加快建设乡镇招商网站