1.构建一个Sleuth-Remote项目
(1)添加Maven依赖
关键:openfeign依赖
<?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">
<modelVersion>4.0.0</modelVersion>
<groupId>gdut.ff</groupId>
<artifactId>Sleuth-Remote</artifactId>
<version>1.0-SNAPSHOT</version>
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.3.12.RELEASE</version>
</parent>
<properties>
<maven.compiler.source>8</maven.compiler.source>
<maven.compiler.target>8</maven.compiler.target>
<springcloud-version>Hoxton.SR8</springcloud-version>
</properties>
<dependencies>
<!--openfein的依赖-->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-openfeign</artifactId>
</dependency>
</dependencies>
<dependencyManagement>
<dependencies>
<dependency>
<!--springcloud依赖-->
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-dependencies</artifactId>
<version>${springcloud-version}</version>
<type>pom</type>
<scope>import</scope>
</dependency>
</dependencies>
</dependencyManagement>
</project>
(2)定义远程接口
关键:这里我直接指定了远程接口调用的地址。
package gdut.remote;
import org.springframework.cloud.openfeign.FeignClient;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestParam;
@FeignClient(name = "sleuth-remote", url = "http://localhost:8082/sleuthRemote")
public interface SleuthRemoteService {
@PostMapping("/name")
public String name(@RequestParam("name") String name);
}
2.构建一个Sleuth项目
(1)添加Maven依赖
关键:添加sleuth依赖
<?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">
<modelVersion>4.0.0</modelVersion>
<groupId>gdut.ff</groupId>
<artifactId>Sleuth</artifactId>
<version>1.0-SNAPSHOT</version>
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.3.12.RELEASE</version>
</parent>
<properties>
<maven.compiler.source>8</maven.compiler.source>
<maven.compiler.target>8</maven.compiler.target>
<springcloud-version>Hoxton.SR8</springcloud-version>
</properties>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>cn.hutool</groupId>
<artifactId>hutool-all</artifactId>
<version>5.7.5</version>
</dependency>
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<version>1.18.4</version>
</dependency>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.13</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-sleuth</artifactId>
</dependency>
<dependency>
<groupId>gdut.ff</groupId>
<artifactId>Sleuth-Remote</artifactId>
<version>1.0-SNAPSHOT</version>
</dependency>
</dependencies>
<dependencyManagement>
<dependencies>
<dependency>
<!--springcloud依赖-->
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-dependencies</artifactId>
<version>${springcloud-version}</version>
<type>pom</type>
<scope>import</scope>
</dependency>
</dependencies>
</dependencyManagement>
</project>
(2)application.yaml配置
关键:logging.level.org.springframework.web.servlet.DispatcherServlet=DEBUG
spring:
application:
name: sleuth
server:
port: 8082
logging:
level:
org:
springframework:
web:
servlet:
DispatcherServlet: DEBUG
(3)远程接口实现
关键:private static Logger log = LoggerFactory.getLogger(SleuthRemoteServiceImpl.class);
package gdut.service;
import gdut.remote.SleuthRemoteService;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;
@RestController
@RequestMapping("/sleuthRemote")
public class SleuthRemoteServiceImpl implements SleuthRemoteService {
private static Logger log = LoggerFactory.getLogger(SleuthRemoteServiceImpl.class);
@Override
public String name(String name) {
log.info("name is: {}", name);
return name;
}
}
(4)启动类
@SpringBootApplication(proxyBeanMethods = false)
@ComponentScan("gdut")
@EnableFeignClients
public class SleuthApplication {
public static void main(String[] args) {
SpringApplication.run(SleuthApplication.class, args);
}
}
3.测试
http://localhost:8082/sleuthRemote/name?name=liufeifei
控制台输出:
2022-12-31 21:39:38.036 DEBUG [sleuth,81c6ac35a35926ff,81c6ac35a35926ff,true] 1184 --- [nio-8082-exec-2] o.s.web.servlet.DispatcherServlet : POST "/sleuthRemote/name?name=liufeifei", parameters={masked}
2022-12-31 21:39:38.089 INFO [sleuth,81c6ac35a35926ff,81c6ac35a35926ff,true] 1184 --- [nio-8082-exec-2] gdut.service.SleuthRemoteServiceImpl : name is: liufeifei
2022-12-31 21:39:38.146 DEBUG [sleuth,81c6ac35a35926ff,81c6ac35a35926ff,true] 1184 --- [nio-8082-exec-2] o.s.web.servlet.DispatcherServlet : Completed 200 OK
4.远程服务调用实现链路追踪
以下是在一个新的SpringBoot服务
(1)添加以下Maven依赖
<!--openfein的依赖-->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-openfeign</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-sleuth</artifactId>
</dependency>
<dependency>
<groupId>gdut.ff</groupId>
<artifactId>Sleuth-Remote</artifactId>
<version>1.0-SNAPSHOT</version>
</dependency>
<dependencyManagement>
<dependencies>
<dependency>
<!--springcloud依赖-->
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-dependencies</artifactId>
<version>${springcloud-version}</version>
<type>pom</type>
<scope>import</scope>
</dependency>
</dependencies>
</dependencyManagement>
(2)定义Executor
分别创建了一个JDK类型的Executor和Spring类型的Executor。
package gdut.config;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.scheduling.concurrent.CustomizableThreadFactory;
import org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor;
import java.util.concurrent.ArrayBlockingQueue;
import java.util.concurrent.Executor;
import java.util.concurrent.ThreadPoolExecutor;
import java.util.concurrent.TimeUnit;
@Configuration
public class ExecutorConfig {
@Bean
public Executor customExecutor() {
ThreadPoolTaskExecutor threadPoolTaskExecutor = new ThreadPoolTaskExecutor();
threadPoolTaskExecutor.setCorePoolSize(5);
threadPoolTaskExecutor.setMaxPoolSize(20);
threadPoolTaskExecutor.setQueueCapacity(20);
threadPoolTaskExecutor.setKeepAliveSeconds(60);
threadPoolTaskExecutor.setThreadNamePrefix("ThreadPoolTaskExecutor");
threadPoolTaskExecutor.setRejectedExecutionHandler(new ThreadPoolExecutor.CallerRunsPolicy());
threadPoolTaskExecutor.initialize();
return threadPoolTaskExecutor;
}
@Bean
public Executor jdkCustomExecutor() {
ThreadPoolExecutor threadPoolExecutor = new ThreadPoolExecutor(5, 20, 60, TimeUnit.SECONDS, new ArrayBlockingQueue<Runnable>(20));
threadPoolExecutor.setThreadFactory(new CustomizableThreadFactory("ThreadPoolExecutor"));
threadPoolExecutor.setRejectedExecutionHandler(new ThreadPoolExecutor.CallerRunsPolicy());
return threadPoolExecutor;
}
}
(3)Web接口(调用远程接口)
package gdut.controller;
import gdut.remote.SleuthRemoteService;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.scheduling.annotation.Async;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;
import java.util.concurrent.Executor;
@RestController
@RequestMapping("/sleuth")
public class SleuthController {
private static final Logger log = LoggerFactory.getLogger(SleuthController.class);
@Autowired
SleuthRemoteService sleuthRemoteService;
@Autowired
@Qualifier("jdkCustomExecutor")
Executor executor;
@PostMapping("/createName")
public String createName(@RequestParam("name")String name) {
log.info("name is {}", name);
return sleuthRemoteService.name(name);
}
@PostMapping("/newThread")
public String newThread(@RequestParam("name")String name) {
log.info("newThread name is {}", name);
new Thread(new Runnable() {
@Override
public void run() {
sleuthRemoteService.name(name);
}
}).start();
return "success";
}
@PostMapping("/newExecutor")
public String newExecutor(@RequestParam("name")String name) {
log.info("newExecutor name is {}", name);
ThreadPoolExecutor threadPoolExecutor = new ThreadPoolExecutor(5, 20, 60, TimeUnit.SECONDS, new ArrayBlockingQueue<Runnable>(20));
threadPoolExecutor.setThreadFactory(new CustomizableThreadFactory("ThreadPoolExecutor"));
threadPoolExecutor.setRejectedExecutionHandler(new ThreadPoolExecutor.CallerRunsPolicy());
threadPoolExecutor.submit(new Runnable() {
@Override
public void run() {
sleuthRemoteService.name(name);
}
});
return "success";
}
@PostMapping("/newThreadAutowired")
public String newThreadAutowired(@RequestParam("name")String name) {
log.info("newThreadAutowired newThread name is {}", name);
executor.execute(new Runnable() {
@Override
public void run() {
sleuthRemoteService.name(name);
}
});
return "success";
}
@PostMapping("/newThreadSpring")
public String newThreadSpring(@RequestParam("name")String name) {
log.info("newThreadSpring name is {}", name);
async(name);
return "success";
}
@Async("customExecutor")
public void async(String name) {
sleuthRemoteService.name(name);
}
}
(4)测试
(4.1)同步调用远程服务
http://localhost:8081/sleuth/createName?name=liufeifei
源服务控制台输出:
2022-12-31 22:01:31.470 DEBUG [flowable,f68e6477d2959f9a,f68e6477d2959f9a,true] 24116 --- [nio-8081-exec-5] o.s.web.servlet.DispatcherServlet : POST "/sleuth/createName?name=liufeifei", parameters={masked}
2022-12-31 22:01:31.471 INFO [flowable,f68e6477d2959f9a,f68e6477d2959f9a,true] 24116 --- [nio-8081-exec-5] gdut.controller.SleuthController : name is liufeifei
2022-12-31 22:01:31.483 DEBUG [flowable,f68e6477d2959f9a,f68e6477d2959f9a,true] 24116 --- [nio-8081-exec-5] o.s.web.servlet.DispatcherServlet : Completed 200 OK
远程服务控制台输出
2022-12-31 22:01:31.476 DEBUG [sleuth,f68e6477d2959f9a,53fb7d3d06a142d0,true] 1184 --- [nio-8082-exec-9] o.s.web.servlet.DispatcherServlet : POST "/sleuthRemote/name?name=liufeifei", parameters={masked}
2022-12-31 22:01:31.477 INFO [sleuth,f68e6477d2959f9a,53fb7d3d06a142d0,true] 1184 --- [nio-8082-exec-9] gdut.service.SleuthRemoteServiceImpl : name is: liufeifei
2022-12-31 22:01:31.480 DEBUG [sleuth,f68e6477d2959f9a,53fb7d3d06a142d0,true] 1184 --- [nio-8082-exec-9] o.s.web.servlet.DispatcherServlet : Completed 200 OK
总结:同步调用,源服务和调用的远程服务具有相同的traceId,不同的SpanId。
(4.2)开启异步线程调用远程服务
http://localhost:8081/sleuth/newThread?name=liufeifei
源服务控制台输出:
2022-12-31 22:05:44.751 DEBUG [flowable,97211f5d9afdbe9e,97211f5d9afdbe9e,true] 24116 --- [io-8081-exec-10] o.s.web.servlet.DispatcherServlet : POST "/sleuth/newThread?name=liufeifei", parameters={masked}
2022-12-31 22:05:44.752 INFO [flowable,97211f5d9afdbe9e,97211f5d9afdbe9e,true] 24116 --- [io-8081-exec-10] gdut.controller.SleuthController : newThread name is liufeifei
2022-12-31 22:05:44.756 DEBUG [flowable,97211f5d9afdbe9e,97211f5d9afdbe9e,true] 24116 --- [io-8081-exec-10] o.s.web.servlet.DispatcherServlet : Completed 200 OK
远程服务控制台输出:
2022-12-31 22:05:44.760 DEBUG [sleuth,68271bfc63b5eea7,68271bfc63b5eea7,false] 1184 --- [nio-8082-exec-1] o.s.web.servlet.DispatcherServlet : POST "/sleuthRemote/name?name=liufeifei", parameters={masked}
2022-12-31 22:05:44.761 INFO [sleuth,68271bfc63b5eea7,68271bfc63b5eea7,false] 1184 --- [nio-8082-exec-1] gdut.service.SleuthRemoteServiceImpl : name is: liufeifei
2022-12-31 22:05:44.762 DEBUG [sleuth,68271bfc63b5eea7,68271bfc63b5eea7,false] 1184 --- [nio-8082-exec-1] o.s.web.servlet.DispatcherServlet : Completed 200 OK
总结:直接开启线程异步调用,源服务和调用的远程服务具有不同的traceId,不同的SpanId。
(4.3)创建异步线程池调用远程服务
http://localhost:8081/sleuth/newExecutor?name=liufeifei
源服务控制台输出:
2022-12-31 22:37:39.689 DEBUG [flowable,dc54b639d0c98ff9,dc54b639d0c98ff9,true] 18704 --- [nio-8081-exec-2] o.s.web.servlet.DispatcherServlet : POST "/sleuth/newExecutor?name=liufeifei", parameters={masked}
2022-12-31 22:37:39.746 INFO [flowable,dc54b639d0c98ff9,dc54b639d0c98ff9,true] 18704 --- [nio-8081-exec-2] gdut.controller.SleuthController : newExecutor name is liufeifei
2022-12-31 22:37:39.824 DEBUG [flowable,dc54b639d0c98ff9,dc54b639d0c98ff9,true] 18704 --- [nio-8081-exec-2] o.s.web.servlet.DispatcherServlet : Completed 200 OK
远程服务控制台输出:
2022-12-31 22:37:39.803 DEBUG [sleuth,afaec96c4a4cca35,afaec96c4a4cca35,true] 21176 --- [nio-8082-exec-3] o.s.web.servlet.DispatcherServlet : POST "/sleuthRemote/name?name=liufeifei", parameters={masked}
2022-12-31 22:37:39.804 INFO [sleuth,afaec96c4a4cca35,afaec96c4a4cca35,true] 21176 --- [nio-8082-exec-3] gdut.service.SleuthRemoteServiceImpl : name is: liufeifei
2022-12-31 22:37:39.809 DEBUG [sleuth,afaec96c4a4cca35,afaec96c4a4cca35,true] 21176 --- [nio-8082-exec-3] o.s.web.servlet.DispatcherServlet : Completed 200 OK
总结:直接创建线程池异步调用,源服务和调用的远程服务具有不同的traceId,不同的SpanId。
(4.4)依赖注入自定义的JDK类型的线程池,异步调用远程服务
http://localhost:8081/sleuth/newThreadAutowired?name=liufeifei
源服务控制台输出:
2022-12-31 22:12:51.542 DEBUG [flowable,ba648d5bfea91137,ba648d5bfea91137,true] 24116 --- [nio-8081-exec-1] o.s.web.servlet.DispatcherServlet : POST "/sleuth/newThreadAutowired?name=liufeifei", parameters={masked}
2022-12-31 22:12:51.562 INFO [flowable,ba648d5bfea91137,ba648d5bfea91137,true] 24116 --- [nio-8081-exec-1] gdut.controller.SleuthController : newThreadAutowired newThread name is liufeifei
2022-12-31 22:12:51.570 DEBUG [flowable,ba648d5bfea91137,ba648d5bfea91137,true] 24116 --- [nio-8081-exec-1] o.s.web.servlet.DispatcherServlet : Completed 200 OK
远程服务控制台输出:
2022-12-31 22:12:51.576 DEBUG [sleuth,ba648d5bfea91137,b7b1060071073038,true] 1184 --- [nio-8082-exec-3] o.s.web.servlet.DispatcherServlet : POST "/sleuthRemote/name?name=liufeifei", parameters={masked}
2022-12-31 22:12:51.577 INFO [sleuth,ba648d5bfea91137,b7b1060071073038,true] 1184 --- [nio-8082-exec-3] gdut.service.SleuthRemoteServiceImpl : name is: liufeifei
2022-12-31 22:12:51.579 DEBUG [sleuth,ba648d5bfea91137,b7b1060071073038,true] 1184 --- [nio-8082-exec-3] o.s.web.servlet.DispatcherServlet : Completed 200 OK
总结:依赖注入自定义的JDK类型的线程池,异步调用远程服务,源服务和调用的远程服务具有相同的traceId,不同的SpanId。
(4.5)@Async指定使用Spring类型的线程池,异步调用远程服务
http://localhost:8081/sleuth/newThreadSpring?name=liufeifei
源服务控制台输出:
2022-12-31 22:18:36.346 DEBUG [flowable,244958caed0939a9,244958caed0939a9,true] 24116 --- [nio-8081-exec-4] o.s.web.servlet.DispatcherServlet : POST "/sleuth/newThreadSpring?name=liufeifei", parameters={masked}
2022-12-31 22:18:36.348 INFO [flowable,244958caed0939a9,244958caed0939a9,true] 24116 --- [nio-8081-exec-4] gdut.controller.SleuthController : newThreadSpring name is liufeifei
2022-12-31 22:18:36.357 DEBUG [flowable,244958caed0939a9,244958caed0939a9,true] 24116 --- [nio-8081-exec-4] o.s.web.servlet.DispatcherServlet : Completed 200 OK
远程服务控制台输出:
2022-12-31 22:18:36.352 DEBUG [sleuth,244958caed0939a9,b7af0aa9376641f5,true] 1184 --- [nio-8082-exec-5] o.s.web.servlet.DispatcherServlet : POST "/sleuthRemote/name?name=liufeifei", parameters={masked}
2022-12-31 22:18:36.353 INFO [sleuth,244958caed0939a9,b7af0aa9376641f5,true] 1184 --- [nio-8082-exec-5] gdut.service.SleuthRemoteServiceImpl : name is: liufeifei
2022-12-31 22:18:36.354 DEBUG [sleuth,244958caed0939a9,b7af0aa9376641f5,true] 1184 --- [nio-8082-exec-5] o.s.web.servlet.DispatcherServlet : Completed 200 OK
总结:@Async指定使用Spring类型的线程池,异步调用远程服务,源服务和调用的远程服务具有相同的traceId,不同的SpanId。
参考
SpringBoot和SpringCloud之间的依赖关系
SpringCloud多线程链路追踪
Spring cloud Sleuth链路追踪对于异步线程池的支持