本文在提供完整代码示例,可见https://github.com/khalidzk/SpringBoot-Tutorialstutorial-springboot/tutorial-trace/tutorial-trace-01-skywalking目录。

1.概述

本文使用的软件版本

  • apache/skywalking-oap-server:10.2.0
  • apache/skywalking-ui:10.2.0
  • apache-skywalking-java-agent-9.5.0

如果还没了解过分布式链路追踪 SkyWalking,建议先阅读下 《SkyWalking 初探》 文章。

可能会有大家会有疑惑,Spring Boot 不是一个单体应用么,为什么可以使用 SkyWalking 进行分布式链路追踪呢?其实这里有一个误区!即使是一个 Spring Boot 单体应用,我们一般可能会和以下服务打交道:

  • 关系数据库,例如说 MySQL、Oracle、SQLServer、PostgreSQL 等等。
  • 文档数据库,例如说 MongoDB 等等。
  • 缓存数据库,例如说 Redis、Memcached 等等。
  • 外部三方服务,例如说微信公众号、微信支付、支付宝支付、短信平台等等。

那么即使是一个 Spring Boot 单体应用,就已经涉及到分布在不同进程中的服务。此时,就已经满足使用 SkyWalking 进行分布式链路追踪的条件,同时也是非常有必要的。例如说,我们线上某个 API 接口访问非常慢,可以通过 SkyWalking 来排查,是因为 MySQL 查询比较慢呢,还是调用的第三方服务比较慢。

2.SpringMVC 示例

示例代码仓库地址:tutorial-trace-01-skywalking-springmvc

我们来搭建一个 SkyWalking 对 SpringMVC 的 API 接口的链路追踪。该链路通过如下插件实现收集:

2.1.引入依赖

pom.xml文件中,引入相关依赖。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
<?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 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.2.1.RELEASE</version>
<relativePath/> <!-- lookup parent from repository -->
</parent>
<modelVersion>4.0.0</modelVersion>

<artifactId>tutorial-trace-01-skywalking-springmvc</artifactId>

<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
</dependencies>

</project>

2.2.配置文件

1
2
server:
port: 44079

2.3.DemoController

1
2
3
4
5
6
7
8
9
10
11
12
13
14
@RestController
@RequestMapping("/demo")
public class DemoController {

@GetMapping("/echo")
public String echo() {
return "SkyWalking";
}

@GetMapping("/testIgnore")
public String hello() {
return "SkyWalking TestIgnore!";
}
}

2.4.TutorialTrace01SkyWalkingSpringMvcApplication

1
2
3
4
5
6
@SpringBootApplication
public class TutorialTrace01SkyWalkingSpringMvcApplication {
public static void main(String[] args) {
SpringApplication.run(TutorialTrace01SkyWalkingSpringMvcApplication.class, args);
}
}

2.5.IDEA 配置

然后启动该 Spring Boot 应用。如果说控制台打印如下日志,说明 SkyWalking Agent 基本加载成功:

1
2
DEBUG 2025-08-22 23:43:05.892 main AgentPackagePath : The beacon class location is jar:file:/E:/work/devenv/skywalking/skywalking-agent/skywalking-agent.jar!/org/apache/skywalking/apm/agent/core/boot/AgentPackagePath.class. 
INFO 2025-08-22 23:43:05.894 main SnifferConfigInitializer : Config file found in E:\work\devenv\skywalking\skywalking-agent\config\agent.config.

2.6.简单测试

  1. 首先,使用浏览器,访问下 http://127.0.0.1:44079/demo/echo 地址,请求下 Spring Boot 应用提供的 API。因为,我们要追踪下该链路。

  1. 然后,继续使用浏览器,打开 http://127.0.0.1:8080/ 地址,进入 SkyWalking UI 界面。如下图所示:

3.忽略部分 URL 的追踪

示例代码仓库地址:tutorial-trace-01-skywalking-springmvc

官方文档地址:https://skywalking.apache.org/docs/skywalking-java/latest/en/setup/service-agent/java-agent/agent-optional-plugins/trace-ignore-plugin/

在「2. SpringMVC 示例」小节中,我们已经实现了对 SpringMVC 提供的 HTTP API 接口的链路追踪。但是,我们可能希望忽略部分特殊 URL 的追踪,例如说,健康检查的 HTTP API。

所以,我们可以使用 SkyWalking 提供 trace-ignore-plugin 插件,可以实现忽略部分 URL 的追踪。

我们无需单独搭建项目,而是直接使用tutorial-trace-01-skywalking-springmvc项目即可。

3.1 复制插件

trace-ignore-plugin插件,在skywalking-agen/optional-plugins目录下,是可选插件,所以我们需要复制到 plugins 目录下。

3.2.配置文件

trace-ignore-plugin插件,读取apm-trace-ignore-plugin.config配置文件,默认情况下不存在,所以我们需要进行创建并配置。命令行操作如下:

1
2
3
# 创建 apm-trace-ignore-plugin.config 配置文件,并进行设置
cd /opt/skywalking/skywalking-agent
vi config/apm-trace-ignore-plugin.config

配置文件内容如下:

1
2
3
4
5
6
7
# If the operation name of the first span is matching, this segment should be ignored
# ant path match style
# /path/? Match any single character
# /path/* Match any number of characters
# /path/** Match any number of characters and support multilevel directories
# Multiple path comma separation, like trace.ignore_path=/eureka/**,/consul/**
trace.ignore_path=${SW_AGENT_TRACE_IGNORE_PATH:/eureka/**}
  • trace.ignore_path配置项,设置忽略的 URL 路径,基于 Ant 风格路径表达式
  • 这里,我们配置了读取环境变量SW_AGENT_TRACE_IGNORE_PATH,这样方便我们自定义。

3.3.IDEA 配置

然后启动该 Spring Boot 应用。

3.4.简单测试

  1. 首先,使用浏览器,访问下 http://127.0.0.1:44079/demo/testIgnore 地址,请求下 Spring Boot 应用提供的 API。因为,我们要追踪下该链路。

  1. 查看 SkyWaking Agent 日志,可以看到该 URL 的链路追踪被忽略日志。操作命令如下:
1
2
3
4
5
6
7
8
# 查看当前所在目录
cd /opt/skywalking/skywalking-agent/logs

# 查看 SkyWaking Agent 日志,然后搜 Ignore 关键字
cat skywalking-api.log |grep "IgnoreConfigInitializer"
# 日志示例
INFO 2025-08-23 02:34:10.492 main IgnoreConfigInitializer : Ignore config file found in E:\work\devenv\skywalking\skywalking-agent\config\apm-trace-ignore-plugin.config.

  1. 在 SkyWalking UI 的查看链路追踪的界面。如下图所示:

你会发现有一堆的GET:/demo/testIgnore,结果竟然是没生效。

注意看前缀GET:,可以发现我们配置SW_AGENT_TRACE_IGNORE_PATH的内容少了。好了,把前缀加上

再来看SkyWalking UI 的查看链路追踪的界面,整个世界都安静了!!!

SkyWalking版本不一样,端点长得也不一样,一定要在SkyWalking UI 的查看链路追踪的界面看清楚!!!较新的版本有前缀GET:

4.Mysql 示例

示例代码仓库地址:tutorial-trace-01-skywalking-mysql

我们来搭建一个 SkyWalking 对 MySQL 操作的链路追踪。该链路通过如下插件实现收集:

4.1.引入依赖

pom.xml文件中,引入相关依赖。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
<?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 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.2.2.RELEASE</version>
<relativePath/> <!-- lookup parent from repository -->
</parent>
<modelVersion>4.0.0</modelVersion>

<artifactId>tutorial-trace-01-skywalking-mysql</artifactId>

<dependencies>
<!-- 实现对 SpringMVC 的自动化配置 -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<!-- 实现对数据库连接池的自动化配置 -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-jdbc</artifactId>
</dependency>
<dependency> <!-- 本示例,我们使用 MySQL -->
<groupId>com.mysql</groupId>
<artifactId>mysql-connector-j</artifactId>
<version>9.1.0</version>
</dependency>
</dependencies>

<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
<configuration>
<fork>true</fork>
</configuration>
</plugin>
</plugins>
</build>
</project>

4.2.配置文件

1
2
3
4
5
6
7
8
9
10
server:
port: 44079

spring:
# datasource 数据源配置内容
datasource:
url: jdbc:mysql://${SPRINGBOOT_TUTORIALS_MYSQL_HOST}:3306/springboot_tutorials?useSSL=false&serverTimezone=Asia/Shanghai&allowPublicKeyRetrieval=true&nullCatalogMeansCurrent=true&rewriteBatchedStatements=true # MySQL Connector/J 8.X 连接的示例
driver-class-name: com.mysql.cj.jdbc.Driver
username: springboot_tutorials
password: ${SPRINGBOOT_TUTORIALS_MYSQL_PASSWORD}

建表sql,见springboot_tutorials.sql

1
2
3
4
5
6
7
8
9
10
11
12
DROP TABLE IF EXISTS `t_user`;
CREATE TABLE `t_user` (
`id` int NOT NULL AUTO_INCREMENT COMMENT '主键自增',
`username` varchar(50) CHARACTER SET utf8mb3 COLLATE utf8mb3_general_ci NOT NULL COMMENT '用户名',
`password` varchar(50) CHARACTER SET utf8mb3 COLLATE utf8mb3_general_ci NOT NULL COMMENT '密码',
PRIMARY KEY (`id`) USING BTREE
) ENGINE = InnoDB AUTO_INCREMENT = 2 CHARACTER SET = utf8mb3 COLLATE = utf8mb3_general_ci COMMENT = '用户表' ROW_FORMAT = Dynamic;

-- ----------------------------
-- Records of t_user
-- ----------------------------
INSERT INTO `t_user` VALUES (1, 'khalidlife', 'wuwen');

4.3.DemoController

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
@RestController
@RequestMapping("/demo")
public class DemoController {
@Autowired
private JdbcTemplate template;

@GetMapping("/mysql")
public String mysql() {
this.selectById(1);
return "mysql";
}

public Object selectById(Integer id) {
return template.queryForObject("SELECT id, username, password FROM t_user WHERE id = ?",
new BeanPropertyRowMapper<>(Object.class), // 结果转换成对应的对象。Object 理论来说是 UserDO.class ,这里偷懒了。
id);
}
}

4.4.TutorialTrace01SkyWalkingSpringMvcApplication

1
2
3
4
5
6
@SpringBootApplication
public class TutorialTrace01SkyWalkingMysqlApplication {
public static void main(String[] args) {
SpringApplication.run(TutorialTrace01SkyWalkingMysqlApplication.class, args);
}
}

4.5.IDEA 配置

然后启动该 Spring Boot 应用。

4.6.简单测试

  1. 首先,使用浏览器,访问下 http://127.0.0.1:44079/demo/msyql 地址,请求下 Spring Boot 应用提供的 API。因为,我们要追踪下该链路。

  1. 然后,继续使用浏览器,打开 http://127.0.0.1:8080/ 地址,进入 SkyWalking UI 界面。如下图所示:

  1. 之后,点击「拓扑图」菜单,进入查看拓扑图的界面,可以看到 MySQL 小方块。如下图所示:

  1. 再之后,点击「追踪」菜单,进入查看链路数据的界面。如下图所示:

这里,我们暂时无法看到 SQL 的数据参数,可以通过修改config/agent.config配置文件,将plugin.mysql.trace_sql_parameters配置项,设置为 true 。例如:

1
2
# If set to true, the parameters of the sql (typically `java.sql.PreparedStatement`) would be collected.
plugin.jdbc.trace_sql_parameters=${SW_JDBC_TRACE_SQL_PARAMETERS:true}

当然,也可以通过SW_JDBC_TRACE_SQL_PARAMETERS环境变量。

5.Redis 示例

示例代码仓库地址:tutorial-trace-01-skywalking-redis

我们来搭建一个 SkyWalking 对 MySQL 操作的链路追踪。该链路通过如下插件实现收集:

5.1.引入依赖

pom.xml文件中,引入相关依赖。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
<?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 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.2.2.RELEASE</version>
<relativePath/> <!-- lookup parent from repository -->
</parent>
<modelVersion>4.0.0</modelVersion>

<artifactId>tutorial-trace-01-skywalking-redis</artifactId>

<dependencies>
<!-- 实现对 SpringMVC 的自动化配置 -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>

<!-- 实现对 Spring Data Redis 的自动化配置 -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-redis</artifactId>
<exclusions>
<!-- 去掉对 Lettuce 的依赖,因为 Spring Boot 优先使用 Lettuce 作为 Redis 客户端 -->
<exclusion>
<groupId>io.lettuce</groupId>
<artifactId>lettuce-core</artifactId>
</exclusion>
</exclusions>
</dependency>

<!-- 引入 Jedis 的依赖,这样 Spring Boot 实现对 Jedis 的自动化配置 -->
<dependency>
<groupId>redis.clients</groupId>
<artifactId>jedis</artifactId>
</dependency>
</dependencies>

<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
<configuration>
<fork>true</fork>
</configuration>
</plugin>
</plugins>
</build>
</project>

4.2.配置文件

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
server:
port: 44079

spring:
# 对应 RedisProperties 类
redis:
host: 127.0.0.1
port: 6379
password: # Redis 服务器密码,默认为空。生产中,一定要设置 Redis 密码!
database: 0 # Redis 数据库号,默认为 0 。
timeout: 0 # Redis 连接超时时间,单位:毫秒。
# 对应 RedisProperties.Jedis 内部类
jedis:
pool:
max-active: 8 # 连接池最大连接数,默认为 8 。使用负数表示没有限制。
max-idle: 8 # 默认连接数最小空闲的连接数,默认为 8 。使用负数表示没有限制。
min-idle: 0 # 默认连接池最小空闲的连接数,默认为 0 。允许设置 0 和 正数。
max-wait: -1 # 连接池最大阻塞等待时间,单位:毫秒。默认为 -1 ,表示不限制。

4.3.DemoController

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
@RestController
@RequestMapping("/demo")
public class DemoController {

@Autowired
private StringRedisTemplate redisTemplate;

@GetMapping("/redis")
public String redis() {
this.get("demo");
return "redis";
}

public void get(String key) {
redisTemplate.opsForValue().get(key);
}

}

4.4.TutorialTrace01SkyWalkingSpringMvcApplication

1
2
3
4
5
6
7
8
@SpringBootApplication
public class TutorialTrace01SkyWalkingRedisApplication {

public static void main(String[] args) {
SpringApplication.run(TutorialTrace01SkyWalkingRedisApplication.class, args);
}

}

4.5.IDEA 配置

然后启动该 Spring Boot 应用。

4.6.简单测试

  1. 首先,使用浏览器,访问下 http://127.0.0.1:44079/demo/redis 地址,请求下 Spring Boot 应用提供的 API。因为,我们要追踪下该链路。

  1. 然后,继续使用浏览器,打开 http://127.0.0.1:8080/ 地址,进入 SkyWalking UI 界面。如下图所示:

  1. 之后,点击「拓扑图」菜单,进入查看拓扑图的界面,可以看到 Redis 小方块。如下图所示:

  1. 再之后,点击「追踪」菜单,进入查看链路数据的界面。如下图所示:

不过没有看到 Redis 操作的具体参数。因为 Spring Data Redis 会把提前具体参数转换成二进制数组,导致 jedis-2.x-plugin 插件的JedisMethodInterceptor不进行收集。代码如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
// JedisMethodInterceptor.java
private Optional<String> getKey(Object[] allArguments) {
if (!JedisPluginConfig.Plugin.Jedis.TRACE_REDIS_PARAMETERS) {
return Optional.empty();
}
if (allArguments.length == 0) {
return Optional.empty();
}
Object argument = allArguments[0];
// include null
if (!(argument instanceof String)) {// 非String 类型,不进行收集
return Optional.empty();
}
return Optional.of(StringUtil.cut((String) argument, JedisPluginConfig.Plugin.Jedis.REDIS_PARAMETER_MAX_LENGTH));
}

6.MongoDB 示例

待续

7.Elasticsearch 示例

待续

8.RocketMQ 示例

待续

9.Kafka 示例

待续

10.RabbitMQ 示例

待续

11.ActiveMQ 示例

待续

12.日志框架示例

待续

13.自定义追踪方法

待续

14.OpenTracing 示例

待续

15.Spring 异步任务示例

待续

16.Dubbo 示例

待续