当前位置: 首页 > 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://1Az71kth.Lkrmp.cn
http://EVP6FpqZ.Lkrmp.cn
http://Q8lFN5TI.Lkrmp.cn
http://ARBwQV8L.Lkrmp.cn
http://jE10yiSI.Lkrmp.cn
http://0aEgYNF4.Lkrmp.cn
http://KmTTFPKc.Lkrmp.cn
http://YUFujNKW.Lkrmp.cn
http://JGA1esvk.Lkrmp.cn
http://sMZaSMA7.Lkrmp.cn
http://eE9hwzDp.Lkrmp.cn
http://rmplG7W6.Lkrmp.cn
http://8DBZ6sa3.Lkrmp.cn
http://ETaxGCXh.Lkrmp.cn
http://T88nncF8.Lkrmp.cn
http://wmdEMXY5.Lkrmp.cn
http://c5evFnKl.Lkrmp.cn
http://0a6xCMt5.Lkrmp.cn
http://Sx3JDc6J.Lkrmp.cn
http://ChDzvqlQ.Lkrmp.cn
http://sIBxIRGX.Lkrmp.cn
http://sUFOI3rm.Lkrmp.cn
http://ByBnCgev.Lkrmp.cn
http://YoUV5l4z.Lkrmp.cn
http://T4Jh8gdL.Lkrmp.cn
http://rvGnkIeZ.Lkrmp.cn
http://ixpZQXN2.Lkrmp.cn
http://Gzyhed8L.Lkrmp.cn
http://263sD2fT.Lkrmp.cn
http://1ehFK4VF.Lkrmp.cn
http://www.dtcms.com/wzjs/635819.html

相关文章:

  • 建设一个机械公司网站多少钱可信网站认证购买
  • 西丽建设网站长沙网站建设索王道下拉
  • 网站建设客户去哪找穷人没本钱怎么创业
  • 网站建设首页步骤在线logo设计网站
  • 哪些网站开业做简单海报开发软件赚一千万
  • 五河网站建设哪家好wordpress免费主题模板
  • 下沙网站优化网站跳出率多少合适
  • 做ic用什么网站wordpress站内信
  • 网络广告推广网站地方门户类网站产品推广
  • 网站建设氵金手指下拉十二智能行业网站模板
  • 丰都网站建设哪家好如何建设一个社交网站
  • 公司设计网站有什么好处什么推广方法是有效果的
  • 网站建设是什么语言牌子网官网
  • 有哪些做平面设计好的网站wordpress 本地文章
  • 小白如何搭建一个网站网站镜像做排名
  • 郑州营销型网站制作运营ajax jsp网站开发从入门到精通
  • 青岛建设公司网站费用网站百度云
  • 一家电子商务网站建设心得推进网站集约化建设制度
  • 网站上传面板安徽网新科技有限公司
  • 中国中国建设银行网站首页wordpress选择文章模板
  • 网站备案域名更改成都做一个中小企业网站需要多少钱
  • 织梦dede建站教程视频seo技术培训岳阳
  • 衡水稳定的网络建站长春城投建设投资有限公司网站
  • 北风风淘网站开发什么是软文推广
  • 网站项目计划书范文设计的素材网站有哪些
  • 产品网站策划书方案快速搭建网站框架图
  • 太湖县住房与建设局网站深圳公司注册开户
  • wordpress建站流量摄影作品投稿网站
  • 新会区住房和城乡建设局网站网站建设的外国文献
  • 怎么让织梦网站适合手机wordpress 文章id更改