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

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

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

一、TraceId 是什么?

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

場景一:無SkyWalking的最優(yōu)實現(xiàn)

核心方案

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

適用場景

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

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

1.1 SpringBoot單體項目依賴

<?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>
        <!-- 測試依賴(非核心) -->
        <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微服務項目依賴

<?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> <!-- 對應Cloud 2021.0.x -->
        <relativePath/>
    </parent>
    <groupId>com.example</groupId>
    <artifactId>cloud-traceid-no-skywalking</artifactId>
    <version>0.0.1-SNAPSHOT</version>
    <dependencies>
        <!-- 基礎依賴(同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>
        <!-- 微服務核心:OpenFeign -->
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-openfeign</artifactId>
        </dependency>
        <!-- 測試依賴 -->
        <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. 核心代碼實現(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時:自定義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ā)用,單機/低并發(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(默認,無需額外依賴)
        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;
    }
    /**
     * 手動設置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過濾器(請求入口生成/讀取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時:請求入口生成/讀取TraceId,放入MDC
 * 優(yōu)先級最高,保證所有邏輯執(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)關/其他服務)
            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 {
            // 核心:請求結束清除MDC,避免線程池復用導致TraceId錯亂
            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時:異步線程池配置,傳遞MDC上下文
 */
@Configuration
@EnableAsync
public class AsyncTraceConfig {
    // 自定義TaskDecorator:復制父線程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 微服務跨服務傳遞(Feign/RestTemplate攔截器)

2.4.1 Feign攔截器(微服務專屬)
package com.example.traceid.interceptor;
import com.example.traceid.util.TraceIdUtils;
import feign.RequestInterceptor;
import feign.RequestTemplate;
import org.springframework.stereotype.Component;
/**
 * 無SkyWalking時:Feign調用傳遞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攔截器(微服務專屬)
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時: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>
    <!-- 控制臺輸出 -->
    <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的核心驗證

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

場景二:有SkyWalking的最優(yōu)實現(xiàn)

核心方案

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

核心差異

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

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

1.1 SpringBoot單體項目(新增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>
        <!-- 基礎依賴(同無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日志增強:自動綁定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微服務項目(新增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>
        <!-- 基礎依賴(同無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增強:跨服務鏈路追蹤 -->
        <dependency>
            <groupId>org.apache.skywalking</groupId>
            <artifactId>apm-toolkit-feign</artifactId>
            <version>8.16.0</version>
        </dependency>
        <!-- SkyWalking日志增強 -->
        <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極簡部署(Docker,中小型項目首選)

# 1. 拉取OAP和UI鏡像(版本與項目依賴一致)
docker pull apache/skywalking-oap-server:8.16.0
docker pull apache/skywalking-ui:8.16.0
# 2. 啟動OAP(單節(jié)點,H2存儲,無需額外數(shù)據(jù)庫)
docker run -d \
  --name skywalking-oap \
  -p 11800:11800 \ # Agent上報端口
  -p 12800:12800 \ # UI訪問OAP端口
  -e SW_STORAGE=h2 \
  apache/skywalking-oap-server:8.16.0
# 3. 啟動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. 核心代碼實現(xiàn)(有SkyWalking專屬)

3.1 TraceId工具類(復用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時:復用其TraceId,無需自定義生成
 */
public class TraceIdUtils {
    // 復用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(僅特殊場景用)
     */
    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過濾器(簡化:僅綁定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時:過濾器僅綁定其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上下文(避免內存泄漏)
            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時:異步線程池傳遞MDC+SkyWalking上下文
 */
@Configuration
@EnableAsync
public class AsyncTraceConfig {
    private static class MdcTraceDecorator implements TaskDecorator {
        @Override
        public Runnable decorate(Runnable runnable) {
            // 復制父線程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默認配置 -->
    <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 項目掛載SkyWalking Agent(核心步驟)

啟動項目時添加JVM參數(shù)(本地/生產通用):

# 本地IDEA VM Options
-javaagent:/path/to/skywalking-agent/skywalking-agent.jar
-DSW_AGENT_NAME=boot-traceid-demo # 服務名(UI中顯示)
-DSW_AGENT_COLLECTOR_BACKEND_SERVICES=127.0.0.1:11800 # OAP地址
# 生產Jar啟動
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的核心驗證

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

核心差異總結

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

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

相關文章

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

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

    這篇文章主要介紹了基于swagger參數(shù)與實體中參數(shù)不一致的原因分析,具有很好的參考價值,希望對大家有所幫助,如有錯誤或未考慮完全的地方,望不吝賜教
    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對普通SQL語句的支持非常好,需要的朋友可以參考下
    2016-04-04
  • java多線程讀取多個文件的方法

    java多線程讀取多個文件的方法

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

    Java中Socket用法詳解

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

    淺析Java和Scala中的Future

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

    Spring框架中部署log4j.xml的詳細步驟

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

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

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

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

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

    Java?InheritableThreadLocal使用示例詳解

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

    一文盤點Java中常見內存泄漏場景與解決方法

    內存泄漏 是指對象 已經(jīng)不再被程序使用,但因為某些原因 無法被垃圾回收器回收,長期占用內存,最終可能引發(fā)?OOM,本文會介紹常見的幾類內存泄漏場景,大家可以避免一下
    2025-12-12

最新評論

新竹市| 木里| 渭源县| 邵武市| 拉孜县| 西畴县| 屏边| 蒲城县| 河曲县| 石柱| 东源县| 桐城市| 舞阳县| 咸丰县| 运城市| 拉萨市| 泽库县| 新泰市| 泽普县| 揭西县| 昌江| 呼图壁县| 新晃| 萝北县| 重庆市| 古交市| 金溪县| 弥渡县| 彰化县| 华安县| 特克斯县| 咸阳市| 丰镇市| 绥江县| 贡嘎县| 洮南市| 墨竹工卡县| 修水县| 枣强县| 松滋市| 溧阳市|