1.前言
上一节 讲述了如何通过 Ribbon + RestTemplate 的方式去消费服务,而在实际工作中,我们基本上都是使用 Feign 来完成调用。这篇就来说说如何通过 Feign 实现服务消费者去消费服务。
Feign 默认集成了 Ribbon,并和 Eureka 结合,默认实现了负载均衡的效果。其特点有:
- 可插拔的注解支持
- 支持可插拔的 HTTP 编码器和解码器
- 支持 Hystrix 和它的 Fallback
- 支持 Ribbon 的负载均衡
- 支持 HTTP 请求和响应的压缩
2.准备
三个角色,依旧使用上面章节已经创建好的工程:
- 服务注册中心:wei-eureka-server,端口 8090,启动一个(无需修改,正常启动)
- 服务提供者:wei-service-provider,分别以 8010、8011 端口启动一次,获得两个实例的集群(以端口号正常启动)
- 服务消费者:Feign,创建一个 wei-consumer-feign 模块,端口 8030(新建应用)
3.实践
3.1.创建服务消费者(Feign)
在项目上新建一个模块:wei-consumer-feign,创建方法与第一节创建模块过程类似。但在 Dependencies 选择依赖时需要注意以下:
a) 选择左侧的 Web 后,这里需要钩上 Web 项
b) 选择左侧的 Cloud Discovery 后,这里需要钩上 Eureka Discovery 项
c) 选择左侧的 Cloud Routing 后,这里需要钩上 Feign 项
最后点 Finish 按钮后,一个模块就自动生成了。
3.1.1.POM依赖
其 pom.xml 全内容如下:
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>com.wei</groupId>
<artifactId>wei-consumer-feign</artifactId>
<version>0.0.1-SNAPSHOT</version>
<packaging>jar</packaging>
<name>wei-consumer-feign</name>
<description>服务消费者(Feign)(Finchley版本)</description>
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.0.5.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>
<spring-cloud.version>Finchley.SR1</spring-cloud.version>
</properties>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>
</dependency>
<!--Feign实现声明式HTTP客户端-->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-openfeign</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</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>
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
</plugin>
</plugins>
</build>
</project>
3.1.2.配置服务消费者
编写配置 application.yml:
server:
port: 8030
spring:
application:
name: wei-cloud-feign # 指定进行服务注册时该服务的名称,服务与服务之间相互调用一般都是根据这个name
eureka:
client:
service-url:
defaultZone: http://localhost:8090/eureka/ # 指定进行服务注册的地址
这里,指定的服务注册中心地址为 http://localhost:8090/eureka/,服务名称为:wei-consumer-feign,程序端口为:8030,spring.application.name:指定进行服务注册时该服务的名称,服务与服务之间相互调用一般都是根据这个name。
3.1.3.编写配置Service
package com.wei.service.demo;
import org.springframework.cloud.openfeign.FeignClient;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.RequestParam;
/**
* 通过@FeignClient("Eureka服务名称"),来指定调用消费哪个服务
*/
@FeignClient(value = "wei-service-provider")
public interface IDemoFeignService {
/**
* 注解@RequestMapping,映射服务提供者中的URL
* @param name 入参
* @return
*/
@RequestMapping(value = "/demo/info", method = RequestMethod.GET)
String getDemoFeignServiceName(@RequestParam(value = "name") String name);
// Feign客户端和Ribbon类似,同样实现了客户端的负载均衡
// 与Ribbon不同的是,Feign的调用与本地接口的调用更加类似,并且更加便捷、更加优雅,传入参数较多时得以体现
}
注意,这个 Service 是一个接口类。通过@FeignClient("Eureka服务提供者名称"),来指定调用和消费哪个服务提供者。当前配置是消费服务提供者 wei-service-provider 的 “/demo/info” 接口。
3.1.4.编写配置Controller
package com.wei.controller.demo;
import com.wei.service.demo.IDemoFeignService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;
@RestController
public class DemoFeignController {
/**
* 编译器报错,无视。因为这个Bean是在程序启动的时候注入的,编译器感知不到,所以报错
*/
@Autowired
private IDemoFeignService iDemoFeignService;
@RequestMapping(value = {"/feign/demo/info", "/demo/info"}, method = RequestMethod.GET)
public String getDemoFeignName(@RequestParam(value = "name") String name) {
String result = iDemoFeignService.getDemoFeignServiceName(name);
result += "[Feign]";
System.out.println(result);
return result;
}
}
具体使用时,通过 Service层,调用服务提供者的方法就像调用本地方法一样进行调用即可。
3.1.5.配置main启动类
package com.wei;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.openfeign.EnableFeignClients;
/**
* 注解@EnableFeignClients,开启Feign客户端功能
*/
@SpringBootApplication
@EnableFeignClients
public class WeiConsumerFeignApplication {
public static void main(String[] args) {
SpringApplication.run(WeiConsumerFeignApplication.class, args);
}
}
以前使用注解@EnableDiscoveryClient向服务中心注册,因为Eureka2.0已经不需要,所以这里可以不用该注解。
通过 Spring Cloud Feign 来实现服务调用的方式非常简单,注解 @EnableFeignClients 即可开启 Feign 客户端功能。
最后,Run一下这个启动类。
4.测试
好了,一切准备就绪。我们就来验证一下吧。
4.1.验证服务注册中心
我们再去 Spring Eureka 的服务注册信息面板,看一看这个服务消费者有没有被Eureka所发现并注册进去。
![](https://i-blog.csdnimg.cn/blog_migrate/0b0d9cdfb3bf2d1c55bedaf9af5b1b10.png)
看来,一切正常。
4.2.验证服务消费者
好了,一切准备就绪。我们就来验证一下吧:
浏览器反复请求URL:http://localhost:8030/demo/info?name=tester 或者 http://localhost:8030/feign/demo/info?name=tester
Hi,tester,我是服务,我被调用了,服务名为:wei-service-provider,端口为:8010[Feign]
Hi,tester,我是服务,我被调用了,服务名为:wei-service-provider,端口为:8011[Feign]
我们可以看到浏览器也在8010和8011端口之间,也就是这个小的Service服务提供者集群之间交替打印输出内容。
到此,Feign 的负载均衡功能验证成功。论点2成立。
本节源码:https://github.com/itanping/wei-springcloud/tree/master/chapter03-feign
下一节,请关注:SpringCloud进击 | 四浅出:断路器(Hystrix)【Finchley版本】
5.总结
Feign 客户端和 Ribbon 类似,同样实现了客户端的负载均衡,但与 Ribbon 不同的是,Feign 的调用与本地接口的调用更加类似,并且更加便捷、更加优雅,传入参数较多时得以体现。
5.1.案例中有三个角色:
服务注册中心、服务提供者、服务消费者
5.2.它们的工作流:
- 启动服务注册中心
- 服务提供者 生产服务并注册到服务中心
- 服务消费者 从服务中心中获取服务并使用
5.3.此时的架构图:
![](https://i-blog.csdnimg.cn/blog_migrate/1043744d6cc6778bebbbcf6efef6e0bb.png)
6.物语
SpringCloud进击 | 一浅出:服务注册与发现(Eureka)【Finchley版本】
SpringCloud进击 | 二浅出:服务消费者(Ribbon+REST)【Finchley版本】
SpringCloud进击 | 三浅出:服务消费者(Feign)【Finchley版本】
SpringCloud进击 | 四浅出:断路器与容错(Hystrix)【Finchley版本】
SpringCloud进击 | 五浅出:服务网关 - 路由(Zuul Router)【Finchley版本】
SpringCloud进击 | 六浅出:服务网关 - 过滤器(Zuul Filter)【Finchley版本】
SpringCloud进击 | 七浅出:配置中心(Git配置与更新)【Finchley版本】
SpringCloud进击 | 一深入:配置中心(服务化与高可用)【Finchley版本】
SpringCloud进击 | 二深入:配置中心(消息总线)【Finchley版本】
SpringCloud进击 | 三深入:服务链路跟踪(Spring Cloud Sleuth)【Finchley版本】
SpringCloud进击 | 四深入:服务链路跟踪(Sleuth+Zipkin+RabbitMQ整合)【Finchley版本】
SpringCloud进击 | 五深入:断路器监控(Hystrix Dashboard)【Finchley版本】
SpringCloud进击 | 六深入:断路器聚合监控(Hystrix Turbine)【Finchley版本】
SpringCloud进击 | 七深入:高可用的服务注册中心【Finchley版本】