feign 声明式客户端接口
feign 声明式客户端接口
解决问题: feign集成了远程调用
, ribbon
, hystrix
, 实现业务之间的远程调用及负载均衡的
微服务应用中,ribbon 和 hystrix 总是同时出现,feign 整合了两者,并提供了声明式消费者客户端
用 feign 代替 hystrix+ribbon
快速开始
1. 创建springboot项目导入依赖
依赖: Spring Boot Actuator
(监控工具), Eureka Discovery Client
(Eureka客户端), OpenFeign
(feign), Spring Web
(Web)
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-actuator</artifactId>
</dependency>
<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>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-openfeign</artifactId>
</dependency>
2. yml配置
spring:
application:
name: feign
server:
port: 3001
eureka:
client:
service-url:
defaultZone: http://eureka1:2001/eureka, http://eureka2:2002/eureka
3. 主程序添加注解
@EnableDiscoveryClient
(高版本可省略) 和 @EnableFeignClients
@EnableFeignClients // 开启Feign
@EnableDiscoveryClient // 注册中心(Eureka)客户端开启注解, 高版本可省略此注解
@SpringBootApplication
public class Sp09FeignApplication {
public static void main(String[] args) {
SpringApplication.run(Sp09FeignApplication.class, args);
}
}
4. 定义客户端通信接口
在feign包下定义接口, 用于和其他的服务器通信
- 接口上需要使用
@FeignClient*(name = "item-service")
注解, name参数是服务器的ID, 即配置文件中的服务名, - 接口中的方法使用SpringMVC的注解, 例如
@RequestMapping
,,@GetMapping
,@PostMapping
等
例如:
@FeignClient(name = "item-service") // name(别名value) 的属性为服务yml中配置的应用名
public interface ItemFeignClient {
@GetMapping("/{orderId}") // SpringMVC的注解
JsonResult<List<Item>> getItems(@PathVariable String orderId);
@PostMapping("/decreaseNumber") // SpringMVC的注解
JsonResult decrease(@RequestBody List<Item> items);
}
假如调用接口中的getItem方法, 例如getItem(7)
实际上就是发送了远程Http请求, 如下
http://IP:PORT/7
其中IP和PORT是由Eureka
注册中心所绑定的, 会根据应用名item-service
找到对应的ip和port
5. 编写Controlller
@RestController
@Slf4j
public class FeignController {
@Autowired
private ItemFeignClient itemFeignClient; // 注入接口对象, 对象由底层实现
@GetMapping("/item-service/{orderId}")
public JsonResult<List<Item>> getItems(@PathVariable String orderId) {
log.info("调用商品服务, 获得订单的商品列表");
return itemFeignClient.getItems(orderId); // 调用feign的接口, 远程通信
}
@PostMapping("/item-service/decreaseNumber")
public JsonResult deccreaseNumber(@RequestBody List<Item> items) {
log.info("调用商品服务, 减少商品库存");
return itemFeignClient.decrease(items); // 调用feign的接口, 远程通信
}
}
注意, 接口中的注解尽量和Controller保持一致, 例如@PathVariable
注解不能省略, 否则可能会出现链接失败异常
自行测试访问feign中的controller, 是否能够调用item-service的controller
案例执行流程图
案例总结
feign 利用了我们熟悉的 spring mvc 注解来对接口方法进行设置,降低了我们的学习成本。
通过这些设置,feign可以拼接后台服务的访问路径和提交的参数例如:
@GetMapping("/{userId}/score") JsonResult addScore(@PathVariable Integer userId, @RequestParam Integer score); 12
当这样调用该方法:
service.addScore(7, 100); 1
那么 feign 会向服务器发送请求:
http://用户微服务/7/score?score=100 1
- 注意:如果 score 参数名与变量名不同,需要添加参数名设置:
@GetMapping("/{userId}/score") JsonResult addScore(@PathVariable Integer userId, @RequestParam("score") Integer s
feign + ribbon 负载均衡和重试
- 无需额外配置,feign 默认已启用了 ribbon 负载均衡和重试机制。可以通过配置对参数进行调整
yml配置
如下yml配置:
# 所有服务都有效
ribbon:
ConnectTimeout: 1000 # 链接超时时间
ReadTimeout: 1000 # 读取超时时间
# 只对 item-service 有效
item-service:
ribbon:
MaxAutoRetries: 1 # 单台服务器最大自动重试次数
MaxAutoRetriesNextServer: 2 # 自动更换服务器次数
ConnectTimeout: 1000 # 链接超时时间
ReadTimeout: 500 # 读取超时时间
参数默认值
MaxAutoRetries: 0
MaxAutoRetriesNextServer: 1
ReadTimeout: 1000
feign + hystrix 降级
特殊需求,要启用Hystrix,首先做基本基础配置:
- 添加 Hystrix 完整依赖
- 添加注解 @EnableCircuitBreaker
- yml 配置启用 hystrix:
feign.hystrix.enabled=true
大体结构如下
// 声明式客户端接口添加注解属性
@FeignClient(name="item-service", fallback=降级类.class)
public interface ItemFeignClient {
}
//定义降级类,实现声明式客户端接口
public class 降级类 implements ItemFeignClient {
}
1. feign 启用 hystrix
feign 默认没有启用 hystrix,添加配置,启用 hystrix
feign.hystrix.enabled=true
yml中配置
feign:
hystrix:
enabled: true
降级超时时间配置
hystrix:
command:
default:
execution:
isolation:
thread:
timeoutInMilliseconds: 1000 # 按需求自行配置, 单位为毫秒(一般大于重试时间, 5-10秒即可)
2. feign 远程接口中指定降级类
我们上面使用了@FeignClient(name="item-service")
注解来制定了远程的服务器, 现在我们需要添加一个fallback
参数来指定降级类
...
@FeignClient(name="item-service", fallback = ItemFeignServiceFB.class)
public interface ItemFeignService {
...
}
3. 实现降级类
ItemFeignServiceFB
降级类需要实现远程调用的接口, 然后重写接口中的方法
当接口中的方法, 远程调用(出现异常、等待超时、不能连接)时, 会执行降级类中的重写方法
@Component
public class ItemFeignServiceFB implements ItemFeignService {
@Override
public JsonResult<List<Item>> getItems(String orderId) {
return JsonResult.err("无法获取订单商品列表");
}
@Override
public JsonResult decreaseNumber(List<Item> items) {
return JsonResult.err("无法修改商品库存");
}
}
可自行测试
feign + hystrix 监控和熔断测试
步骤:
- 添加 actuator 依赖
- 暴露监控端点 m.e.w.e.i=hystrix.stream
1. 依赖
快速开始案例中已经加过此依赖就不需要再加了
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-hystrix</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-actuator</artifactId>
</dependency>
2. 主程序注解
@EnableCircuitBreaker
主程序需要假如此注解
@EnableCircuitBreaker // hystrix
@EnableFeignClients // feign
@EnableDiscoveryClient // eureka注册中心客户端, 高版本可省略
@SpringBootApplication
public class Sp09FeignApplication {
public static void main(String[] args) {
SpringApplication.run(Sp09FeignApplication.class, args);
}
}
3.配置 actuator,暴露监控端点
management:
endpoints:
web:
exposure:
include: hystrix.stream # 只暴露 hystrix.stream 端点
4. 启动服务,查看监控端点
查看所有监控链接: http://localhost:3001/actuator
查看hystrix监控: http://localhost:3001/actuator/hystrix.stream
如果hystrix一直出现ping, 可尝试发送一次请求, 会不会出现一大坨信息, 如果还是没有一大坨信息, 可能时降级没有配置好,
5. 仪表盘监控以及并发测试
关于仪表盘监控, 请参考这里: [仪表盘监控]
关于并发测试: [并发测试]