OpenFeign请求拦截器组件RequestInterceptor原理与使用场景

简介: 该文章讲述了OpenFeign中的请求拦截器组件RequestInterceptor的原理及其常见使用场景。

前言

前几篇文章已经分析过了OpenFeign的Client组件和重试组件。

今天开始分析OpenFeign的第3个组件RequestInterceptor

RequestInterceptor是在发起远程请求前对请求对象进行拦截的,这个组件其实使用场景挺常见的。比如传递公用的参数,对feign请求url进行限流计数,编码等场景,下面我们来详细看看他的原理。

RequestInterceptor组成

我们需要先看下RequestInterceptor的组成。

package feign;

public interface RequestInterceptor {
   
   

void apply(RequestTemplate var1);

}

RequestInterceptor 是一个接口,apply方法接受请求模版RequestTemplate对象,

我们可以看到 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);
}

RequestTemplate组成

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;
//请求url
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.enabledfeign.compression.response.enabled

都是通过FeignAcceptGzipEncodingAutoConfiguration自动装配类实现的

  • 开启响应压缩
@Configuration
@EnableConfigurationProperties({
   
   FeignClientEncodingProperties.class})
@ConditionalOnClass({
   
   Feign.class})
@ConditionalOnBean({
   
   Client.class})
@ConditionalOnProperty(
    value = {
   
   "feign.compression.response.enabled"},
    matchIfMissing = false
)
@ConditionalOnMissingBean(
    type = {
   
   "okhttp3.OkHttpClient"}
)
@AutoConfigureAfter({
   
   FeignAutoConfiguration.class})
public class FeignAcceptGzipEncodingAutoConfiguration {
   
   
    public FeignAcceptGzipEncodingAutoConfiguration() {
   
   
    }

    //响应压缩拦截器
    @Bean
    public FeignAcceptGzipEncodingInterceptor feignAcceptGzipEncodingInterceptor(FeignClientEncodingProperties properties) {
   
   
        return new FeignAcceptGzipEncodingInterceptor(properties);
    }
}
  • 开启请求压缩
@Configuration
@EnableConfigurationProperties(FeignClientEncodingProperties.class)
@ConditionalOnClass(Feign.class)
@ConditionalOnBean(Client.class)
// The OK HTTP client uses "transparent" compression.
// If the content-encoding header is present it disable transparent compression
@ConditionalOnMissingBean(type = "okhttp3.OkHttpClient")
@ConditionalOnProperty(value = "feign.compression.request.enabled", matchIfMissing = false)
@AutoConfigureAfter(FeignAutoConfiguration.class)
public class FeignContentGzipEncodingAutoConfiguration {
   
   

    @Bean
    public FeignContentGzipEncodingInterceptor feignContentGzipEncodingInterceptor(
            FeignClientEncodingProperties properties) {
   
   
        return new FeignContentGzipEncodingInterceptor(properties);
    }

}

image.png

需要注意的是如果使用okhttp通信客户端,okhttp是支持transparent compression压缩的,因此上面的配置都是在非okhttp客户端的情况下生效。

二、透传tocken,TraceId,请求计数,监控打点等

如果我们需要对一些请求传一些固定的参数,比如token,或者接入统一的监控平台,一般会使用请求拦截器实现。

比如下方案例,通过RequestInterceptor传递traceId,请求计数

public class TraceIdInterceptor implements RequestInterceptor {
   
   

    AtomicLong uriAtomicLong = new AtomicLong();

    @Override
    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生效。

@Configuration
public class FeignClientConfiguration {
   
   

    @Bean
    public TraceIdInterceptor interceptor() {
   
   
        return new TraceIdInterceptor();
    }
}

二、针对指定FeignClient生效

如果想只对某些FeignClient生效,需要创建一个配置类,同时在FeignClient中指定configuration配置类属性。

public class FeignClientConfiguration {
   
   

    @Bean
    public TraceIdInterceptor interceptor() {
   
   
        return new TraceIdInterceptor();
    }
}


@FeignClient(value = "fox-server", configuration = TestFeignClientConfiguration.class)
public interface FeignService {
   
   
    @PostMapping("/get")
    String getName(@RequestBody @Validated DemoRequest request);
}

注意这种情况FeignClientConfiguration是没有增加@Configuration,不会被Spring容器扫描到的。

总结

RequestInterceptor是OpenFeign提供一个对Feign请求拦截的组件,能够在发起请求前对header,body进行修改,一般用来实现一些非业务功能的需求,比如公用参数,监控,打点,压缩等,支持对全局FeignClient生效,也支持对部分FeignClient生效。

关于RequestInterceptor的分析结束了,你有没有更好的使用场景案例呢,欢迎评论区分享给大家。

image.png

相关文章
|
6月前
|
Dubbo Java 应用服务中间件
微服务框架(十一)Dubbo调用拦截及参数校检扩展
  此系列文章将会描述Java框架Spring Boot、服务治理框架Dubbo、应用容器引擎Docker,及使用Spring Boot集成Dubbo、Mybatis等开源框架,其中穿插着Spring Boot中日志切面等技术的实现,然后通过gitlab-CI以持续集成为Docker镜像。   使用Dubbo框架时,面对自身的业务场景,需根据定制的需求编写SPI拓展实现,再根据配置来加载拓展点。
|
1月前
|
存储 缓存 Java
Spring高手之路23——AOP触发机制与代理逻辑的执行
本篇文章深入解析了Spring AOP代理的触发机制和执行流程,从源码角度详细讲解了Bean如何被AOP代理,包括代理对象的创建、配置与执行逻辑,帮助读者全面掌握Spring AOP的核心技术。
39 3
Spring高手之路23——AOP触发机制与代理逻辑的执行
|
1月前
|
Java 程序员 API
《Spring Boot应用进阶:打造优雅的错误处理机制与全局异常拦截器》
《Spring Boot应用进阶:打造优雅的错误处理机制与全局异常拦截器》
115 0
|
4月前
|
负载均衡 Java API
通用快照方案问题之Feign添加请求拦截器如何解决
通用快照方案问题之Feign添加请求拦截器如何解决
33 1
|
5月前
|
存储 缓存 负载均衡
OpenFeign高级用法:缓存、QueryMap、MatrixVariable、CollectionFormat优雅地远程调用
OpenFeign高级用法:缓存、QueryMap、MatrixVariable、CollectionFormat优雅地远程调用
|
消息中间件 设计模式 Java
Spring 四种方式教你异步接口返回结果
Spring 四种方式教你异步接口返回结果
Spring 四种方式教你异步接口返回结果
|
负载均衡 Java 数据处理
案例03-fegin调用报404问题
fegin调用报404问题
156 0
|
SQL 监控 前端开发
Springboot过滤器和拦截器详解及使用场景
过滤器和拦截器触发时机不一样,过滤器是在请求进入容器后,但请求进入servlet之前进行预处理的。请求结束返回也是,是在servlet处理完后,返回给前端之前。
|
API 微服务 容器
微服务组件之OpenFeign配置信息及RequestInterceptor请求拦截器
OpenFeign配置信息及RequestInterceptor请求拦截器
我的心血全在这了,这种方式讲@Async原理,你别再不懂Spring了
想你在看这篇文章之前有过使用@Async注解进行任务异步处理的经历,在项目开发过程中,针对非主流程、非实时、耗时的任务,往往会进行异步处理,这样既不会影响主流程,还会提高主流程的响应时间。
下一篇
无影云桌面