zoukankan      html  css  js  c++  java
  • Feign拦截器和解码器

    一、业务需求

    在Spring Cloud的项目中,A服务使用Feign调用B服务的某个接口,如果需要传递全局认证token或参数,在方法参数里面加相应字段的方式显然是不可取的。

     

    首先想到的是AOP方式,使用切面拦截Feign方法,在AOP切面里面向方法参数里面添加数据,Feign方法执行完成之后,从响应对象里面获取返回的数据,这样的方式可以解决数据的传递和接收,但也必将需要方法参数和响应对象的支持,与业务耦合,并不是合理的架构实现方案。

     

    如果有某种机制可以拦截到Feign的请求对象和响应对象,便可以获取到请求头和响应头,就可以使用请求头和响应头来传递数据。

     

    经过一番调查,了解到Feign的RequestInterceptor可以拦截到Feign请求,可以获取到请求对象和请求头,但是RequestInterceptor无法处理响应。

     

    于是又进行调查,得知解码器Decoder是对响应进行解码的组件,可以获取到响应对象和响应头。

     

    在调查过程中,还有另外的收获:FeignClientsConfiguration类。

     

    二、FeignClientsConfiguration类

    Feign默认配置类是FeignClientsConfiguration类,该类定义了Feign默认的编码器、解码器、所使用的契约等。

    Spring Cloud允许通过注解@FeignClient的configuration属性自定义Feign配置,自定义配置的优先级比FeignClientsConfiguration要高。

    这个类的核心代码如下:

     1 @Configuration
     2 public class FeignClientsConfiguration {
     3 
     4     @Autowired
     5     private ObjectFactory<HttpMessageConverters> messageConverters;
     6 
     7     @Autowired(required = false)
     8     private List<AnnotatedParameterProcessor> parameterProcessors = new ArrayList<>();
     9 
    10     @Autowired(required = false)
    11     private List<FeignFormatterRegistrar> feignFormatterRegistrars = new ArrayList<>();
    12 
    13     @Autowired(required = false)
    14     private Logger logger;
    15 
    16     @Bean
    17     @ConditionalOnMissingBean
    18     public Decoder feignDecoder() {
    19         return new OptionalDecoder(new ResponseEntityDecoder(new SpringDecoder(this.messageConverters)));
    20     }
    21 
    22     @Bean
    23     @ConditionalOnMissingBean
    24     @ConditionalOnMissingClass("org.springframework.data.domain.Pageable")
    25     public Encoder feignEncoder() {
    26         return new SpringEncoder(this.messageConverters);
    27     }
    28 
    29     @Bean
    30     @ConditionalOnMissingBean
    31     public Contract feignContract(ConversionService feignConversionService) {
    32         return new SpringMvcContract(this.parameterProcessors, feignConversionService);
    33     }
    34 
    35     @Bean
    36     @Scope("prototype")
    37     @ConditionalOnMissingBean
    38     public Feign.Builder feignBuilder(Retryer retryer) {
    39         return Feign.builder().retryer(retryer);
    40     }
    41 }

    三、Feign请求拦截器

    参考FeignClientsConfiguration类,我们可以编写一个configuration类,注入自定义的RequestInterceptor实现类对象,在apply(RequestTemplate requestTemplate)方法中获取到请求RestTemplate对象,使用RequestTemplate对象设置请求参数、添加请求头。

    示例如下:

    1 @Configuration
    2 public class MyConfig {
    3     @Bean("myInterceptor")
    4     public RequestInterceptor getRequestInterceptor() {
    5         return new MyClientInterceptor();
    6     }
    7 }

    MyClientInterceptor类:

    1 class MyClientInterceptor implements RequestInterceptor {
    2     @Override
    3     public void apply(RequestTemplate requestTemplate) {
    4         requestTemplate.query("name", "Allen");
    5         requestTemplate
    6               .header("token", "token")
    7               .header("id", id);
    8     }
    9 }

    四、Feign解码器

    1、解码器概述

    Feign解码器负责对响应进行解码,返回符合Feign接口需求的对象。

    我们可以参考FeignClientsConfiguration类中的方式编写和注入自定义的解码器。

    1 @Bean
    2 @ConditionalOnMissingBean
    3 public Decoder feignDecoder() {
    4     return new OptionalDecoder(
    5             new ResponseEntityDecoder(new SpringDecoder(this.messageConverters)));
    6 }

    2、继承SpringDecoder自定义解码器

     1 class TraceDecoder extends SpringDecoder {
     2 
     3     TraceDecoder(ObjectFactory<HttpMessageConverters> messageConverters) {
     4         super(messageConverters);
     5     }
     6 
     7     @Override
     8     public Object decode(Response response, Type type) throws IOException, FeignException {
     9 
    10         // 这里可以从response对象里面获取响应头和响应体
    11 
    12         // 获取响应头
    13         Map<String, Collection<String>> headers = response.headers();
    14 
    15         return super.decode(response, type);
    16     }
    17 }

    3、注入自定义解码器

    feignDecoder()方法完全参考了FeignClientsConfiguration类的写法。

     1 @Slf4j
     2 @Configuration
     3 @ConditionalOnClass({Feign.class})
     4 @AutoConfigureBefore(FeignAutoConfiguration.class)
     5 public class CommonLogFeignConfig {
     6 
     7     @Autowired
     8     private ObjectFactory<HttpMessageConverters> messageConverters;
     9 
    10     @Bean
    11     public Decoder feignDecoder() {
    12         return new OptionalDecoder(new ResponseEntityDecoder(new TraceDecoder(this.messageConverters)));
    13     }
    14 }
  • 相关阅读:
    Robotframework自动化6-基础关键字介绍(3)
    Robotframework自动化5-基础关键字介绍(2)
    Robotframework自动化4-基础关键字介绍(1)
    Robotframework自动化3-APP启动
    Robotframework自动化2-Windows环境搭建
    Robotframework自动化1-Windows环境搭建
    python2与python3同时安装
    Fiddler的基本界面介绍
    Fiddler的安装和APP抓包
    正则表达式
  • 原文地址:https://www.cnblogs.com/xugf/p/13458520.html
Copyright © 2011-2022 走看看