Spring Cloud OpenFeign


Feign原意为伪装,是一个声明式的伪Java Http客户端,Feign不做任何的请求处理,Feign通过处理注解生成Request模板,从而简化了Http API的开发。开发人员可以使用注解的方式定制Request API模板,在发送Http Request请求之前,Feign通过处理注解的方式替换掉Request模板中的参数,生成真正的Request,并交给Java Http客户端去处理。利用这种方式,使得开发者只需关注Feign注解模板的开发,而不用关注Http请求本身,简化了Http请求的过程,使得程序中的Http请求变得简单和容易理解。Feign提供Feign提供可插拔的配置注解和encoder、decoder。也可以通过集成Ribbon 和 Eureka、Spring Cloud CircuitBreaker 以及 Spring Cloud LoadBalancer 来使 Feign 可成为负载均衡的 http 客户端。

一、引入启用OpenFeign

1、在使用了SpringBoot和SpringCloud的项目中:

<dependency>
      <groupId>org.springframework.cloud</groupId>
      <artifactId>spring-cloud-starter-openfeign</artifactId>
</dependency>

2、在主启动类上添加@EnableFeignClients注解

@SpringBootApplication
@EnableFeignClients
public class Application {

    public static void main(String[] args) {
        SpringApplication.run(Application.class, args);
    }

}

二、OpenFeign的简单使用

@FeignClient(value="stores")
public interface StoreClient {
    @RequestMapping(method = RequestMethod.GET, value = "/stores")
    List<Store> getStores();

    @RequestMapping(method = RequestMethod.GET, value = "/stores")
    Page<Store> getStores(Pageable pageable);

    @RequestMapping(method = RequestMethod.POST, value = "/stores/{storeId}", consumes = "application/json")
    Store update(@PathVariable("storeId") Long storeId, Store store);
}

1、@FeignClient
在上例的@FeignClient 注释中,字符串值(上面的“stores”)是一个任意的客户端名称(微服务中的服务名),它用于创建 Ribbon 负载平衡器或 Spring Cloud LoadBalancer。你还可以使用 url 属性(绝对值或仅主机名)指定真实接口的 URL。
Spring Cloud Netflix Ribbon 现在处于维护模式,因此建议改用 Spring Cloud LoadBalancer。为此,需将 spring.cloud.loadbalancer.ribbon.enabled 的值设置为 false。

一个FeignClient下的具体接口和SpringMVC中编写接口的方式是一致的。当调用这些伪装的接口时,OpenFeign就会通过在@FeignClient中配置的服务名或者URL去寻找调用真实的接口。

2、使用StoreClient

@Service
public class TestService {
    @Autowired
    StoreClient storeClient;

    public String stores(){
        return storeClient.getStores();
    }
}

当调用storeClient的getStores()方法时,就会去请求stores服务下的/stores接口。

三、覆盖Feign的默认配置

Spring Cloud 使用 FeignClientsConfiguration 为每个命名的客户端按需创建一个的ensemble 作为 ApplicationContext。ensemble 包含(除其他外)一个 feign.Decoder、一个 feign.Encoder 和一个 feign.Contract。可以使用 @FeignClient 注解的 contextId 属性来覆盖ensemble 的名称。
Spring Cloud 允许通过使用 @FeignClient 声明额外的配置(在 FeignClientsConfiguration 之上)来完全控制 feign 客户端。例如:

@FeignClient(name = "stores", configuration = FooConfiguration.class)
public interface StoreClient {
    //..
}

在上例中,客户端由 FeignClientsConfiguration 中已有的组件和 FooConfiguration 中的任何组件组成(后者将覆盖前者)。FooConfiguration 不需要用@Configuration 注解。但如果使用了@Configuration 注解,那么请注意将其从任何包含此配置的@ComponentScan 中排除,因为在指定时它将成为 feign.Decoder、feign.Encoder、feign.Contract 等的默认源。可以以与上述类似的方式在 @EnableFeignClients 属性 defaultConfiguration 中指定默认配置。不同之处在于此配置将适用于所有 feign 客户端。

以前使用 url 属性时不需要 name 属性。现在需要。

Spring Cloud OpenFeign默认提供以下bean:

BeanTypebeanNameClassName
DecoderfeignDecoderResponseEntityDecoder
EncoderfeignEncoderSpringEncoder
LoggerfeignLoggerSlf4jLogger
ContractfeignContractSpringMvcContract
Feign.BuilderfeignBuilderHystrixFeign.Builder
Feign.BuilderfeignBuilderFeignCircuitBreaker.Builder
ClientfeignClientLoadBalancerFeignClient(有Ribbon时)、FeignBlockingLoadBalancerClient (有Spring Cloud LoadBalancer时),都没有的话就是默认Client

OkHttpClient 和 ApacheHttpClient 以及 ApacheHC5 feign 客户端可以通过分别将 feign.okhttp.enabled 或 feign.httpclient.enabled 或 feign.httpclient.hc5.enabled 设置为 true并将导入其依赖包来使用。也可以通过提供 org.apache.http.impl.client.CloseableHttpClient 的 bean 来自定义使用的 HTTP 客户端。

@FeignClient 也可以使用配置属性进行配置。

feign:
  client:
    config:
      feignName:
        connectTimeout: 5000
        readTimeout: 5000
        loggerLevel: full
        errorDecoder: com.example.SimpleErrorDecoder
        retryer: com.example.SimpleRetryer
       defaultQueryParameters:
          query: queryValue
        defaultRequestHeaders:
          header: headerValue
        requestInterceptors:
          - com.example.FooRequestInterceptor
          - com.example.BarRequestInterceptor
        decode404: false
        encoder: com.example.SimpleEncoder
        decoder: com.example.SimpleDecoder
        contract: com.example.SimpleContract

如果我们同时创建@Configuration bean 和配置属性,配置属性将获胜。它将覆盖@Configuration 值。但是如果你想把优先级改成@Configuration,你可以把feign.client.default-to-properties改成false。默认情况下,Feign 客户端不编码斜杠/字符。可以通过将 feign.client.decodeSlash 的值设置为 false 来更改此行为。

配置失败重试
OpenFeign默认请求失败后重试次数为0,即不重试,如果想要配置重试,就需要在FeignClient指定的配置类中注入Retryer的bean,覆盖掉默认的Retryer:

@Configuration
public class FeignConfig {
    @Bean
    public Retryer feignRetryer(){
    // 重试间隔为100毫秒,最大重试时间为2秒,重试次数为5次
        return new Retryer.Default(100,2000,5);
    }
}

四、超时处理

我们可以对每个Feign客户端进行超时配置,主要有connectTimeout和readTimeout两个配置参数。connectTimeout 可防止由于服务器处理时间过长而阻塞调用者。而readTimeout则适用于读取响应时间过长的情况。启用 Hystrix 时,其超时配置默认为 1000 毫秒。可以在配置文件中增加超时时间:

feign:
  client:
    config:
      default:
        connectTimeout: 5000
        readTimeout: 5000
  hystrix:
    enabled: true

hystrix:
  command:
    default:
      execution:
        timeout:
          enabled: true
        isolation:
          thread:
            timeoutInMilliseconds: 60000

仅配置feign的超时时间而不增加hystrix的超时时间,总的超时时间仍然还是是1000毫秒。

五、Feign对Hystrix的支持

如果项目中使用了Hystrix并且配置了feign.hystrix.enabled=true,Feign会将所有的方法包装为断路器。Hystrix支持fallback的概念:当熔断降级链路打开或出现错误时会执行指定路径的代码。要为给定的 @FeignClient 启用fallback,请将fallback属性设置为实现了指定FeignClient的类名,例如:

@FeignClient(name = "hello", fallback = HystrixClientFallback.class)
protected interface HystrixClient {
    @RequestMapping(method = RequestMethod.GET, value = "/hello")
    Hello iFailSometimes();
}

static class HystrixClientFallback implements HystrixClient {
    @Override
    public Hello iFailSometimes() {
        return new Hello("fallback");
    }
}

如果需要访问触发回退的原因,可以在@FeignClient 中使用 fallbackFactory 属性。

@FeignClient(name = "hello", fallbackFactory = HystrixClientFallbackFactory.class)
protected interface HystrixClient {
    @RequestMapping(method = RequestMethod.GET, value = "/hello")
    Hello iFailSometimes();
}

@Component
static class HystrixClientFallbackFactory implements FallbackFactory<HystrixClient> {
    @Override
    public HystrixClient create(Throwable cause) {
        return new HystrixClient() {
            @Override
            public Hello iFailSometimes() {
                return new Hello("fallback; reason was: " + cause.getMessage());
            }
        };
    }
}

六、Feign对Spring Cloud CircuitBreaker 的支持

与Hystrix一样,当项目中使用了Spring Cloud CircuitBreaker并且配置了feign.circuitbreaker.enabled=true时,Feign会将所有的方法包装为断路器。同样也可以使用fallback机制。

七、请求响应压缩

可以考虑为 Feign 启用请求和响应的 GZIP 压缩。只需通过启用以下属性来执行此操作:

feign.compression.request.enabled=true
feign.compression.response.enabled=true

也可以通过以下配置来设置对哪些类型的请求响应才进行压缩,以及多大的请求才压缩:
feign.compression.request.mime-types=text/xml,application/xml,application/json
feign.compression.request.min-request-size=2048

对于除了 OkHttpClient 之外的 http 客户端,可以启用默认的 gzip 解码器来解码 UTF-8 编码的 gzip 响应:
feign.compression.response.useGzipDecoder=true

八、Feign的日志

每个 Feign 客户端会创建一个日志记录器,默认情况下,记录器的名称是用于创建 Feign 客户端的接口的完整类名。 Feign logging 只响应 DEBUG 级别。可以在配置文件中进行配置:
logging:
level.xyz.ymtao.feign.TestFeign: DEBUG

可以通过为每个客户端配置 Logger.Level 对象告诉 Feign 要记录多少日志内容。可选的Level有:

  • NONE:不记录;
  • BASIC:仅记录请求方法和 URL 以及响应状态代码和执行时间;
  • HEADERS:记录请求和响应头的基本信息;
  • FULL:记录请求和响应的标头、正文和元数据。

例如:

@Configuration
public class FooConfiguration {
    @Bean
    Logger.Level feignLoggerLevel() {
        return Logger.Level.FULL;
    }
}

九、@QueryMap

OpenFeign 的@QueryMap 注解支持将 POJO 转换为 GET请求的 参数映射。不幸的是,默认的 OpenFeign QueryMap 注释与 Spring 不兼容,因为它缺少 value 属性。Spring Cloud OpenFeign 提供了一个等效的 @SpringQueryMap 注解,用于将 POJO 或 Map 参数注解为查询参数映射。例如,Params 类定义了参数 param1 和 param2:

@FeignClient("demo")
public interface DemoTemplate {

    @GetMapping(path = "/demo")
    String demoEndpoint(@SpringQueryMap Params params);
}

这样,调用时就会是/demo?param1=value1&param2=value2

十、OpenFeign工作流程

1、首先通过@EnableFeignClients注解开启FeignClient的功能,只有这个注解存在,才会在程序启动时进行包扫描,对使用了@FeignClient注解的类作相应处理;

2、当接口方法被调用时,通过JDK的代理来生成具体的RequestTemplate模板对象;

3、根据RequestTemplate再生成Http请求的Request对象;

4、将Request对象交给Client去处理,其中Client可以是HttpClient,OKHttp,HttpURLConnection;

5、最后Client被封装到LoadBalanceClient类中,这个类结合了Ribbon或Spring Cloud LoadBalance做负载均衡。

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值