
前言
前几篇文章已经分析过了OpenFeign的Client组件和重试组件。
OpenFeign集成Ribbon负载均衡-过滤和选择服务核心实现
今天开始分析OpenFeign的第3个组件RequestInterceptor。
RequestInterceptor是在发起远程请求前对请求对象进行拦截的,这个组件其实使用场景挺常见的。比如传递公用的参数,对feign请求url进行限流计数,编码等场景,下面我们来详细看看他的原理。
RequestInterceptor组成
我们需要先看下RequestInterceptor的组成。
package feign;public interface RequestInterceptor {void apply(RequestTemplate var1);}
RequestInterceptor是一个接口,接口里只有一个apply方法,apply方法接受请求模板RequestTemplate对象,它是在哪里调用的呢?
我们可以看到OpenFeign执行请求的方法
feign.SynchronousMethodHandler#executeAndDecode中
Object executeAndDecode(RequestTemplate template) throws Throwable {//这里会对请求做一次拦截处理Request request = this.targetRequest(template);long start = System.nanoTime();Response response;try {response = this.client.execute(request, this.options);//...return var9;}//对请求拦截器进行应用Request targetRequest(RequestTemplate template) {Iterator var2 = this.requestInterceptors.iterator();while(var2.hasNext()) {//循环每个拦截器进行应用到请求对象RequestInterceptor interceptor = (RequestInterceptor)var2.next();interceptor.apply(template);}return this.target.apply(template);}
RequestInterceptor能够帮我们做什么呢?我们看下RequestTemplate类的组成
public final class RequestTemplate implements Serializable {private static final Pattern QUERY_STRING_PATTERN = Pattern.compile("(?<!\\{)\\?");private final Map<String, QueryTemplate> queries = new LinkedHashMap();private final Map<String, HeaderTemplate> headers;private String target;private String fragment;private boolean resolved;private UriTemplate uriTemplate;private HttpMethod method;private transient Charset charset;private Body body;private boolean decodeSlash;private CollectionFormat collectionFormat;
里面有几个非常熟悉的字段:
queries是存储请求的参数
headers存储请求头
uriTemplate存储请求url
RequestInterceptor使用案例
就是上面这三个字段,工作中可以用来解决一些问题。
一、压缩请求传输的数据
OpenFeign内置已经做了一些扩展,我们对一些请求响应时间性能要求比较高的场景,通常需要对请求传输的数据进行压缩。OpenFeign内置了gzip压缩算法的实现
FeignContentGzipEncodingInterceptor 压缩请求体
FeignAcceptGzipEncodingInterceptor 压缩响应体
这两个配置项项目中有没有用过呢?通过这两个项目就可以开启压缩功能了
feign.compression.request.enabled、 feign.compression.response.enabled
他们都是通过FeignAcceptGzipEncodingAutoConfiguration自动装配类实现的
开启响应压缩
value = {},matchIfMissing = false)type = {})public class FeignAcceptGzipEncodingAutoConfiguration {public FeignAcceptGzipEncodingAutoConfiguration() {}//响应压缩拦截器public FeignAcceptGzipEncodingInterceptor feignAcceptGzipEncodingInterceptor(FeignClientEncodingProperties properties) {return new FeignAcceptGzipEncodingInterceptor(properties);}}
开启请求压缩
// The OK HTTP client uses "transparent" compression.// If the content-encoding header is present it disable transparent compressionpublic class FeignContentGzipEncodingAutoConfiguration {public FeignContentGzipEncodingInterceptor feignContentGzipEncodingInterceptor(FeignClientEncodingProperties properties) {return new FeignContentGzipEncodingInterceptor(properties);}}
需要注意的是如果使用okhttp通信客户端,okhttp是支持transparent compression压缩的,因此上面的配置都是在非okhttp客户端的情况下生效。
二、透传TraceId,请求计数,监控打点等
如果我们需要对一些请求传一些固定的参数,比如token,或者接入统一的监控平台,一般会使用请求拦截器实现。
比如下方案例,通过RequestInterceptor传递traceId,请求计数
public class TraceIdInterceptor implements RequestInterceptor {AtomicLong uriAtomicLong = new AtomicLong();public void apply(RequestTemplate requestTemplate) {//传递traceid给下游系统requestTemplate.header("traceId", UUID.fastUUID().toString(true));String url = requestTemplate.url();long accessCount = uriAtomicLong.incrementAndGet();//上报访问次数...}
RequestInterceptor生效
以上面TraceIdInterceptor为例,如何使RequestInterceptor生效呢?
一、全局生效
通过配置类的方式,增加@Configuration注解,让Spring容器扫描到,这样就会对所有FeignClient生效。
public class FeignClientConfiguration {public TraceIdInterceptor interceptor() {return new TraceIdInterceptor();}}
二、针对指定FeignClient生效
如果想只对某些FeignClient生效,需要创建一个配置类,同时在FeignClient中指定configuration配置类属性。
public class FeignClientConfiguration {public TraceIdInterceptor interceptor() {return new TraceIdInterceptor();}}public interface FeignService {String getName( DemoRequest request);}
注意这种情况FeignClientConfiguration是没有增加@Configuration,不会被Spring容器扫描到的。
总结
RequestInterceptor是OpenFeign提供一个对Feign请求拦截的组件,能够在发起请求前对header,body进行修改,一般用来实现一些非业务功能的需求,比如公用参数,监控,打点,压缩等,支持对全局FeignClient生效,也支持对部分FeignClient生效。
关于RequestInterceptor的分析结束了,你有没有更多的使用场景案例呢,欢迎评论区分享给大家。
原文作者:服务端技术栈;如有侵权,请联系管理员删除。