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包下定义接口, 用于和其他的服务器通信

  1. 接口上需要使用@FeignClient*(name = "item-service")注解, name参数是服务器的ID, 即配置文件中的服务名,
  2. 接口中的方法使用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,首先做基本基础配置:

  1. 添加 Hystrix 完整依赖
  2. 添加注解 @EnableCircuitBreaker
  3. 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 监控和熔断测试

步骤:

  1. 添加 actuator 依赖
  2. 暴露监控端点 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. 仪表盘监控以及并发测试

关于仪表盘监控, 请参考这里: [仪表盘监控]

关于并发测试: [并发测试]

posted @ 2020-08-30 09:46  zpk-aaron  阅读(635)  评论(0编辑  收藏  举报