• feign拦截器和解码器


    原文链接:https://blog.csdn.net/xuguofeng2016/article/details/107882619

    业务需求

    在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要高。

    这个类的核心代码如下:

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

    Feign请求拦截器

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

    示例如下:

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

    MyClientInterceptor类:

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

    Feign解码器

    解码器概述

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

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

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

    继承SpringDecoder自定义解码器

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

    注入自定义解码器

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

    @Slf4j
    @Configuration
    @ConditionalOnClass({Feign.class})
    @AutoConfigureBefore(FeignAutoConfiguration.class)
    public class CommonLogFeignConfig {
    
    	@Autowired
        private ObjectFactory<HttpMessageConverters> messageConverters;
    
    	@Bean
    	public Decoder feignDecoder() {
    		return new OptionalDecoder(new ResponseEntityDecoder(new TraceDecoder(this.messageConverters)));
    	}
    }
  • 相关阅读:
    CRISPR Screening的应用
    Trios | 家系研究
    高通量测序数据的存储、分析和管理
    glusterfs部署及卷类型使用【转】
    perf的使用方法(CPU占用高分析)【转】
    MGR的gtid_executed不连续的问题分析【转】
    Ceph存储使用【转】
    Pycharm2018激活(含软件下载)【转】
    Jupyter notebook添加kernel【转】
    Kubernetes零宕机滚动更新【转】
  • 原文地址:https://www.cnblogs.com/fswhq/p/13827605.html
Copyright © 2020-2023  润新知