继承RequestInterceptor,实现feign调用前参数配置,为何会被所有项目下请求调用

继承RequestInterceptor,实现feign调用前参数配置,为何会被所有项目下请求调用?

本篇会分以下几个模块进行梳理,如有需要可以直接进行跳转

  1. Feign调用原理
  2. 重要组件的主要作用
  3. Feign的简单使用
  4. Feign调用前的参数设置
    (1)header存值大小限制
    (2)多线程情况下的上下文丢失
  5. 配置为何会被所有项目下请求调用

一、Feign调用原理

SpringCloud 中 Feign 是目前跨服务调用应用中使用最多的技术。
在微服务启动时,Feign会进行包扫描,对加@FeignClient注解的接口,按照注解的规则,创建远程接口的本地JDK Proxy代理实例。然后,将这些本地Proxy代理实例,注入到Spring IOC容器中。当远程接口的方法被调用,由Proxy代理实例去完成真正的远程访问,并且返回结果。
执行图例:
在这里插入图片描述

二、重要组件的主要作用

组件名称作用领域
JDK Proxy不属于Feign组件 内置代理
FeignInvocationHandler实现了InvocationHandler,Feign专属处理器,反射用来寻找MethodHandler
SynchronousMethodHandler实现了MethodHandler,进行请求重封装,并接收返回值
1、创建requestTemplate 2、client.excecute()正式调用 3、response接收
Client最终进行请求封装的组件
LoadBalancerFeignClient负载均衡客户端选择调用Default进行请求

执行顺序图示:
在这里插入图片描述
Cilent的四种实现方式,注意上表中Client调用方式

名称来源
Defaultfeign.Client
ApacheHttpClientApache httpclient
OkHttpClientOkHttp3
LoadBalancerFeignClientRibben

三、Feign的简单使用

一、创建一个接口服务,用来专属调用统一url的另一个服务
二、创建方法,设置调用参数与url
三、补充请求方式、请求参数、请求地址

@FeignClient(name = "feignTest", url = "${otherService.url}", configuration = FeignConfiguration.class)
public interface FeignTestService {
   
    @PostMapping("/test/add")
    ResultVO<JSONObject> save(@RequestBody String addVo);
    
    }

四、Feign调用前的参数设置

@FeignClient中有一个参数是configuration,可以支持开发者对请求的自定义。

feign在发送请求之前都会调用RequestInterceptor接口的apply方法,通过实现RequestInterceptor接口的apply方法达到要求

代码示例:

public class FeignConfiguration implements RequestInterceptor {
    @Override
    public void apply(RequestTemplate requestTemplate) {
        ServletRequestAttributes attributes = (ServletRequestAttributes) RequestContextHolder
                .getRequestAttributes();
        if (attributes != null) {
            HttpServletRequest request = attributes.getRequest();
            Enumeration<String> headerNames = request.getHeaderNames();
            if (headerNames != null) {
                while (headerNames.hasMoreElements()) {
                    String name = headerNames.nextElement();
                    String values = null;
                    if ("username".equalsIgnoreCase(name)) {
                        values = request.getHeader(name);
                    }
                    if (StringUtils.isNotBlank(values)) {
                        requestTemplate.header(name, values);
                    }
                }
          }
      }
  }
}
                

RequestInterceptor 有几个实现类,可以直接继承使用,作用分别如下:

在这里插入图片描述
(1)header存值大小限制
如果发现存在:Request header is too large的错误出现,很有可能是header中存放的数据过长导致的

默认情况下,tomcat(8.0版本)允许的http请求header的最大值是8024个字节(8KB)

这种情况下网上也有很多中解决方案推荐,

比如说:设置请求头大小
或者:使用MultiValueMap

处于安全考虑,这里还是建议将header传送的参数修改为paramer形式传递。

(2)多线程情况下的上下文丢失
如果请求被放置在异步中,那么会丢失请求上下文,包括最外层请求中的header
这个问题暂时我还没有更好的解决方案落地
不过网上有几个推荐,有空可以试试:

使用 HystrixRequestVariableDefault,通过该类的注释可以知道,这个是Hystrix 为自身执行的线程提供的一个类似于ThreadLocal 的类,但是它与ThreadLocal 的不同之处在于,该Locals 的作用范围提升到了这个User Request Scope 级别,通过其注解可知,它是通过父类线程与子类线程共享的方式来共用该Locals 中的信息;所以,达到了User Request 线程与Hystrix 线程共用 attributes 的目的;由此,可以猜测,Hystrix 的线程是由当前Request 线程所创建的子线程;不过,使用的过程中,需要注意的是,HystrixRequestVariable 必须在每一个请求开始的时候进行初始化;也就是说,我们可以将 Request Context 中的有用信息存储到HystrixRequestVariableDefault中达到与Hystrix Context 共享信息;也就实现了Request Context 中的属性与Hystrix Context 之间共享的目的。

五、配置为何会被所有项目下请求调用

笔者在这里踩过一个坑,其实也是因为这个坑,才准备写一篇这样子的博客记录整个过程。
事情是这样子的。

需求:新需求里面需要携带用户信息去中台校验权限,每个接口的交互都需要

考虑:如果给每一个接口都放置参数,出问题不好定位,同时需要开发的代码量很大,可以编写配置类,统一处理

做法:
1、@FeignClient中进行configuration配置
2、配置文件使用@Configuration标记
3、继承RequestInterceptor,重写apply放置

简单看起来没有啥问题,可以测试之后发现只要使用到了feign的调用,不管是不是此类中的请求,都会走配置。
原因就是
配置文件加@Configuration会将配置注入到Spring中,导致所有FeignClient都生效

此处涉及到局部注解与全部注解,区别就在于@Configuration

全局配置:

@Configuration
public class FeignConfiguration implements RequestInterceptor {
    @Override
    public void apply(RequestTemplate requestTemplate) {
    }
}

局部配置:

public class FeignConfiguration implements RequestInterceptor {
    @Override
    public void apply(RequestTemplate requestTemplate) {
    }
}

THE END
GOOD LUNCK

感谢前辈笔记
参考博客:
https://www.cnblogs.com/crazymakercircle/p/11965726.html
https://blog.csdn.net/wudiyong22/article/details/103801874

  • 2
    点赞
  • 11
    收藏
    觉得还不错? 一键收藏
  • 6
    评论
评论 6
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值