跟乐乐学微服务!(四)Spring Cloud组件 Feign

上一篇文章:跟乐乐学微服务!(三)SpringCloud组件熔断器 Hystrix

Feign是什么?

Feign可以对服务提供方所暴露的url请求地址进行拼接封装,然后伪装成一个接口的方法,消费方可以通过调用这个Feign伪装了的接口方法,去请求服务提供方。
这是为了让消费方Controller调用提供方暴露的接口时,能够看上去像MVC架构中从Controller去调用Service一样。
是的,说到‘伪装‘,Feign的英文意思叫伪装,事实上它在Cloud微服务中最大的作用就是伪装成方法去调用服务提供方。
同时,Feign也集成了Ribbon负载均衡
,这是因为当服务消费方通过Feign伪装了的接口方法去请求服务提供方时,会自动进行负载均衡。
此外,Feign还集成了Hystrix熔断器。

Feign应用:伪装

Feign伪装概念

在没有Feign之前,服务消费方要访问提供方所暴露的接口的话,
服务消费方需要在controller层,根据服务提供方的服务名和接口路径来拼接成一个url,接着通过restTemplate对象来访问。
但是通过Feign的话,消费方可以通过调用一个接口(使用了FeignClient注解)的方法,直接去访问服务提供方的接口。
这么做的好处在于,能够隐藏向提供方发起的Rest请求,伪装成SpringMVC架构这种、直接调用Service层接口的风格。
在这里插入图片描述

Feign伪装实现

在这里插入图片描述

  • 先在消费方引入Feign的依赖
        <!-- Feign依赖 -->
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-openfeign</artifactId>
        </dependency>
  • 在消费方的SpringBoot启动类中,加入@EnableFeignClients注解,声明使用Feign组件。

在这里插入图片描述

  • 创建一个用于伪装的接口,有两点需要注意。
    1.接口上面使用@FeignClient注解指定一个用于请求的服务提供方的服务名。
    2.接口方法必须为Rest风格定义,因此要有@GetMapping或@PostMapping等注解(和服务提供方一致),Rest请求注解内的value值便是提供方所暴露接口的路径。
package com.databasequery.databasequeryconsumer.feign;

import org.springframework.cloud.openfeign.FeignClient;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;

@FeignClient(value = "database-provider-service")//value值为服务提供方的服务名
public interface ProviderServiceFeign {

    @GetMapping(value = "/query/qq/{qqnum}")//value为服务提供方暴露的接口路径。Rest注解也需要和服务提供方的接口保持一致。
    Object qqQuery(@PathVariable("qqnum") String qq);

}


  • 接下来在消费方的Controller中,通过@Autowired注解注入这个接口(如果注入爆红,则无视),然后定义一个新的消费方法’qqQueryFeign’,这个方法不再通过restTemplate对象进行请求,改为直接调用feign伪装接口的的方法。
@RestController
@RequestMapping(value = "query")
@DefaultProperties(defaultFallback = "defaultFallbach") //指定当前类的全局服务降级方法
public class QueryController {

    // restTemplate用于访问服务提供方暴露的接口。
    @Autowired
    private RestTemplate restTemplate;

    @Autowired
    private ProviderServiceFeign providerServiceFeign;

	//直接调用Fegin伪装接口的方法来请求服务提供方的接口。
    @HystrixCommand
    @GetMapping("qqQueryFeign/{qqNumber}")
    public Object qqQueryFeign(@PathVariable("qqNumber") String qqNumber){
       return providerServiceFeign.qqQuery(qqNumber);
    }

    @HystrixCommand
    @GetMapping("qq/{qqNumber}")
    public Object qqQuery(@PathVariable("qqNumber") String qqNumber){
        System.out.println("收到一条查询请求,被查账号是:"+qqNumber);
        String url = "http://database-provider-service/query/qq/"+qqNumber;
        Object qr =   restTemplate.getForObject(url, Object.class);
       return qr;
    }

    public Object defaultFallbach(){

        String responseErrorStr = "不好意思,服务正忙,请您稍后再试!--- 来自全局默认的降级方法";
        return responseErrorStr;
    }
}
  • 接下来,我们尝试访问消费服务方。成功响应。

在这里插入图片描述

Feign内置集成应用:Ribbon负载均衡

介绍

不知道你有注意到没,我们在消费方和提供方的耦合这一点上,是通过在接口上声明 @FeignClient(value = “提供方的服务名称”) 注解来实现的。
我们并没有从eureka服务端拉取过来的服务列表中选择其中的某个服务。
是不是感觉有点熟悉呢?
没错,这是Feign它自身已经集成了Ribbon来实现负载均衡的缘故。

关于Eureka和Feign各自都有集成Ribbon这一点

但是,在我的微服务第二篇博客文章SpringCloud组件负载均衡Ribbon的应用中,我提到了Eureka客户端集成了Ribbon;那么,既然Feign也集成了Ribbon,他们会冲突吗?
答案是并不会发生冲突
不过需要注意的是,当使用了Feign后,application.yml中ribbon的配置参数,将会只对调用了Feign伪装接口的消费者controller层方法起作用
并不会对使用RestTemaplte对象进行负载均衡请求的消费者controller层方法起作用。
为了确认这一点,我们可以进行一个演示。

  1. 配置负载均衡

前面说到,使用了Feign组件的情况下,配置文件中的ribbon参数将会只对调用了feign接口的controller层方法起作用;
为了证明,我们在消费方的appilication.yml配置文件中,对Ribbon进行配置。
ribbon的默认超时是1秒,那么参数中我们指定为100毫秒。

ribbon:
  ReadTimeout: 100 # 读取超时时长。默认1秒。衡量的是消费方和提供方建立连接后,从读取资源到响应回消费方本地所耗费的时长。为方便验证,这里改为100毫秒
  ConnectTimeout: 100 # 建立链接的超时时长,默认1秒。衡量的是消费方和提供方建立连接所耗费的时长。为方便验证,这里改为100毫秒
  OkToRetryOnAllOperations: false # 默认为true,是否对所有的请求重试。
  MaxAutoRetries: 0 # 表示当消费方访问提供方实例出错后,对同一个提供方实例所进行的重试次数。默认为1。为方便验证,这里改为0
  MaxAutoRetriesNextServer: 0 # 当对同一个提供方实例的重试达到了规定次数后,会自动更换另一个实例进行请求;此处设置的是更换实例的次数。默认为2。为方便验证,这里改为0
  1. 更改服务提供方的逻辑
    在提供方controller层的某个方法内,加一个延时逻辑,以演示出 Eureka内置的ribbon负载均衡(RestTemaplte对象) 和 Feign内置的ribbon负载均衡(调用伪装接口) 遇到超时情况,哪一方会依照application.yaml文件中的ribbon配置参数去处理。
@RestController
@RequestMapping(value = "query")
public class QueryController {

    @Autowired
    private QueryService queryService;

    @GetMapping("qq/{qqnum}")
    public QueryResult qqQueryMethod(@PathVariable("qqnum") String qqnum){
        try {
            Thread.sleep(500);//延时500毫秒
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        QueryResult query = queryService.query(qqnum);
        return query;
    }
}
  1. 得出结果

现在我们分别访问两个地址:
http://127.0.0.1:8082/query/qqQueryFeign/980199757 使用feign伪装的接口调用。
http://127.0.0.1:8082/query/qq/980199757 使用RestTemaplte对象调用。
在这里插入图片描述
可以看到,左侧等待了500毫秒后(ribbon默认最大超时1秒),成功响应了数据给前端。而右侧则是被进行了降级处理(配置文件中设置的最大超时为100毫秒)。
这说明,在使用了Eureka和Feign的情况下,application.yml文件中的Ribbon负载均衡配置,只Feign所集成的Ribbon组件起作用。而非对Eureka所集成的Ribbon组件起作用。

Feign内置集成应用:Hystrix熔断器

在这里插入图片描述

介绍

Feign内部也集成了Hystrix熔断器。但是它的实现过程和我的上一篇文章跟乐乐学微服务!(三)SpringCloud组件熔断器 Hystrix中所介绍的不同。
它需要一个实现类去实现Feigon伪装接口(之前的ProviderServiceFeign.class),重写它的方法(qqQuery),然后这个重写的方法体就是用于处理服务降级的方法。

实现

  1. Feign尽管内部集成了Hystrix,但默认是不开启状态的,所以需要先在配置文件中声明开启。
feign:
  hystrix:
    enabled: true # 声明feign内部集成的hystrix为开启状态。默认为关闭。
  1. 创建实现类去实现Feign伪装接口,去重写方法。该类和重写的方法将作为对应请求的服务降级方法。
@Component // 必须要使用@Compoent将实现类交由Spring管理。否则Controller层无法调用接口。
public class ProviderServiceFeignImpl implements ProviderServiceFeign {

    @Override
    public Object qqQuery(String qq) {
        return "查询正忙! 来自Fengin内置Hystirx组件的降级处理。";
    }
}
  1. 在Feign伪装接口的@FeignClient注解中,通过fallback属性指定它的实现类为服务降级处理类。

在这里插入图片描述

  1. 为了能够触发熔断机制,使得用户请求被降级处理,我们更改一下服务提供方中controller层的逻辑。
@RestController
@RequestMapping(value = "query")
public class QueryController {

    @Autowired
    private QueryService queryService;

    @GetMapping("qq/{qqnum}")
    public QueryResult qqQueryMethod(@PathVariable("qqnum") String qqnum){

        if (qqnum.equals("99999")){// 如果传入的参数是这个,就报异常。
            throw new RuntimeException("异常。。。");
        }

        QueryResult query = queryService.query(qqnum);
        return query;
    }
}

  1. 请求消费方,消费方调用Feign伪装的接口后,因为提供方抛出了异常,所以请求被Feign内置的hystrix熔断器进行降级方法处理了。
    在这里插入图片描述

关于独立引用Hystrix和Feign内置Hystirx

假如说,我们之前已经根据上一篇文章跟乐乐学微服务!(三)SpringCloud组件熔断器 引入了独立版本的Hystrix依赖。现在又使用Feign内置的Hystrix的话,会不会有冲突呢?
答案是:不会有冲突。
假如,用户所请求的消费方Controller层的方法内,是调用了Feign伪装的接口去请求提供方的话,那么将会使用Feign内置的Hystrix;如果需要降级处理,是让Feign伪装接口的实现类中的方法去处理。

假如,用户所请求的服务消费方Controller层的方法内,是通过RestTemaplte对象请求提供方的话。那么将会使用独立的Hystrix组件;如果需要降级处理的话,也是通过@HystrixCommand或@DefaultProperties注解所指定的方法去处理降级。
通过下面的图解,可以验证。
在这里插入图片描述

Feign应用:Gzip压缩

Feign可以将 请求 和 响应 的数据通过Gzip进行压缩,以此来减少数据交互过程中的性能损耗从而提高效率。

  • 开启request数据压缩,默认为false。

feign.compression.request.enabled=true

  • 设置要压缩的数据类型。默认为text/html,application/xml,application/json

feign.compression.request.mime-types=text/html,application/xml,application/json

  • 设置触发压缩请求数据的大小上线。默认值为2048(kb)
    feign.compression.request.min-request-size=2048

  • 开启response数据压缩,默认为false。
    feign.compression.response.enabled=true

转换为Yaml格式后如下:

feign:
  compression:
    request:
      enabled: true # 开启request数据压缩,默认为false。
      mime-types: text/html,application/xml,application/json # 要压缩的数据类型。此为默认值。
      min-request-size: 2048 # 触发压缩的大小上线。此为默认值(2mb)。
    response:
      enabled: true # 开启response数据压缩。默认为false。

Feign应用:日志级别设置

Feign也可以进行日志记录,不过需要创建一个配置类,然后将该类实例化为一个Bean给IOC容器管理,才能实现日志记录功能。

  1. 首先在消费方的application.yml进行日志参数配置。

其中需要指定一个包路径,这个路径一般涵盖了消费方的Controller层路径,或者还涵盖了Service,Dao这三层;这代表对该路径下的所有类发生的操作进行日志记录。
日志级别指定为debug

logging:
  level:
    com.databasequery.databasequeryconsumer: debug # 对com.databasequery.databasequeryconsumer包路径进行日志记录 日志级别为debug。

在这里插入图片描述

  1. 创建Feign的配置类,并在其中创建用于指定日志级别的方法,将该方法通过@Bean实例化。

日志级别有以下四个:

 * NONE:不记录任何日志信息,这是默认值。
 * BASIC:仅记录请求的方法,URL以及响应状态码和执行时间
 * HEADERS:在BASIC的基础上,额外记录了请求和响应的头信息
 * FULL:记录所有请求和响应的明细,包括头信息、请求体、元数据。
import feign.Logger;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
/**
 * Feign的配置类。主要用于配置
 */
@Configuration
public class FeignConfig {

    /**
     * 此处返回Feign的日志记录等级。
     * @return
     */
    @Bean
    Logger.Level logLevelInfo(){
        return Logger.Level.FULL;
    }

}
  1. 在Feign伪装接口,通过@FeignClient注解的configuration属性,指定其Feign配置类。
    在这里插入图片描述
  2. 一切配置好后,我们启动服务并尝试访问一下,能够看到可以输出用户的访问信息了。
    在这里插入图片描述
    不过要注意的是,只会对调用了feign伪装接口的请求进行日志记录,并不会对使用RestTemplate对象去调用提供方的请求进行记录。
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 6
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 6
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值