Spring Cloud Feign(声明式/模板化的HTTP客户端)

来源

Feign使得 Java HTTP 客户端编写更方便。Feign 灵感来源于RetrofitJAXRS-2.0WebSocketFeign 最初是为了降低统一绑定DenominatorHTTP API 的复杂度,不区分是否支持 Restful

Retrofit是Square开发的一个AndroidJavaREST客户端库。
github地址:https://github.com/square/retrofit

JAX-RS(Java API for RESTful Web Services) 2.0 又称JSR 339 不仅定义了一套用于构建 RESTful 网络服务的 API,同时也通过增强客户端 API 功能简化了REST 客户端的构建过程。
github地址:https://github.com/eclipse-ee4j/jaxrs-api
WebSocket 是一种网络通信协议。RFC6455 定义了它的通信标准。
协议说明:https://tools.ietf.org/html/rfc6455

Denominator是一个用于操作DNS云的可移植Java
github地址:https://github.com/Netflix/Denominator

简介

Spring Cloud Netflix 的微服务都是以 HTTP 接口的形式暴露的,
所以调用方式有:
JDK原生的URLConnection
Apache的Http Client
Netty的异步HTTP Client
Spring的RestTemplate
Feign
而 Feign 是一个使用起来更加方便的 HTTP 客戶端,使用起来就像是调用自身工程的方法,而感觉不到是调用远程方法。feign还支持可插拔的编码器和解码器,Spring在用的时候增加了对@requestMapping的处理,Feign 的目的是尽量的减少资源和代码来实现和HTTP API的连接。通过自定义的编码解码器以及错误处理,可以编写任何基于文本的HTTP API

github地址:https://github.com/OpenFeign/feign
在源码中可以看到子模块包括RibbonHystrix,所以feign是基于RibbonHystrix的声明式服务调用组件。Feign是一种声明式、模板化的HTTP客户端。

`

实现声明式REST客户端Feign

引入Spring Cloud Feign依赖以及相关依赖

<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-web</artifactId>
</dependency>
<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>

注:网上有的文章说引入的依赖是spring-cloud-starter-feign,其实官方不再推荐使用,推荐使用spring-cloud-starter-openfeign

在应用主类中通过@EnableFeignClients注解开启Feign功能,因为要注册服务,所以还要使用@EnableEurekaClient

@SpringBootApplication
@EnableFeignClients
@EnableEurekaClient
public class SpringcloudFeignApplication {

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

修改yml配置文件

server:
  port: 8088
eureka:
  client:
    service-url:
      defaultZone: http://localhost:9090/eureka
spring:
  application:
    name: springcloud-feign-client

重点:Feign声明式/模块化体现

接下来定义服务接口类
使用@FeignClient("springcloud-eureka-client")注解来绑定该接口对应springcloud-eureka-client服务

@Component
@FeignClient(name = "springcloud-eureka-client")
public interface Client {
    @GetMapping("/client")
    public String getInfo();
}

通过声明式的注解,提供一个供其它服务调用的 Client。
@FeignClient用于通知Feign组件对该接口进行代理(不需要编写接口实现),使用者可直接通过@Autowired注入
注:多个feignCLient类中@FeignClient注解中的name值不能重复,url可以重复
Spring Cloud应用在启动时,Feign会扫描标有@FeignClient注解的接口,生成代理,并注册到Spring容器中。生成代理时Feign会为每个接口方法创建一个RequetTemplate对象,该对象封装了HTTP请求需要的全部信息,请求参数名、请求方法等信息都是在这个过程中确定的,Feign的模板化就体现在这里。

注意:绑定的接口服务必须是对应服务上存在的接口
例如我把接口名改为client123便会报如下错误

image.png

也就是找不到对应的接口服务,所绑定的springcloud-eureka-client没有client123接口

这是springcloud-eureka-client服务中的client接口

@RestController
public class DiscoveryController {
    @Autowired
    private DiscoveryClient discoveryClient;
    @Value("${server.port}")
    private String ip;

    @GetMapping("/client")
    public String client() {
        String services = "调用的服务是: " + discoveryClient.getServices()+" 对应的端口号 :"+ip;
        System.out.println("调用的服务是: " + discoveryClient.getServices()+" 对应的端口号 :"+ip);
        return services;
    }
}

调用上面定义的接口

@RestController
public class FeignClientController {
    @Autowired
    Client client;
    @GetMapping("/info")
    public String getInfo(){
        return client.getInfo();
    };
}

这里的接口名就任意取了,这里主要是获取绑定服务的接口的信息。

整体项目结构

Eureka服务端 端口号是9090
Eureka客户端 端口号是8082 服务名springcloud-eureka-client
feign消费者客户端 端口号是8088
(如需测试负载均衡的可以再启动一个端口号为8081的服务,服务名同样是springcloud-eureka-client)

启动服务进行测试

先启动服务端再启动客户端,客户端启动顺序没要求
访问http://localhost:9090服务注册中心

image.png

在服务注册中心可以看到,服务提供者和消费者都注册好了

访问feign定义的接口/infohttp://localhost:8088/info

image.png

测试负载均衡

服务列表

image.png

访问http://localhost:8088/info
image.png

刷新下,再次访问
image.png

实现了与Ribbon相同的负载均衡功能

实现Feign熔断

需要先写一个调用延迟或失败时调用的类

@Component
public class FailClass implements Client{
    @Override
    public String getInfo() {
        return "服务中断连接,请联系管理员";
    }
}

需要实现自定义服务接口的方法,以至于显示对应服务的对应接口调用失败的返回信息
然后在自定义服务接口中添加fallback异常处理回调。

@Component
@FeignClient(name = "springcloud-eureka-client",fallback = FailClass.class)
public interface Client {
    @GetMapping("/client")
    public String getInfo();
}

还需要在yml配置文件中开启熔断,默认为false

feign:
  hystrix:
    enabled: true

关闭两个springcloud-eureka-client服务后访问http://localhost:8088/info会显示

image.png

总结:

其实通过Feign封装了HTTP调用服务方法,使得客户端像调用本地方法那样直接调用方法,Feign本质上是个HTTP客户端
Feign继承特性用起来确实很方便,但是也带来一个问题,就是服务提供者和服务消费者的耦合度太高,此时如果服务提供者修改了一个接口的定义,服务消费者可能也得跟着变化,进而带来很多未知的工作量,如果通过此方法来实现接口共享的话,建议严格遵守面向对象的开闭原则,尽可能低做好前后版本兼容,防止因为版本原因造成接口定义的不一致。

推荐文章
Feign相关参数配置:https://blog.csdn.net/u012702547/article/details/78327668?locationNum=10&fps=1
Feign源码分析:https://blog.csdn.net/forezp/article/details/73480304

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 203,547评论 6 477
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 85,399评论 2 381
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 150,428评论 0 337
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,599评论 1 274
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,612评论 5 365
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,577评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 37,941评论 3 395
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,603评论 0 258
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 40,852评论 1 297
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,605评论 2 321
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,693评论 1 329
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,375评论 4 318
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 38,955评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,936评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,172评论 1 259
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 43,970评论 2 349
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,414评论 2 342

推荐阅读更多精彩内容