【SpringCloud学习笔记】Feign

/ 微服务 / 没有评论 / 1680浏览

Openfeign

openfeign简介

Feign是声明性的web服务客户端。它使编写web服务客户端更加容易。要使用Feign,请创建一个接口并对其进行注释。它具有可插入的注释支持,包括Feign注释和JAX-RS注释。Feign还支持可插拔编码器和解码器。Spring Cloud添加了对Spring MVC注释的支持,并支持使用Spring Web中默认使用的同一HttpMessageConverters。Spring Cloud集成了Ribbon和Eureka以在使用Feign时提供负载平衡的http客户端。

feign作用

feign旨在使编写Java Http客户端变的更加容易。

之前的学习中我们使用Ribbon + RestTemplate 对Http请求进行封装处理,形成了一套模板化的调用方法。但在实际开发中对服务依赖的调用可能不止一处,往往一个接口会被多处调用,所以通常都会针对每个微服务自行封装一些客户端类来包装这些依赖服务的调用。所以,Feign在此基础上做了封装,来帮助我们定义和实现依赖服务接口的定义。在Feign的实现下,我们只需要创建一个接口并使用注解的方式来配置它(以前是Dao接口上面标注Mapper注解,现在是一个微服务接口上标注一个Feign注解即可),便可按成对服务提供方的接口绑定,简化了使用Spring Cloud Ribbon时,自动封装服务调用客户的开发量。

使用feign

==用于消费者端==

创建maven项目

创建名为:cloud-consumer-order-feign-80 的项目。

修改pom文件

添加feign依赖:

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

创建applicaiton.yml

server:
  port: 80

eureka:
  client:
    register-with-eureka: true
    fetch-registry: true
    service-url:
      defaultZone: http://eureka7001.com:7001/eureka,http://eureka7002.com:7002/eureka
#      defaultZone: http://localhost:7001/eureka
    healthcheck:
      enabled: true
spring:
  application:
    name: cloud-consumer-order-feign-80

创建启动类

添加@EnableFeignClients 注解,开启feign支持!

@SpringBootApplication
@EnableFeignClients
public class CloudConsumerOrderFeignApplication {

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

编写业务类

通过一个接口封装需要调用的业务逻辑。

@Component
@FeignClient(value = "CLOUD-PROVIDER-PAYMENT")
public interface PaymentFeignService {

    @GetMapping("/payment/get/{id}")
    public CommonResult getById(@PathVariable("id") Long id);

    @GetMapping("/payment/feign/timeout")
    public Object timeout();
}

测试

测试结果如下:

image-20210301135701086

feign超时控制

feign客户端默认只等待一秒钟,但是服务器端处理需要超过1秒钟,导致feign客户端不想等待了,直接返回错误;为了避免这种情况;有时候我们需要设置feign客户的超时控制。这需要在yml中开启。

错误模拟

添加模拟方法

我们在8001和8002服务提供端添加一个超1秒才能返回的方法;在之前的实例中PaymentController中:

    @GetMapping("/feign/timeout")
    @ResponseBody
    public Object timeout(){
        try {
            TimeUnit.SECONDS.sleep(3);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        return port;
    }
添加消费端调用
@Component
@FeignClient(value = "CLOUD-PROVIDER-PAYMENT")
public interface PaymentFeignService {

    @GetMapping("/payment/get/{id}")
    public CommonResult getById(@PathVariable("id") Long id);

    @GetMapping("/payment/feign/timeout")
    public Object timeout();
}

添加Controller调用

    @GetMapping("/payment/feign/timeout")
    @ResponseBody
    public Object timeout(){
        return paymentFeignService.timeout();
    }
测试结果
image-20210301141040470

解决方案

在yml中配置相关超时参数,注意配置是没有语法自动提示的。

ribbon:
  ConnectTimeout: 5000
  ReadTimeout: 5000

feign日志增强

添加配置类

@Configuration
public class FeignConfig {
    @Bean
    public Logger.Level logLevel(){
        return Logger.Level.FULL;
    }
}

配置yml文件

logging:
  level:
    info.huzd.cloud.service.PaymentFeignService: debug

查看日志

2021-03-01 14:20:03.611  INFO 3382 --- [p-nio-80-exec-1] c.n.l.DynamicServerListLoadBalancer      : DynamicServerListLoadBalancer for client CLOUD-PROVIDER-PAYMENT initialized: DynamicServerListLoadBalancer:{NFLoadBalancer:name=CLOUD-PROVIDER-PAYMENT,current list of Servers=[130.30.3.224:8001, 130.30.3.224:8002],Load balancer stats=Zone stats: {defaultzone=[Zone:defaultzone;	Instance count:2;	Active connections count: 0;	Circuit breaker tripped count: 0;	Active connections per server: 0.0;]
},Server stats: [[Server:130.30.3.224:8002;	Zone:defaultZone;	Total Requests:0;	Successive connection failure:0;	Total blackout seconds:0;	Last connection made:Thu Jan 01 08:00:00 CST 1970;	First connection made: Thu Jan 01 08:00:00 CST 1970;	Active Connections:0;	total failure count in last (1000) msecs:0;	average resp time:0.0;	90 percentile resp time:0.0;	95 percentile resp time:0.0;	min resp time:0.0;	max resp time:0.0;	stddev resp time:0.0]
, [Server:130.30.3.224:8001;	Zone:defaultZone;	Total Requests:0;	Successive connection failure:0;	Total blackout seconds:0;	Last connection made:Thu Jan 01 08:00:00 CST 1970;	First connection made: Thu Jan 01 08:00:00 CST 1970;	Active Connections:0;	total failure count in last (1000) msecs:0;	average resp time:0.0;	90 percentile resp time:0.0;	95 percentile resp time:0.0;	min resp time:0.0;	max resp time:0.0;	stddev resp time:0.0]
]}ServerList:org.springframework.cloud.netflix.ribbon.eureka.DomainExtractingServerList@68ca0868
2021-03-01 14:20:03.664 DEBUG 3382 --- [p-nio-80-exec-1] i.h.cloud.service.PaymentFeignService    : [PaymentFeignService#getById] <--- HTTP/1.1 200 (170ms)
2021-03-01 14:20:03.665 DEBUG 3382 --- [p-nio-80-exec-1] i.h.cloud.service.PaymentFeignService    : [PaymentFeignService#getById] connection: keep-alive
2021-03-01 14:20:03.665 DEBUG 3382 --- [p-nio-80-exec-1] i.h.cloud.service.PaymentFeignService    : [PaymentFeignService#getById] content-type: application/json
2021-03-01 14:20:03.665 DEBUG 3382 --- [p-nio-80-exec-1] i.h.cloud.service.PaymentFeignService    : [PaymentFeignService#getById] date: Mon, 01 Mar 2021 06:20:03 GMT
2021-03-01 14:20:03.665 DEBUG 3382 --- [p-nio-80-exec-1] i.h.cloud.service.PaymentFeignService    : [PaymentFeignService#getById] keep-alive: timeout=60
2021-03-01 14:20:03.665 DEBUG 3382 --- [p-nio-80-exec-1] i.h.cloud.service.PaymentFeignService    : [PaymentFeignService#getById] transfer-encoding: chunked
2021-03-01 14:20:03.665 DEBUG 3382 --- [p-nio-80-exec-1] i.h.cloud.service.PaymentFeignService    : [PaymentFeignService#getById] 
2021-03-01 14:20:03.666 DEBUG 3382 --- [p-nio-80-exec-1] i.h.cloud.service.PaymentFeignService    : [PaymentFeignService#getById] {"code":200,"message":"查询成功(服务端口:8001)","object":{"id":1,"serial":"101010101010101"}}
2021-03-01 14:20:03.666 DEBUG 3382 --- [p-nio-80-exec-1] i.h.cloud.service.PaymentFeignService    : [PaymentFeignService#getById] <--- END HTTP (103-byte body)
2021-03-01 14:20:04.609  INFO 3382 --- [erListUpdater-1] c.netflix.config.ChainedDynamicProperty  : Flipping property: CLOUD-PROVIDER-PAYMENT.ribbon.ActiveConnectionsLimit to use NEXT property: niws.loadbalancer.availabilityFilteringRule.activeConnectionsLimit = 2147483647

以上的第一步也可以用过一个配置实现:

feign:
  client:
    config:
      default:
        connectTimeout: 5000  #效果等同ribbon.ConnectTimeout
        readTimeout: 5000 #效果等同ribbon.readTimeout
        loggerLevel: full # 可以取代第一步