【第四章】详解Feign的实现原理

  • Post author:
  • Post category:其他




1.1

Feign

概述

这篇文章主要讲述如何通过

Feign

去消费服务,以及

Feign

的实现原理的解析。


Feign



Netflix

开发的声明式、模板化的

HTTP

客户端,

Feign

可以帮助我们更快捷、优雅地调用

HTTP API


Feign

是个

HTTP

请求的轻量级客户端框架。通过 接口 + 注解的方式发起

HTTP

请求调用,面向接口编程,而不是像

Java

中通过封装

HTTP

请求报文的方式直接调用。服务消费方拿到服务提供方的接,然后像调本地接法样去调,实际发出的是远程的请求。让我们更加便捷和优雅的去调基于

HTTP



API

,被泛应在

Spring Cloud

的解决案中。

在前面的文章中可以发现当我们通过

RestTemplate

调用其它服务的

API

时,所需要的参数须在请求的

URL

中进行拼接,如果参数少的话或许我们还可以忍受,一旦有多个参数的话,这时拼接请求字符串就会效率低下,并且显得好傻。

那么有没有更好的解决方案呢?答案是确定的有,

Netflix

已经为我们提供了一个框架:

Feign


Feign

是一个声明式的

Web Service

客户端,它的目的就是让

Web Service

调用更加简单。

Feign

提供了

HTTP

请求的模板,通过编写简单的接口和插入注解,就可以定义好

HTTP

请求的参数、格式、地址等信息。



Feign

则会完全代理

HTTP

请求,我们只需要像调用方法一样调用它就可以完成服务请求及相关处理。

Feign

整合了

Ribbon



Hystrix

(关于

Hystrix

我们后面再讲),可以让我们不再需要显式地使用这两个组件。

总起来说,

Feign

具有如下特性:

  • 采用的是基于接口可插拔的注解支持,包括

    Feign

    注解和

    JAX-RS

    注解;
  • 支持可插拔的

    HTTP

    编码器和解码器;
  • 支持

    Hystrix

    和它的

    Fallback

    ,具有熔断降级的能力;
  • 支持

    Ribbon

    的负载均衡,具有负载均衡的能力;
  • 支持

    HTTP

    请求和响应的压缩。

这看起来有点像我们

Spring MVC

模式的

Controller

层的

RequestMapping

映射。这种模式是我们非常喜欢的。

Feign

是用

@FeignClient

来映射服务的。



1.2 为什么使用

Feign


Feign

的首要目标就是减少

HTTP

调用的复杂性。在微服务调用的场景中,我们调用很多时候都是基于

HTTP

协议的服务,如果服务调用只使用提供

HTTP

调用服务的

HTTP Client

框架(e.g. Apache HttpComponnets、HttpURLConnection OkHttp 等),我们需要关注哪些问题呢?

在这里插入图片描述

相比这些

HTTP

请求框架,

Feign

封装了

HTTP

请求调用的流程,而且会强制使用者去养成面向接口编程的习惯(因为

Feign

本身就是要面向接口)。



1.3

Feign

详解



1.3.1 代码示例

首先第一步,在原来的基础上新建一个

Feign

模块,接着引入相关依赖,引入

Feign

依赖,会自动引入

Hystrix

依赖的,如下所示:

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

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


application.yml

配置如下所示:

server:
  port: 8083
spring:
  application:
    name: feign-consumer
eureka:
  client:
    service-url:
      defaultZone: http://localhost:8888/eureka/,http://localhost:8889/eureka/

接着在前面文章中的的的两个

provider1



provider2

两个模块的服务新增几个方法,如下代码所示:

@RestController
public class HelloController {

    @RequestMapping("/hello")
    public String hello(){
        System.out.println("访问来1了......");
        return "hello1";
    }

    @RequestMapping("/hjcs")
    public List<String> laowangs(String ids){
        List<String> list = new ArrayList<>();
        list.add("laowang1");
        list.add("laowang2");
        list.add("laowang3");
        return list;
    }

    //新增的方法
    @RequestMapping(value = "/hellol", method= RequestMethod.GET)
    public String hello(@RequestParam String name) {
        return "Hello " + name;
    }

    @RequestMapping(value = "/hello2", method= RequestMethod.GET)
    public User hello(@RequestHeader String name, @RequestHeader Integer age) {
        return new User(name, age);
    }

    @RequestMapping(value = "/hello3", method = RequestMethod.POST)
    public String hello (@RequestBody User user) {
        return "Hello "+ user. getName () + ", " + user. getAge ();
    }

}

接着是上面代码所需用到的

User

类,代码如下所示:

public class User {

    private String name;
    private Integer age;

    //序列化传输的时候必须要有空构造方法,不然会出错
    public User() {
    }
    public User(String name, Integer age) {
        this.name = name;
        this.age = age;
    }
      //...getter setter省略
}

接下来用

Feign



@FeignClient(“服务名称”)

映射服务调用。代码如下所示:

package hjc;

import org.springframework.cloud.netflix.feign.FeignClient;
import org.springframework.web.bind.annotation.*;

//configuration = xxx.class  这个类配置Hystrix的一些精确属性
//value=“你用到的服务名称”

@FeignClient(value = "hello-service",fallback = FeignFallBack.class)
public interface FeignService {
  //服务中方法的映射路径
    @RequestMapping("/hello")
    String hello();

    @RequestMapping(value 



版权声明:本文为m0_67400972原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。