OpenFeign

Feign

  • 官网 https://github.com/OpenFeign/feign
  • Feign是一个受到Retrofit,JAXRS-2.0和WebSocket启发的Java到HTTP客户端绑定器。
  • Feign的第一个目标是降低将Denominator统一绑定到HTTP API 的复杂性。相当于,OpenFeign将HTTP服务之间的请求由传统的HTTP API调用IP完整路径替换成模块化访问,降低复杂度

Spring Cloud OpenFeign

  • Spring Cloud OpenFeign以将OpenFeign集成到Spring Boot应用中的方式,为微服务架构下服务之间的调用提供了解决方案。

  • 我们知道,前端访问后端微服务接口时,都是通过:“ip+端口+接口api”的形式进行调用的,而有时候我们访问一个服务的接口,该接口业务可能还会内部调用另一个微服务的接口进行信息处理,而这时候采用硬编码方式即使用IP+端口方式调用则会显得十分僵硬和不方便。

  • 结合SpringCloud后,由于存在注册中心,每个服务都会在注册中心进行注册,所以Spring Cloud OpenFeign实现了通过注册服务模块进行特定服务访问的方式,方便了服务间调用的简化

原理

整合Spring Cloud Feign

  • 引依赖。新建一个测试项目:springcloud-client2,并引入依赖

    1
    2
    3
    4
    5
    6
    7
    8
    9
    <!--feign 依赖-->
    <dependency>
    <groupId>io.github.openfeign</groupId>
    <artifactId>feign-okhttp</artifactId>
    </dependency>
    <dependency>
    <groupId>org.springframework.cloud</groupId>
    <artifactId>spring-cloud-starter-openfeign</artifactId>
    </dependency>
  • 加配置,将该模块服务注册在eureka中

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    server:
    port: 7920 #服务端口
    spring:
    profiles:
    active: 700 #当前生效环境
    application:
    name: springcloud-client2 #指定应用的唯一标识/服务名
    # 配置中心
    cloud:
    config:
    fail-fast: true
    name: ${spring.application.name},datasource,redis #指定工程于config server中的应用名
    profile: ${spring.profiles.active} #指定工程于config server中的生效环境
    uri: http://localhost:8080 #指定配置中心的注册路径
    # 注册中心配置
    eureka:
    instance:
    prefer-ip-address: true #优先使用IP地址注册
    client:
    service-url:
    defaultZone: http://127.0.0.1:8761/eureka/ #eureka的注册地址
  • 加注解,启动类使用@EnableFeignClient 注解开启Feign服务

    1
    2
    3
    4
    5
    6
    7
    8
    @EnableFeignClients
    @EnableEurekaClient
    @SpringBootApplication
    public class SpringCloudClient2Application {
    public static void main(String[] args) {
    SpringApplication.run(SpringCloudClient2Application.class, args);
    }
    }
  • 编写一个FeignClient

    • @FeignClient("provider微服务名字")
    • 如果需要传递参数,那么@RequestParam 和@RequestBody @PathVariable 不能省,必加
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    @FeignClient(value = "springcloud-client", name = "springcloud-client") //指向注册名为springcloud-client的服务
    public interface TestFeignIntercept {
    /**
    * 内部接口,获取信息
    * @return
    */
    @GetMapping("/test/feign/{id}")
    //指向springcloud-client中接口路径为/feign/test的接口
    Map getFeignMassage(@PathVariable("id") Long id);
    }
  • 同时,在springcloud-client服务工程中编写接口路径为/test/feign的接口,供内部调用

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    @RestController
    public class FeignTestController {
    @GetMapping("/test/feign/{id}")
    public Map getUser(@PathVariable("id") Long id) {
    Map result = new HashMap();
    result.put("id", id);
    result.put("name", "xiaoming");
    result.put("sex", "male");
    result.put("age", 12);
    return result;
    }
    }
  • 编写接口调用FeignClient实现内部访问@FeignClient("springcloud-client")

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    @RestController
    public class TestFeignController {
    @Autowired
    private TestFeignIntercept testFeignIntercept;
    /**
    * 获取信息
    * @return
    */
    @GetMapping("/testFeign/{id}")
    public Map getFeignMessage(@PathVariable("id") Long id){
    return this.testFeignIntercept.getFeignMassage(id);
    }
    }
  • 启动Eureka,Config,client,Client2服务, 调用springcloud-client2的 /testFeign 接口:

OpenFeign超时控制

演示超时出错

  • 超时设置,故意设置超时演示出错情况

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    @GetMapping("/test/feign/{id}")
    public Map getUser(@PathVariable("id") Long id) throws InterruptedException {
    // 服务提供方8001故意写暂停程序
    Thread.sleep(3000);
    Map result = new HashMap();
    result.put("id", id);
    result.put("name", "xiaoming");
    result.put("sex", "male");
    result.put("age", 12);
    return result;
    }

超时控制

  • 默认Feign客户端只等待一秒钟,但是服务段处理需要超过1秒钟,导致Feign客户端不想等待了,直接返回报错。

  • 为了避免这种请况,有时候我们需要设置Feign客户端的超时控制

  • Feign 默认是支持Ribbon ,Feign依赖里自己带了Ribbon

  • 在消费端的配置文件中配置

    • 这里的ReadTimeout 和 ConnectTimeout 没有代码提示,但可以使用
    1
    2
    3
    4
    5
    6
    # 设置feign 客户端超时时间(OpenFeign默认支持ribbon)
    ribbon:
    # 设置建立连接后从服务器读取到可用资源所用的时间
    ReadTimeout: 5000
    # 设置建立连接所用的时间,适用于网络状况正常的情况下,两端连接所用的时间
    ConnectTimeout: 5000

OpenFeign日志打印

  • Feign提供了日志打印功能,我们可以通过配置来调整日志级别,从而了解Feign中Http请求的细节。

  • 说白了就是:对Feign接口的调用情况进行监控和输出。

    日志级别 说明
    NONE 默认的,不显示任何日志
    BASIC 仅记录请求方法、URL、响应状态码及执行时间
    HEADERS 除了BASIC中定义的信息之外,还有请求和响应的头信息
    FULL 除了HEADERS中定义的信息外,还有请求和响应的正文及元数据。

消费端配置日志

  • 配置日志bean

    1
    2
    3
    4
    5
    6
    7
    8
    9
    import feign.Logger;
    import org.springframework.context.annotation.Bean;

    public class FeignConfig {
    @Bean
    Logger.Level feignLoggerLevel(){
    return Logger.Level.FULL;
    }
    }
  • 配置文件

    1
    2
    3
    4
    logging:
    level:
    # feign 日志以什么级别监控哪个接口
    pers.fulsun.demo.springcloud.controller.TestFeignIntercept: debug