Spring Boot 1.5中如何排除Feign调用/客户端的Sleuth链路追踪
嘿,针对你在Spring Boot 1.5微服务里遇到的Feign链路追踪过滤需求,我整理了几个适配这个版本栈的实用方案,你可以根据自己的场景选择:
方案1:自定义注解+拦截器,灵活跳过指定方法/客户端
这种方式能让你精准控制单个Feign方法或整个客户端是否追踪,灵活性最高。
步骤1:定义跳过追踪的注解
先创建一个自定义注解,用来标记不需要追踪的Feign方法或客户端:
@Target({ElementType.METHOD, ElementType.TYPE}) @Retention(RetentionPolicy.RUNTIME) public @interface SkipTrace { }
步骤2:自定义Feign拦截器
我们需要编写一个拦截器,优先于Sleuth的默认拦截器执行,检查当前调用是否标记了@SkipTrace,如果是就跳过追踪逻辑:
import feign.RequestInterceptor; import feign.RequestTemplate; import org.springframework.context.annotation.Primary; import org.springframework.stereotype.Component; import java.lang.reflect.Method; @Component @Primary // 确保这个拦截器优先于Sleuth默认拦截器加载 public class SkipTraceFeignInterceptor implements RequestInterceptor { // 注入Sleuth的默认追踪拦截器,用于正常请求的处理 private final RequestInterceptor sleuthDelegate; public SkipTraceFeignInterceptor(RequestInterceptor sleuthDelegate) { this.sleuthDelegate = sleuthDelegate; } @Override public void apply(RequestTemplate template) { // 获取当前Feign调用的方法和目标客户端类信息 Method targetMethod = template.metadata().method(); Class<?> clientClass = template.metadata().targetType(); // 检查方法或类上是否有@SkipTrace注解 if (targetMethod.isAnnotationPresent(SkipTrace.class) || clientClass.isAnnotationPresent(SkipTrace.class)) { // 跳过追踪,直接返回,不注入Zipkin追踪头 return; } // 正常调用Sleuth的拦截器处理追踪逻辑 sleuthDelegate.apply(template); } }
步骤3:标记需要跳过的Feign调用
现在你可以在整个Feign客户端或者单个方法上添加@SkipTrace注解:
// 整个客户端的所有调用都跳过追踪 @SkipTrace @FeignClient(name = "unimportant-service") public interface UnimportantFeignClient { @GetMapping("/api/data") String getUnimportantData(); } // 仅单个方法跳过追踪,其他方法正常追踪 @FeignClient(name = "mixed-service") public interface MixedFeignClient { @SkipTrace @GetMapping("/api/skip") String getSkippedData(); @GetMapping("/api/trace") String getTracedData(); }
方案2:给指定Feign客户端使用原始Client,完全绕过Sleuth包装
如果你想让某个Feign客户端的所有调用都不被追踪,可以直接给它配置原始的Feign Client,跳过Sleuth的包装逻辑。
步骤1:创建Feign配置类
编写一个配置类,返回原始的Feign Client实例:
import feign.Client; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; @Configuration public class NoTraceFeignConfig { @Bean public Client feignClient() { // 返回Feign默认的Client,不经过Sleuth的TraceFeignClient包装 return new Client.Default(null, null); } }
步骤2:给目标Feign客户端引用这个配置
在Feign客户端的configuration属性里指定刚才的配置类:
@FeignClient(name = "unimportant-service", configuration = NoTraceFeignConfig.class) public interface UnimportantFeignClient { @GetMapping("/api/data") String getUnimportantData(); }
这样这个客户端的所有请求都不会生成追踪Span,完全绕过Sleuth的处理。
方案3:通过自定义采样器过滤(适合全局规则)
如果你的需求是基于服务名或URI等全局规则过滤,可以自定义Sleuth的采样器,决定哪些Span不发送到Zipkin。不过要注意,这种方式仍然会创建Span,只是不提交到Zipkin,性能上不如前两种方案。
import org.springframework.cloud.sleuth.Sampler; import org.springframework.cloud.sleuth.Span; import org.springframework.stereotype.Component; @Component public class CustomTraceSampler implements Sampler { @Override public boolean isSampled(Span span) { // 根据远程服务名判断是否跳过采样 String remoteService = span.remoteServiceName(); if ("unimportant-service".equals(remoteService)) { return false; // 不采样,不发送到Zipkin } // 其他请求保持默认采样逻辑(这里直接返回true,你也可以结合默认采样器) return true; } }
注意事项
- 因为你用的是Spring Boot 1.5,对应的Spring Cloud版本大概率是Dalston或Edgware系列,上述方案都是适配这些版本的。如果遇到
template.metadata()不可用的情况,可以尝试通过ThreadLocal在调用前标记是否跳过追踪。 - 方案1中的
@Primary注解必须加,否则自定义拦截器可能不会优先执行。 - 方案2的配置类要确保只被目标Feign客户端引用,不要全局生效,否则所有Feign调用都会跳过追踪。
内容的提问来源于stack exchange,提问作者slippery




