
友情提醒
- 文末获取【真会玩】- SpringCloud Netflix 实战系列
Postman在线脚本
、Github仓库实战源码
- 【真会玩】- SpringCloud Netflix 实战系列有概念有实战,考验动手能力,如果实战中有操作没有达到与本文同等效果的请先仔细检查个人操作与文中相关内容是否一致,如检查无误请私信或评论区留言~
Feign和OpenFeign
- Feign是
Netflix
开发的声明式、模板化
的HTTP请求客户端。可以更加便捷、优雅地调用http api- Feign有一套自己的注解,
不支持
Spring MVC的注解- OpenFeign是Spring Cloud 在Feign的基础上支持了Spring MVC的注解,如@RequesMapping
- OpenFeign的
@FeignClient
可以解析SpringMVC的@RequestMapping
注解的接口,
并通过动态代理
的方式产生实现类,实现类中做负载均衡
并调用其他服务。- OpenFeign会根据带有注解的函数信息构建出网络请求的模板,在发送网络请求之前,OpenFeign会将函数的参数值设置到这些请求模板中
- 使用OpenFeign提供的注解修饰定义网络请求的接口类,就可以使用该接口的实例发送RESTful的网络请求。还可以集成
Ribbon
和Hystrix
,提供负载均衡
和断路器
工程搭建
新建
Feign-Api
、Feign-Provider
和Feign-Consumer
工程来演示Feign
的使用,现在我们开始创建工程,按以下顺序逐步创建
- 新建
Service-Api
- 新建
Feign-Provider
- 新建
Feign-Consumer
Service-Api搭建
Service-Api
只需要添加一个Spring Web
依赖即可
新建
ServiceApi
接口,暴露一个/pingFeignProvider
@RequestMapping("")
public interface ServiceApi {
@GetMapping("/pingFeignProvider")
String pingFeignProvider();
}
FeignProvider搭建
Feign-Provider
这边我们选上Spring Web
和Eureka Discovery Client
两个依赖即可,这边的SpringBoot
版本不用管,本次用的SpringCloud版本为 Hoxton.SR12, 所以SpringBoot版本要选2.3.12.RELEASE 这里是没有,我们稍后手动到pom文件里面修改版本即可
修改
pom
文件中spring-boot-starter-parent - version
为2.3.12.RELEASE
新建
application.yml
文件并添加以下配置
server:
port: 9090
spring:
application:
name: FeignProvider
eureka:
client:
service-url:
#向eureka发起注册请求
defaultZone: http://RhysNi:123456@eureka1.com:7901/eureka/
healthcheck:
enabled: true
instance:
#查找主机
hostname: localhost
instance-id: ${eureka.instance.hostname}:${spring.application.name}:${server.port}
将
Service-Api
作为依赖添加到Feign-provider
groupId
记得根据自己定义的进行修改
<dependency>
<groupId>com.rhys</groupId>
<artifactId>Service-Api</artifactId>
<version>0.0.1-SNAPSHOT</version>
</dependency>
新建
FeignProviderController
,由于我们将Service-Api
作为依赖添加到Feign-provider
了,可以直接实现ServiceApi
接口那有兄弟要问了:“这样的话我如果想像以前一样直接调用这个接口该怎么调用呢?”
- http://localhost:9090/pingFeignProvider 这样就可以了,照常调用就可以了,接口路径保持
ServiceApi
中的路径相同即可
@RestController
public class FeignProviderController implements ServiceApi {
@Override
public String pingFeignProvider() {
return "Ping Feign Provider Success";
}
}
Feign-Consumer搭建
同样的在左侧栏里面找到并勾选
Spring Web
和Eureka Discovery Client
、OpenFeign
三个依赖
同
Feign-Provider
一样方式修改SpringCloud 和 SpringBoot版本 (修改方式同上,忘记的点击前方关键词跳转查看)
新建
application.yml
文件并添加以下配置
server:
port: 9080
spring:
application:
name: FeignConsumer
eureka:
client:
service-url:
#向eureka发起注册请求
defaultZone: http://RhysNi:123456@eureka1.com:7901/eureka/
healthcheck:
enabled: true
instance:
#查找主机
hostname: localhost
instance-id: ${eureka.instance.hostname}:${spring.application.name}:${server.port}
特殊说明:
- 上边的
defaultZone
配置项里面我带了一个RhysNi:123456
这个是因为我的Eureka-Server
开启了Spring Security
安全认证,所以需要用户名密码才能成功注册到Eureka
,如果没有集成过Spring Security
把这个defaultZone
配置的值改为http://eureka1.com:7901/eureka/
即可- 还有一点,
defaultZone
配置项里面eureka1.com
这个是因为我在本地配置了hostname
映射了127.0.0.1
,想了解怎么配置的兄弟点击跳转查看配置方式
由于我们接下来要用
Feign
调用接口,所以要在Feign-Consumer
的启动类上添加@EnableFeignClients
注解以支持
@SpringBootApplication
@EnableFeignClients
public class FeignConsumerApplication {
public static void main(String[] args) {
SpringApplication.run(FeignConsumerApplication.class, args);
}
}
将
Service-Api
作为依赖添加到Feign-consumer
groupId
记得根据自己定义的进行修改
<dependency>
<groupId>com.rhys</groupId>
<artifactId>Service-Api</artifactId>
<version>0.0.1-SNAPSHOT</version>
</dependency>
新建
FeignConsumerApi
接口,在接口上添加@FeignClient
注解并继承ServiceApi
接口(这样就不用我们再次声明一次接口了,减少冗余代码),@FeignClient
注解的name
属性填我们要调用的Feign-Provider
的服务名,我们刚设置的是FeignProvider
,这样就可以走Ribbon
进行负载均衡了此时便可以在需要调用的类中注入
ServiceApi
调用Feign-Provider
的接口了
@FeignClient(name = "FeignProvider")
public interface FeignConsumerApi extends ServiceApi {
}
新建
FeignConsumerController
并注入FeignConsumerApi
@RestController
public class FeignConsumerController {
@Resource
private FeignConsumerApi feignConsumerApi;
@GetMapping("/testOpenFeign")
public String testOpenFeign() {
return feignConsumerApi.pingFeignProvider();
}
}
- 启动
Eureka-Server
服务,启动集群还是单体在本地无所谓,爱动手的兄弟们可以玩玩高可用,Eureka服务端搭建 、Eureka服务端高可用搭建- 启动两个
Feign-Provider
服务,IDEA应用开启多实例- 启动一个
Feign-Consumer
服务- 调用
Feign-Consumer
中的/testOpenFeign
接口
可以看到所有服务都在Eureka注册成功了
调用
http://localhost:9080/testOpenFeign
接口
超时案例
在
Feign-Consumer
服务调用方模块中添加如下配置
ribbon:
#连接超时(ms)
ConnectTimout: 1000
#逻辑响应超时(ms)
ReadTimout: 3000
我们模拟一下超时场景,在
FeignProviderController
中让这个接口睡上5秒
@RestController
public class FeignProviderController implements ServiceApi {
private AtomicInteger requestCount = new AtomicInteger();
@Value("${server.port}")
private String port;
@Override
public String pingFeignProvider() {
try {
System.out.println("开始模拟超时");
TimeUnit.MILLISECONDS.sleep(5000);
} catch (InterruptedException e) {
throw new RuntimeException();
}
return "Ping Feign Provider Port:" + port + " Success Count:"+requestCount.incrementAndGet();
}
}
我们配置的逻辑响应超时是3s,所以当
Feign-Consumer
调用Feign-Provider
的/pingFeignProvider
接口时就会认为接口响应超时了
Ribbon对于超时还有重试机制,比如咱们起的
Feign-Provider
服务为多实例,Ribbon则会基于负载均衡对其余节点依次执行重试机制
重试机制
关于重试机制也是有配置项可配的,一起来看看怎么配
Feign默认支持Ribbon
Ribbon的重试机制和Feign的重试机制有冲突,所以源码中默认关闭Feign的重试机制,使用Ribbon的重试机制
ribbon重试机制,请求失败后,每6秒会重新尝试
ribbon:
#同一台实例最大重试次数,不包括首次调用
MaxAutoRetries: 1
#重试负载均衡其他的实例最大重试次数,不包括首次调用
MaxAutoRetriesNextServer: 1
#是否所有操作都重试
OkToRetryOnAllOperations: false
注意,接下来启动服务才是本次演示讲究的地方
- 用
睡眠
的那套代码启动一个实例- 在注释掉
睡眠
代码,启动两个实例- 总共三个实例,模拟Ribbon的重试和
服务降级
(非熔断降级),这边降级意思就是重试一定次数后,在一定时间内
(一般6秒)就不会再去调这个服务节点,6秒后再有请求过来会再次尝试去调用该服务节点
最后再调用
Feign-Consumer
的/testOpenFeign
接口
- 可以看到每次调用到
超时
的节点时都会进行一次重试,一共是调用两次该接口,所以控制台每次都会打印两行模拟重试的提示信息
,在重试还是失败的情况下会去调用其他节点进行重试,如果其他节点调用成功则返回
源码&脚本获取地址
- Postman脚本:
https://www.getpostman.com/collections/8a0954746646f0dee9a6
- 脚本可直接复制到Postman使用
Link
方式导入- 实战源码仓库:
https://github.com/RhysNi/SpringCloudFamilyMeals.git