1. 故事背景

Feign + Hystrix 是一对黄金组合,虽然我没有吃透。在我使用的过程中,遇到了一个问题。首先Feign在默认情况下,http状态码4XX和5XX都是会触发熔断的(404可以配置不触发),但是对于我这种使用Restful规范的人来说,就有点儿尴尬。因为在我这里,大部分情况下,内部服务抛出的4XX、5XX,是不希望触发熔断的。为什么呢?有以下几点原因:

  • 4XX是一定不需要触发,因为最基本的表单校验失败就是4XX,需要把最原始的信息通知到,具体如何显示,客户端说了算。
  • 5XX说明服务有异常,这个按需处理,往上抛的话,可以方便前后端配合查错,不往上抛,有可能是因为这并不是主业务,并不影响主流程

基于这个,我需要重新配置Feign的错误处理逻辑。

2. 提前准备

  • 使用了Feign和Hystrix的环境,使用了如下版本:

    <dependency>
        <groupId>org.springframework.cloud</groupId>
        <artifactId>spring-cloud-starter-feign</artifactId>
        <version>1.4.3.RELEASE</version>
    </dependency>
    

3. 实践

最重要的官网参考 ,搜索了好多的参考,好多都对我有帮助,但不完全生效,最后还是结合着官网尝试成功。

先说说我的目标:

  • 可以有全局的错误处理配置,不需要每个Feign客户端都配一遍
  • 可以用个性化的配置,特殊的客户端,使用特殊的配置

具体来说,全局那个是4XX和5XX均不熔断,在面对客户端那层再进行统一处理;个性化配置,针对5XX会触发熔断。

3.1 配置

配置生效注意点:

  1. 不需要@Configuration注解

    public class FeignErrorDecodeDefaultConfiguration {
        @Primary
        @Bean
        public ErrorDecoder errorDecoder() {
            return new DefaultErrorDecoder();
        }
    }
    
  2. 不能在主@ComponentScan (or @SpringBootApplication)范围内,从其包名上分离

  3. @FeignClient注解的属性name不能重复

    // 就是下面这个name属性,不能重复
    @FeignClient(name = "foo.bar.com/foo",  path = "/foo")
    public interface FooFeign {
    }
    

全局配置和局部配置共存方式:

  1. 通过配置文件配置好全局的配置

    feign:
      hystrix:
        enabled: true
      client:
        config:
          default:
            errorDecoder: foo.bar.feign.configuration.DefaultErrorDecoder
    

    这个时候,全局配置生效,你想某些Feign用其他配置,你可以在注解@FeignClient上添加属性configuration指定,但你会发现,貌似没生效。

    因为全局的优先级是最高的,但可以调整,增加配置调整优先级default-to-properties: false

  2. 配置优先级,全部配置如下:

    feign:
      hystrix:
        enabled: true
      client:
        default-to-properties: false
        config:
          default: 
            errorDecoder: foo.bar.feign.configuration.DefaultErrorDecoder
    

这样的话,局部配置也会生效。

4. 总结

Feign的配置方式好复杂,并且思维方式有点与我相反,我不喜欢,但是没办法,还是得用他。