最新国产好看的视频,伊人天堂AV在线,国产Aaaaaa视频,蜜臀视频在线观看一区,人妻av色图,密臀久久久精品影片,青青视频免费观看毛片,久草在线观看视,国产三级精品色情在线

SpringBoot集成TraceId的方案詳解(追蹤ID)

 更新時(shí)間:2025年12月03日 10:03:53   作者:Slow菜鳥  
文章介紹了兩種在Java應(yīng)用中實(shí)現(xiàn)TraceId(請(qǐng)求鏈路唯一標(biāo)識(shí))的方法,兩種方案都通過合理配置和代碼實(shí)現(xiàn),確保了TraceId在不同服務(wù)和異步線程中的傳遞,從而實(shí)現(xiàn)統(tǒng)一的日志跟蹤和問題排查,感興趣的朋友跟隨小編一起看看吧

一、TraceId 是什么?

  • TraceId 就是給每一條請(qǐng)求鏈路分配的全局唯一 “身份證號(hào)” —— 不管是單體項(xiàng)目里的一次接口請(qǐng)求,還是分布式微服務(wù)里跨多個(gè)服務(wù)的調(diào)用流程,只要屬于同一條請(qǐng)求鏈路,全程共用同一個(gè) TraceId。
  • 你可以把它理解成:用戶在 APP 點(diǎn)了 “下單” 按鈕,這個(gè)請(qǐng)求從前端→網(wǎng)關(guān)→訂單服務(wù)→用戶服務(wù)→支付服務(wù),整個(gè)流程會(huì)被分配一個(gè)唯一的 TraceId,所有環(huán)節(jié)的日志、調(diào)用記錄都帶上這個(gè) ID。排查問題時(shí),只要搜這個(gè) TraceId,就能把整條鏈路的日志 / 調(diào)用記錄都揪出來,不用在海量日志里大海撈針。

場(chǎng)景一:無SkyWalking的最優(yōu)實(shí)現(xiàn)

核心方案

MDC(日志上下文) + Filter(入口生成/讀取TraceId) + TaskDecorator(異步線程傳遞) + Feign/RestTemplate攔截器(微服務(wù)跨服務(wù)傳遞)

適用場(chǎng)景

  • 中小型單體/微服務(wù)項(xiàng)目;
  • 無可視化鏈路分析需求,僅需日志攜帶TraceId定位問題;
  • 不愿引入額外中間件(SkyWalking OAP)增加運(yùn)維成本。

1. 依賴配置(拆分SpringBoot/SpringCloud)

1.1 SpringBoot單體項(xiàng)目依賴

<?xml version="1.0" encoding="UTF-8"?>
<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 https://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>
    <parent>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-parent</artifactId>
        <version>2.7.15</version> <!-- 3.x可替換為3.2.0 -->
        <relativePath/>
    </parent>
    <groupId>com.example</groupId>
    <artifactId>boot-traceid-no-skywalking</artifactId>
    <version>0.0.1-SNAPSHOT</version>
    <dependencies>
        <!-- SpringBoot Web核心 -->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>
        <!-- 工具類:判空/字符串處理 -->
        <dependency>
            <groupId>org.apache.commons</groupId>
            <artifactId>commons-lang3</artifactId>
            <version>3.14.0</version>
        </dependency>
        <!-- 可選:Hutool(雪花ID生成) -->
        <dependency>
            <groupId>cn.hutool</groupId>
            <artifactId>hutool-all</artifactId>
            <version>5.8.22</version>
        </dependency>
        <!-- 測(cè)試依賴(非核心) -->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-test</artifactId>
            <scope>test</scope>
        </dependency>
    </dependencies>
    <build>
        <plugins>
            <plugin>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-maven-plugin</artifactId>
                <version>2.7.15</version>
            </plugin>
        </plugins>
    </build>
</project>

1.2 SpringCloud微服務(wù)項(xiàng)目依賴

<?xml version="1.0" encoding="UTF-8"?>
<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 https://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>
    <parent>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-parent</artifactId>
        <version>2.7.15</version> <!-- 對(duì)應(yīng)Cloud 2021.0.x -->
        <relativePath/>
    </parent>
    <groupId>com.example</groupId>
    <artifactId>cloud-traceid-no-skywalking</artifactId>
    <version>0.0.1-SNAPSHOT</version>
    <dependencies>
        <!-- 基礎(chǔ)依賴(同SpringBoot) -->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>
        <dependency>
            <groupId>org.apache.commons</groupId>
            <artifactId>commons-lang3</artifactId>
            <version>3.14.0</version>
        </dependency>
        <dependency>
            <groupId>cn.hutool</groupId>
            <artifactId>hutool-all</artifactId>
            <version>5.8.22</version>
        </dependency>
        <!-- 微服務(wù)核心:OpenFeign -->
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-openfeign</artifactId>
        </dependency>
        <!-- 測(cè)試依賴 -->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-test</artifactId>
            <scope>test</scope>
        </dependency>
    </dependencies>
    <!-- Cloud版本管理 -->
    <dependencyManagement>
        <dependencies>
            <dependency>
                <groupId>org.springframework.cloud</groupId>
                <artifactId>spring-cloud-dependencies</artifactId>
                <version>2021.0.5</version>
                <type>pom</type>
                <scope>import</scope>
            </dependency>
        </dependencies>
    </dependencyManagement>
    <build>
        <plugins>
            <plugin>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-maven-plugin</artifactId>
                <version>2.7.15</version>
            </plugin>
        </plugins>
    </build>
</project>

2. 核心代碼實(shí)現(xiàn)(無SkyWalking專屬)

2.1 TraceId工具類(自定義生成/傳遞)

package com.example.traceid.util;
import cn.hutool.core.lang.Snowflake;
import cn.hutool.core.net.NetUtil;
import cn.hutool.core.util.IdUtil;
import org.apache.commons.lang3.StringUtils;
import org.slf4j.MDC;
import java.util.UUID;
/**
 * 無SkyWalking時(shí):自定義TraceId生成/管理工具類
 */
public class TraceIdUtils {
    // MDC中TraceId的Key(日志配置用%X{traceId}讀?。?
    public static final String TRACE_ID_MDC_KEY = "traceId";
    // HTTP頭傳遞TraceId的Key
    public static final String TRACE_ID_HEADER_KEY = "X-Trace-Id";
    // 雪花ID生成器(高并發(fā)用,單機(jī)/低并發(fā)可只用UUID)
    private static final Snowflake SNOWFLAKE = IdUtil.createSnowflake(
            NetUtil.ipv4ToLong(NetUtil.getLocalhostStr()) % 32, 1L
    );
    /**
     * 生成TraceId:低并發(fā)用UUID,高并發(fā)用雪花ID
     */
    public static String generateTraceId() {
        // 方案1:UUID(默認(rèn),無需額外依賴)
        return UUID.randomUUID().toString().replace("-", "");
        // 方案2:雪花ID(高并發(fā)切換)
        // return SNOWFLAKE.nextIdStr();
    }
    /**
     * 從MDC獲取TraceId,兜底返回UNKNOWN
     */
    public static String getTraceId() {
        String traceId = MDC.get(TRACE_ID_MDC_KEY);
        return StringUtils.isBlank(traceId) ? "UNKNOWN" : traceId;
    }
    /**
     * 手動(dòng)設(shè)置TraceId到MDC
     */
    public static void setTraceIdToMdc(String traceId) {
        if (StringUtils.isNotBlank(traceId)) {
            MDC.put(TRACE_ID_MDC_KEY, traceId);
        }
    }
    /**
     * 清除MDC中的TraceId
     */
    public static void clearTraceIdFromMdc() {
        MDC.remove(TRACE_ID_MDC_KEY);
    }
}

2.2 TraceId過濾器(請(qǐng)求入口生成/讀取TraceId)

package com.example.traceid.filter;
import com.example.traceid.util.TraceIdUtils;
import org.apache.commons.lang3.StringUtils;
import org.slf4j.MDC;
import org.springframework.core.Ordered;
import org.springframework.core.annotation.Order;
import org.springframework.stereotype.Component;
import javax.servlet.*;
import javax.servlet.http.HttpServletRequest;
import java.io.IOException;
/**
 * 無SkyWalking時(shí):請(qǐng)求入口生成/讀取TraceId,放入MDC
 * 優(yōu)先級(jí)最高,保證所有邏輯執(zhí)行前已有TraceId
 */
@Component
@Order(Ordered.HIGHEST_PRECEDENCE)
public class TraceIdMdcFilter implements Filter {
    @Override
    public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException {
        try {
            HttpServletRequest httpRequest = (HttpServletRequest) request;
            // 1. 優(yōu)先讀取上游傳遞的TraceId(網(wǎng)關(guān)/其他服務(wù))
            String traceId = httpRequest.getHeader(TraceIdUtils.TRACE_ID_HEADER_KEY);
            // 2. 上游無則生成新的
            if (StringUtils.isBlank(traceId)) {
                traceId = TraceIdUtils.generateTraceId();
            }
            // 3. 放入MDC,供日志讀取
            MDC.put(TraceIdUtils.TRACE_ID_MDC_KEY, traceId);
            // 4. 執(zhí)行后續(xù)邏輯
            chain.doFilter(request, response);
        } finally {
            // 核心:請(qǐng)求結(jié)束清除MDC,避免線程池復(fù)用導(dǎo)致TraceId錯(cuò)亂
            MDC.clear();
        }
    }
}

2.3 異步線程池配置(解決異步TraceId丟失)

package com.example.traceid.config;
import org.slf4j.MDC;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.core.task.TaskDecorator;
import org.springframework.scheduling.annotation.EnableAsync;
import org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor;
import java.util.Map;
import java.util.concurrent.Executor;
import java.util.concurrent.ThreadPoolExecutor;
/**
 * 無SkyWalking時(shí):異步線程池配置,傳遞MDC上下文
 */
@Configuration
@EnableAsync
public class AsyncTraceConfig {
    // 自定義TaskDecorator:復(fù)制父線程MDC到子線程
    private static class MdcTraceDecorator implements TaskDecorator {
        @Override
        public Runnable decorate(Runnable runnable) {
            Map<String, String> parentMdc = MDC.getCopyOfContextMap();
            return () -> {
                try {
                    if (parentMdc != null) {
                        MDC.setContextMap(parentMdc);
                    }
                    runnable.run();
                } finally {
                    MDC.clear(); // 子線程執(zhí)行完清除MDC
                }
            };
        }
    }
    // 全局異步線程池
    @Bean("asyncTraceExecutor")
    public Executor asyncTraceExecutor() {
        ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor();
        int core = Runtime.getRuntime().availableProcessors() * 2;
        executor.setCorePoolSize(core);
        executor.setMaxPoolSize(core * 2);
        executor.setQueueCapacity(200);
        executor.setThreadNamePrefix("async-trace-");
        executor.setTaskDecorator(new MdcTraceDecorator()); // 綁定裝飾器
        executor.setRejectedExecutionHandler(new ThreadPoolExecutor.CallerRunsPolicy());
        executor.setWaitForTasksToCompleteOnShutdown(true);
        executor.setAwaitTerminationSeconds(30);
        executor.initialize();
        return executor;
    }
}

2.4 微服務(wù)跨服務(wù)傳遞(Feign/RestTemplate攔截器)

2.4.1 Feign攔截器(微服務(wù)專屬)
package com.example.traceid.interceptor;
import com.example.traceid.util.TraceIdUtils;
import feign.RequestInterceptor;
import feign.RequestTemplate;
import org.springframework.stereotype.Component;
/**
 * 無SkyWalking時(shí):Feign調(diào)用傳遞TraceId
 */
@Component
public class FeignTraceInterceptor implements RequestInterceptor {
    @Override
    public void apply(RequestTemplate template) {
        String traceId = TraceIdUtils.getTraceId();
        if (!"UNKNOWN".equals(traceId)) {
            template.header(TraceIdUtils.TRACE_ID_HEADER_KEY, traceId);
        }
    }
}
2.4.2 RestTemplate攔截器(微服務(wù)專屬)
package com.example.traceid.config;
import com.example.traceid.util.TraceIdUtils;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.http.client.ClientHttpRequestInterceptor;
import org.springframework.web.client.RestTemplate;
import java.util.Collections;
/**
 * 無SkyWalking時(shí):RestTemplate傳遞TraceId
 */
@Configuration
public class RestTemplateTraceConfig {
    @Bean
    public RestTemplate restTemplate() {
        RestTemplate restTemplate = new RestTemplate();
        restTemplate.setInterceptors(Collections.singletonList((request, body, execution) -> {
            String traceId = TraceIdUtils.getTraceId();
            if (!"UNKNOWN".equals(traceId)) {
                request.getHeaders().add(TraceIdUtils.TRACE_ID_HEADER_KEY, traceId);
            }
            return execution.execute(request, body);
        }));
        return restTemplate;
    }
}

2.5 日志配置(logback-spring.xml)

<?xml version="1.0" encoding="UTF-8"?>
<configuration scan="true" scanPeriod="30 seconds">
    <contextName>traceid-no-skywalking</contextName>
    <!-- 控制臺(tái)輸出 -->
    <appender name="CONSOLE" class="ch.qos.logback.core.ConsoleAppender">
        <encoder>
            <charset>UTF-8</charset>
            <!-- 核心:%X{traceId}讀取MDC中的TraceId -->
            <pattern>%d{yyyy-MM-dd HH:mm:ss.SSS} [%thread] [%X{traceId}] %-5level %logger{50} - %msg%n</pattern>
        </encoder>
    </appender>
    <!-- 文件輸出 -->
    <appender name="FILE" class="ch.qos.logback.core.rolling.RollingFileAppender">
        <file>logs/app.log</file>
        <rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
            <fileNamePattern>logs/app.%d{yyyy-MM-dd}.log</fileNamePattern>
            <maxHistory>7</maxHistory>
            <maxFileSize>100MB</maxFileSize>
        </rollingPolicy>
        <encoder>
            <charset>UTF-8</charset>
            <pattern>%d{yyyy-MM-dd HH:mm:ss.SSS} [%thread] [%X{traceId}] %-5level %logger{50} - %msg%n</pattern>
        </encoder>
    </appender>
    <root level="INFO">
        <appender-ref ref="CONSOLE"/>
        <appender-ref ref="FILE"/>
    </root>
</configuration>

3. 無SkyWalking的核心驗(yàn)證

  • 同步接口:日志中[%X{traceId}]顯示自定義生成的TraceId;
  • 異步任務(wù):子線程日志TraceId與父線程一致;
  • 微服務(wù)調(diào)用:下游服務(wù)日志TraceId與上游一致;
  • 無任何額外中間件依賴,僅依賴Spring原生能力。

場(chǎng)景二:有SkyWalking的最優(yōu)實(shí)現(xiàn)

核心方案

復(fù)用SkyWalking TraceId + MDC綁定 + 上下文傳遞(異步/跨服務(wù))

核心差異

  • 無需自定義生成TraceId,直接復(fù)用SkyWalking的全局TraceId;
  • 日志中同時(shí)綁定SkyWalking TraceId,實(shí)現(xiàn)「日志TraceId=鏈路TraceId」;
  • 異步/跨服務(wù)場(chǎng)景需傳遞SkyWalking上下文,保證鏈路不中斷。

1. 依賴配置(拆分SpringBoot/SpringCloud)

1.1 SpringBoot單體項(xiàng)目(新增SkyWalking依賴)

<?xml version="1.0" encoding="UTF-8"?>
<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 https://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>
    <parent>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-parent</artifactId>
        <version>2.7.15</version>
        <relativePath/>
    </parent>
    <groupId>com.example</groupId>
    <artifactId>boot-traceid-with-skywalking</artifactId>
    <version>0.0.1-SNAPSHOT</version>
    <dependencies>
        <!-- 基礎(chǔ)依賴(同無SkyWalking) -->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>
        <dependency>
            <groupId>org.apache.commons</groupId>
            <artifactId>commons-lang3</artifactId>
            <version>3.14.0</version>
        </dependency>
        <!-- SkyWalking核心依賴 -->
        <dependency>
            <groupId>org.apache.skywalking</groupId>
            <artifactId>apm-toolkit-spring-boot-starter</artifactId>
            <version>8.16.0</version> <!-- 與SkyWalking OAP版本一致 -->
        </dependency>
        <!-- SkyWalking日志增強(qiáng):自動(dòng)綁定TraceId到MDC -->
        <dependency>
            <groupId>org.apache.skywalking</groupId>
            <artifactId>apm-toolkit-logback-1.x</artifactId>
            <version>8.16.0</version>
        </dependency>
    </dependencies>
    <build>
        <plugins>
            <plugin>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-maven-plugin</artifactId>
                <version>2.7.15</version>
            </plugin>
        </plugins>
    </build>
</project>

1.2 SpringCloud微服務(wù)項(xiàng)目(新增SkyWalking依賴)

<?xml version="1.0" encoding="UTF-8"?>
<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 https://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>
    <parent>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-parent</artifactId>
        <version>2.7.15</version>
        <relativePath/>
    </parent>
    <groupId>com.example</groupId>
    <artifactId>cloud-traceid-with-skywalking</artifactId>
    <version>0.0.1-SNAPSHOT</version>
    <dependencies>
        <!-- 基礎(chǔ)依賴(同無SkyWalking) -->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>
        <dependency>
            <groupId>org.apache.commons</groupId>
            <artifactId>commons-lang3</artifactId>
            <version>3.14.0</version>
        </dependency>
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-openfeign</artifactId>
        </dependency>
        <!-- SkyWalking核心依賴 -->
        <dependency>
            <groupId>org.apache.skywalking</groupId>
            <artifactId>apm-toolkit-spring-boot-starter</artifactId>
            <version>8.16.0</version>
        </dependency>
        <!-- SkyWalking Feign增強(qiáng):跨服務(wù)鏈路追蹤 -->
        <dependency>
            <groupId>org.apache.skywalking</groupId>
            <artifactId>apm-toolkit-feign</artifactId>
            <version>8.16.0</version>
        </dependency>
        <!-- SkyWalking日志增強(qiáng) -->
        <dependency>
            <groupId>org.apache.skywalking</groupId>
            <artifactId>apm-toolkit-logback-1.x</artifactId>
            <version>8.16.0</version>
        </dependency>
    </dependencies>
    <dependencyManagement>
        <dependencies>
            <dependency>
                <groupId>org.springframework.cloud</groupId>
                <artifactId>spring-cloud-dependencies</artifactId>
                <version>2021.0.5</version>
                <type>pom</type>
                <scope>import</scope>
            </dependency>
        </dependencies>
    </dependencyManagement>
    <build>
        <plugins>
            <plugin>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-maven-plugin</artifactId>
                <version>2.7.15</version>
            </plugin>
        </plugins>
    </build>
</project>

2. SkyWalking極簡(jiǎn)部署(Docker,中小型項(xiàng)目首選)

# 1. 拉取OAP和UI鏡像(版本與項(xiàng)目依賴一致)
docker pull apache/skywalking-oap-server:8.16.0
docker pull apache/skywalking-ui:8.16.0
# 2. 啟動(dòng)OAP(單節(jié)點(diǎn),H2存儲(chǔ),無需額外數(shù)據(jù)庫(kù))
docker run -d \
  --name skywalking-oap \
  -p 11800:11800 \ # Agent上報(bào)端口
  -p 12800:12800 \ # UI訪問OAP端口
  -e SW_STORAGE=h2 \
  apache/skywalking-oap-server:8.16.0
# 3. 啟動(dòng)UI(可視化界面,訪問http://localhost:8080)
docker run -d \
  --name skywalking-ui \
  -p 8080:8080 \
  --link skywalking-oap:oap \
  -e SW_OAP_ADDRESS=http://oap:12800 \
  apache/skywalking-ui:8.16.0

3. 核心代碼實(shí)現(xiàn)(有SkyWalking專屬)

3.1 TraceId工具類(復(fù)用SkyWalking TraceId)

package com.example.traceid.util;
import org.apache.commons.lang3.StringUtils;
import org.apache.skywalking.apm.toolkit.trace.TraceContext;
import org.slf4j.MDC;
/**
 * 有SkyWalking時(shí):復(fù)用其TraceId,無需自定義生成
 */
public class TraceIdUtils {
    // 復(fù)用SkyWalking的MDC Key(SW_TRACE_ID),也可自定義
    public static final String TRACE_ID_MDC_KEY = "SW_TRACE_ID";
    public static final String TRACE_ID_HEADER_KEY = "X-Trace-Id";
    /**
     * 獲取TraceId:優(yōu)先SkyWalking,兜底UNKNOWN
     */
    public static String getTraceId() {
        // SkyWalking原生TraceId
        String skyWalkingTraceId = TraceContext.traceId();
        if (StringUtils.isNotBlank(skyWalkingTraceId) && !"N/A".equals(skyWalkingTraceId)) {
            return skyWalkingTraceId;
        }
        // 兜底讀取MDC
        String mdcTraceId = MDC.get(TRACE_ID_MDC_KEY);
        return StringUtils.isBlank(mdcTraceId) ? "UNKNOWN" : mdcTraceId;
    }
    /**
     * 綁定SkyWalking TraceId到MDC(僅特殊場(chǎng)景用)
     */
    public static void bindSkyWalkingTraceIdToMdc() {
        String traceId = TraceContext.traceId();
        if (StringUtils.isNotBlank(traceId) && !"N/A".equals(traceId)) {
            MDC.put(TRACE_ID_MDC_KEY, traceId);
        }
    }
}

3.2 TraceId過濾器(簡(jiǎn)化:僅綁定SkyWalking TraceId到MDC)

package com.example.traceid.filter;
import com.example.traceid.util.TraceIdUtils;
import org.apache.skywalking.apm.toolkit.trace.TraceContext;
import org.slf4j.MDC;
import org.springframework.core.Ordered;
import org.springframework.core.annotation.Order;
import org.springframework.stereotype.Component;
import javax.servlet.*;
import java.io.IOException;
/**
 * 有SkyWalking時(shí):過濾器僅綁定其TraceId到MDC,無需生成
 */
@Component
@Order(Ordered.HIGHEST_PRECEDENCE)
public class TraceIdMdcFilter implements Filter {
    @Override
    public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException {
        try {
            // 綁定SkyWalking TraceId到MDC,供日志讀取
            TraceIdUtils.bindSkyWalkingTraceIdToMdc();
            chain.doFilter(request, response);
        } finally {
            MDC.clear();
            // 釋放SkyWalking上下文(避免內(nèi)存泄漏)
            TraceContext.release();
        }
    }
}

3.3 異步線程池配置(傳遞SkyWalking上下文)

package com.example.traceid.config;
import org.apache.skywalking.apm.toolkit.trace.TraceContext;
import org.slf4j.MDC;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.core.task.TaskDecorator;
import org.springframework.scheduling.annotation.EnableAsync;
import org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor;
import java.util.Map;
import java.util.concurrent.Executor;
import java.util.concurrent.ThreadPoolExecutor;
/**
 * 有SkyWalking時(shí):異步線程池傳遞MDC+SkyWalking上下文
 */
@Configuration
@EnableAsync
public class AsyncTraceConfig {
    private static class MdcTraceDecorator implements TaskDecorator {
        @Override
        public Runnable decorate(Runnable runnable) {
            // 復(fù)制父線程MDC和SkyWalking TraceId
            Map<String, String> parentMdc = MDC.getCopyOfContextMap();
            String parentSkyWalkingTraceId = TraceContext.traceId();
            return () -> {
                try {
                    // 子線程綁定MDC
                    if (parentMdc != null) {
                        MDC.setContextMap(parentMdc);
                    }
                    // 子線程綁定SkyWalking TraceId(核心:保證鏈路不中斷)
                    if (StringUtils.isNotBlank(parentSkyWalkingTraceId) && !"N/A".equals(parentSkyWalkingTraceId)) {
                        TraceContext.continueTrace(parentSkyWalkingTraceId);
                    }
                    runnable.run();
                } finally {
                    MDC.clear();
                    TraceContext.release(); // 釋放SkyWalking上下文
                }
            };
        }
    }
    @Bean("asyncTraceExecutor")
    public Executor asyncTraceExecutor() {
        ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor();
        int core = Runtime.getRuntime().availableProcessors() * 2;
        executor.setCorePoolSize(core);
        executor.setMaxPoolSize(core * 2);
        executor.setQueueCapacity(200);
        executor.setThreadNamePrefix("async-trace-");
        executor.setTaskDecorator(new MdcTraceDecorator());
        executor.setRejectedExecutionHandler(new ThreadPoolExecutor.CallerRunsPolicy());
        executor.initialize();
        return executor;
    }
}

3.4 日志配置(綁定SkyWalking TraceId)

<?xml version="1.0" encoding="UTF-8"?>
<configuration scan="true" scanPeriod="30 seconds">
    <!-- 引入SkyWalking默認(rèn)配置 -->
    <include resource="org/apache/skywalking/apm/toolkit/log/logback/default.xml"/>
    <contextName>traceid-with-skywalking</contextName>
    <appender name="CONSOLE" class="ch.qos.logback.core.ConsoleAppender">
        <encoder>
            <charset>UTF-8</charset>
            <!-- %X{SW_TRACE_ID}:SkyWalking原生TraceId -->
            <pattern>%d{yyyy-MM-dd HH:mm:ss.SSS} [%thread] [%X{SW_TRACE_ID}] %-5level %logger{50} - %msg%n</pattern>
        </encoder>
    </appender>
    <appender name="FILE" class="ch.qos.logback.core.rolling.RollingFileAppender">
        <file>logs/app.log</file>
        <rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
            <fileNamePattern>logs/app.%d{yyyy-MM-dd}.log</fileNamePattern>
            <maxHistory>7</maxHistory>
            <maxFileSize>100MB</maxFileSize>
        </rollingPolicy>
        <encoder>
            <charset>UTF-8</charset>
            <pattern>%d{yyyy-MM-dd HH:mm:ss.SSS} [%thread] [%X{SW_TRACE_ID}] %-5level %logger{50} - %msg%n</pattern>
        </encoder>
    </appender>
    <root level="INFO">
        <appender-ref ref="CONSOLE"/>
        <appender-ref ref="FILE"/>
    </root>
</configuration>

3.5 項(xiàng)目掛載SkyWalking Agent(核心步驟)

啟動(dòng)項(xiàng)目時(shí)添加JVM參數(shù)(本地/生產(chǎn)通用):

# 本地IDEA VM Options
-javaagent:/path/to/skywalking-agent/skywalking-agent.jar
-DSW_AGENT_NAME=boot-traceid-demo # 服務(wù)名(UI中顯示)
-DSW_AGENT_COLLECTOR_BACKEND_SERVICES=127.0.0.1:11800 # OAP地址
# 生產(chǎn)Jar啟動(dòng)
java -javaagent:/path/to/skywalking-agent/skywalking-agent.jar \
  -DSW_AGENT_NAME=cloud-traceid-demo \
  -DSW_AGENT_COLLECTOR_BACKEND_SERVICES=192.168.1.100:11800 \
  -jar app.jar

4. 有SkyWalking的核心驗(yàn)證

  • 日志中[%X{SW_TRACE_ID}]顯示SkyWalking的全局TraceId;
  • 異步任務(wù):子線程TraceId與父線程一致,SkyWalking UI可看到異步鏈路;
  • 微服務(wù)調(diào)用:上下游TraceId一致,SkyWalking UI可看到跨服務(wù)完整鏈路;
  • 訪問SkyWalking UI(http://localhost:8080),可通過TraceId搜索整條鏈路。

核心差異總結(jié)

維度無SkyWalking(純自研)有SkyWalking(復(fù)用TraceId)
TraceId生成自定義(UUID/雪花ID)復(fù)用SkyWalking全局TraceId(無需自定義)
核心目標(biāo)日志攜帶TraceId,定位問題日志+可視化鏈路統(tǒng)一,支持跨服務(wù)/異步鏈路分析
運(yùn)維成本0(僅代碼)低(單節(jié)點(diǎn)Docker部署OAP+UI)
異步/跨服務(wù)處理僅傳遞MDC上下文傳遞MDC+SkyWalking上下文(保證鏈路不中斷)
日志配置讀取自定義MDC Key(traceId)讀取SkyWalking MDC Key(SW_TRACE_ID)

到此這篇關(guān)于SpringBoot集成TraceId的方案詳解(追蹤ID)的文章就介紹到這了,更多相關(guān)SpringBoot集成TraceId內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!

相關(guān)文章

  • 基于swagger參數(shù)與實(shí)體中參數(shù)不一致的原因分析

    基于swagger參數(shù)與實(shí)體中參數(shù)不一致的原因分析

    這篇文章主要介紹了基于swagger參數(shù)與實(shí)體中參數(shù)不一致的原因分析,具有很好的參考價(jià)值,希望對(duì)大家有所幫助,如有錯(cuò)誤或未考慮完全的地方,望不吝賜教
    2023-11-11
  • Windows下Java+MyBatis框架+MySQL的開發(fā)環(huán)境搭建教程

    Windows下Java+MyBatis框架+MySQL的開發(fā)環(huán)境搭建教程

    這篇文章主要介紹了Windows下Java+MyBatis框架+MySQL的開發(fā)環(huán)境搭建教程,Mybatis對(duì)普通SQL語句的支持非常好,需要的朋友可以參考下
    2016-04-04
  • java多線程讀取多個(gè)文件的方法

    java多線程讀取多個(gè)文件的方法

    這篇文章主要為大家詳細(xì)介紹了java多線程讀取多個(gè)文件的方法,具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下
    2019-08-08
  • Java中Socket用法詳解

    Java中Socket用法詳解

    本文詳細(xì)講解了Java中Socket的用法,文中通過示例代碼介紹的非常詳細(xì)。對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧
    2021-12-12
  • 淺析Java和Scala中的Future

    淺析Java和Scala中的Future

    這篇文章主要介紹了Java和Scala中的Future的相關(guān)資料,需要的朋友可以參考下
    2017-10-10
  • Spring框架中部署log4j.xml的詳細(xì)步驟

    Spring框架中部署log4j.xml的詳細(xì)步驟

    Log4j是一個(gè)常用的日志記錄工具,它可以幫助我們記錄應(yīng)用程序的運(yùn)行日志并進(jìn)行靈活的配置,在Spring框架中,我們可以很方便地部署log4j.xml配置文件來管理日志記錄,這篇文章主要介紹了Spring框架中部署log4j.xml的詳細(xì)步驟并提供相應(yīng)的代碼示例,需要的朋友可以參考下
    2023-09-09
  • JAVA?SSE接口開發(fā)中的Spring?Security與異步線程池配置方法

    JAVA?SSE接口開發(fā)中的Spring?Security與異步線程池配置方法

    本文詳細(xì)描述了在使用SpringSecurity和異步線程池進(jìn)行SSE接口開發(fā)時(shí)遇到的兩個(gè)問題:AccessDeniedException異常和SimpleAsyncTaskExecutor警告,文章還介紹了線程池參數(shù)的科學(xué)估算方法,并適用于SpringBoot/SpringMVC的SSE接口生產(chǎn)環(huán)境配置,感興趣的朋友一起看看吧
    2025-12-12
  • 簡(jiǎn)單介紹區(qū)分applet和application的方法

    簡(jiǎn)單介紹區(qū)分applet和application的方法

    applet和application都是Java語言編寫出來的應(yīng)用程序,本文簡(jiǎn)單介紹了二者的不同之處,需要的朋友可以參考下
    2017-09-09
  • Java?InheritableThreadLocal使用示例詳解

    Java?InheritableThreadLocal使用示例詳解

    InheritableThreadLocal繼承了ThreadLocal,此類擴(kuò)展了ThreadLocal以提供從父線程到子線程的值的繼承:當(dāng)創(chuàng)建子線程時(shí),子線程接收父線程具有的所有可繼承線程局部變量的初始值。?通常子線程的值與父線程的值是一致的
    2022-09-09
  • 一文盤點(diǎn)Java中常見內(nèi)存泄漏場(chǎng)景與解決方法

    一文盤點(diǎn)Java中常見內(nèi)存泄漏場(chǎng)景與解決方法

    內(nèi)存泄漏 是指對(duì)象 已經(jīng)不再被程序使用,但因?yàn)槟承┰?nbsp;無法被垃圾回收器回收,長(zhǎng)期占用內(nèi)存,最終可能引發(fā)?OOM,本文會(huì)介紹常見的幾類內(nèi)存泄漏場(chǎng)景,大家可以避免一下
    2025-12-12

最新評(píng)論

安福县| 湟中县| 万宁市| 横峰县| 正安县| 陇南市| 宁河县| 西和县| 尉犁县| 涪陵区| 临湘市| 汶川县| 富裕县| 新巴尔虎左旗| 桂东县| 栖霞市| 突泉县| 双辽市| 疏附县| 枣庄市| 东台市| 老河口市| 中方县| 三河市| 华阴市| 天气| 天气| 吉木乃县| 延吉市| 杂多县| 平塘县| 博野县| 保康县| 晋中市| 邯郸县| 旺苍县| 莒南县| 西华县| 邵武市| 长葛市| 扬州市|