1. Feign简介
Feign
是一个声明式的Web服务客户端
,它使得写Web服务
变得更简单。使用Feign
,只需要创建一个接口并注解。它具有可插拔的注解特性,包括Feign
注解和JAX-RS
注解。Feign
同时支持可插拔的编码器
和解码器
。Spring Cloud
对SpringMVC
添加了支持,同时在Spring Web
中次用相同的HttpMessageConverter
。当我们使用Feign
的时候,Spring Cloud
整和了Ribbon
和Eureka
去提供负载均衡。
Feign
基于Netflix Feign
实现,整合了Spring Cloud Ribbon
与Spring Cloud Hystrix
,除了提供这两者的强大功能之外,它还提供了一种声明式的Web服务客户端
定义方式。
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
在源码中可以看到子模块包括Ribbon
和Hystrix
,所以Feign
是基于Ribbon
和Hystrix
的声明式服务调用组件。Feign
是一种声明式、模板化的HTTP
客户端。
2. 来源
Feign
使得Java HTTP
客户端编写更方便。Feign
灵感来源于Retrofit
、JAXRS-2.0
和WebSocket
。Feign
最初是为了降低统一绑定Denominator
到HTTP API
的复杂度,不区分是否支持Restful
。
Retrofit
是Square
开发的一个Android
和Java
的REST
客户端库。
github
地址:https://github.com/square/retrofitJAX-RS(Java API for RESTful Web Services) 2.0
又称JSR 339
不仅定义了一套用于构建RESTful
网络服务的API
,同时也通过增强客户端API
功能简化了REST
客户端的构建过程。
github
地址:https://github.com/eclipse-ee4j/jaxrs-apiWebSocket
是一种网络通信协议。RFC6455
定义了它的通信标准。
协议说明:https://tools.ietf.org/html/rfc6455Denominator
是一个用于操作DNS云
的可移植Java
库。
github
地址:https://github.com/Netflix/Denominator
3. 前期准备
- 一个服务注册中心
tairan-spring-cloud-eureka
,端口8761
。参考SpringCloud组件:搭建Eureka服务注册中心 - 创建
tairan-spring-cloud-feign-api
核心工程,对外提供api
接口。 - 创建服务提供者
tairan-spring-cloud-feign-privder
工程,提供/hello
接口,启动三个实例,端口分别为10001
,10002
,10003
,并注册到服务中心。参考SpringCloud组件:将微服务提供者注册到Eureka服务中心 - 创建服务消费者
tairan-spring-cloud-feign-consumer
工程,提供/feign-hello
接口,端口号为8080
,并注册到服务中心。
4. 构建项目
4.1 创建tairan-spring-cloud-feign-api
工程
同样的是采用idea
开发工具创建一个SpringBoot项目,然后引入Spring Cloud Feign
依赖以及相关依赖,项目的pom.xml
内容如下所示:
...//省略部分配置
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.1.1.RELEASE</version>
<relativePath/> <!-- lookup parent from repository -->
</parent>
<properties>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
<java.version>1.8</java.version>
</properties>
<dependencies>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-openfeign</artifactId>
</dependency>
</dependencies>
...//省略部分配置
注意:网上有的文章说引入的依赖是spring-cloud-starter-feign
,其实官方不再推荐使用,推荐使用spring-cloud-starter-openfeign
。
4.1.1 创建HelloService接口
在tairan-spring-cloud-feign-api
工程中只提供api
接口,具体实现由tairan-spring-cloud-feign-privder
工程实现。代码如下:
package com.tairan.chapter.feign.api;
import org.springframework.cloud.openfeign.FeignClient;
import org.springframework.web.bind.annotation.RequestMapping;
@FeignClient(value = "tairan-spring-cloud-feign-provider")
public interface HelloService {
@RequestMapping("/hello")
String getMessage() throws Exception;
}
4.2 创建tairan-spring-cloud-feign-privder
工程
同样的是采用idea
开发工具创建一个SpringBoot项目,然后引入Spring Cloud Feign
依赖以及tairan-spring-cloud-feign-api
依赖,项目的pom.xml
内容如下所示:
...//省略部分配置
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.1.1.RELEASE</version>
<relativePath/> <!-- lookup parent from repository -->
</parent>
<properties>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
<java.version>1.8</java.version>
<skipTests>true</skipTests>
<spring-cloud.version>Greenwich.RC1</spring-cloud.version>
</properties>
<dependencies>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>com.tairan.chapter</groupId>
<artifactId>tairan-spring-cloud-feign-api</artifactId>
</dependency>
</dependencies>
<dependencyManagement>
<dependencies>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-dependencies</artifactId>
<version>${spring-cloud.version}</version>
<type>pom</type>
<scope>import</scope>
</dependency>
</dependencies>
</dependencyManagement>
...//省略部分配置
4.2.1 创建HelloController
创建HelloController
类,并实现HelloService
接口,代码如下:
package com.tairan.chapter.feigin.provider.controller;
import com.tairan.chapter.feign.api.HelloService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.core.env.Environment;
import org.springframework.web.bind.annotation.RestController;
@RestController
public class HelloController implements HelloService {
@Autowired
private Environment environment;
@Override
public String getMessage() {
return environment.getProperty("spring.application.name") + ":" + environment.getProperty("server.port", "8080");
}
}
Environment
获取项目配置信息,本接口中返回项目服务名与端口号。
4.3 创建tairan-spring-cloud-feign-consumer
工程
同样的是采用idea
开发工具创建一个SpringBoot
项目,然后引入Spring Cloud Feign
依赖以及tairan-spring-cloud-feign-api
依赖,项目的pom.xml
内容如4.2 创建tairan-spring-cloud-feign-privder工程。
4.3.1 入口类
在应用主类中通过@EnableFeignClients
注解开启Feign
功能,因为需要注册到服务中心,所以还需要@EnableDiscoveryClient
注解,代码如下所示:
package com.tairan.chapter.feign.consumer;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.client.discovery.EnableDiscoveryClient;
import org.springframework.cloud.openfeign.EnableFeignClients;
@SpringBootApplication
@EnableDiscoveryClient
// 通过@EnableFeignClients注解开启Spring Cloud Feign的支待功能。
@EnableFeignClients("com.tairan.chapter.feign.api")
public class TairanSpringCloudFeignConsumerApplication {
public static void main(String[] args) {
SpringApplication.run(TairanSpringCloudFeignConsumerApplication.class, args);
}
}
4.3.2 创建FeignHelloController
类
创建FeignHelloController
实现对Feign
客户端的调用,代码如下:
package com.tairan.chapter.feign.consumer.controller;
import com.tairan.chapter.feign.api.HelloService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
@RestController
public class FeignHelloController {
@Autowired
private HelloService helloService;
@RequestMapping("/feign-hello")
public String getNodeInfo() throws Exception {
return helloService.getMessage();
}
}
5. 运行测试
我们已经完成所需工程的创建以及配置工作,接下来我们按照下面的步骤进行执行测试:
- 启动服务注册中心
tairan-spring-cloud-eureka
- 通过如下命令启动
tairan-spring-cloud-feign-privder
三个实例java -jar tairan-spring-cloud-feign-provider-1.0-SNAPSHOT.jar --server.port=10001 java -jar tairan-spring-cloud-feign-provider-1.0-SNAPSHOT.jar --server.port=10002 java -jar tairan-spring-cloud-feign-provider-1.0-SNAPSHOT.jar --server.port=10003
- 启动
tairan-spring-cloud-feign-consumer
服务- 访问
tairan-spring-cloud-feign-consumer
工程的/feign-hello
接口,链接:http://localhost:8080/feign-hello
所以服务启动完成后,打开tairan-spring-cloud-eureka
管理界面地址:http://localhost:8761,如下图所示:
5.1 访问/feign-hello
接口
访问链接:http://localhost:8080/feign-hello
连续访问如上接口链接,展示效果如下图所示:
6. 结论
Feign
实现了与Ribbon
同样的负载均衡的效果。
7. 源码位置
本章源码已经上传到淡若悠然
,请结合源码进行学习,感谢阅读。