OpenFeign组件的使用

168 阅读8分钟

OpenFeign组件的使用

demo地址

gitee.com/w--kk/open-…

说明

  1. 什么Feign组件 ---> OpenFeign组件
    历史: Feign(Netflix)----> 维护状态----> SpringCloud OpenFeign(Spring)  这两个组件现在使用: 特性 使用方式一致
    简介: Rest client: OpenFeign RestTemplate 作用一致, 都是一个http客户端
    RestTemplate: spring框架封装HttpClient对象
    OpenFeign: 伪HttpClient客户端对象(它相当于把RestTemplate包装了) 他可以使服务间通信变得更加简单。 Feign默认集成了Ribbon组件。

    简单:

    1. 使用 写一个接口 加一个注解
    2. 调用服务代码 更加简单 自动完成数据传递过程中对象转换
  2. 为什么使用openFeign?
    a. RestTemplate 使用问题:
    1.路径写死  2.不能自动转换响应结果为对应对象  3.必须集成ribbon实现负载均衡
    b. openFeign组件  解决RestTemplate实现服务间通信所有问题

图中的3个都可以完成系统间的调用 image.png

  1. 使用OpenFeign

    1. 创建两个独立springboot 应用,并注册到服务注册中心 consul
    2. 引入服务注册中心依赖
    <!--引入consul依赖-->
    <dependency>
        <groupId>org.springframework.cloud</groupId>
            <artifactId>
                spring-cloud-starter-consul-discovery
            </artifactId>
    </dependency>
    
    <!-- 这个包是用做健康度监控的-->
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-actuator</artifactId>
    </dependency>
    
    1. 修改配置文件
    erver.port=8086
    spring.application.name= CATEGORY
    
    #注册到consul server
    spring.cloud.consul.host=localhost
    spring.cloud.consul.port=8500
    
    1. 入口类加入注解
    @SpringBootApplication
    @EnableDiscoveryClient //代表这是一个客户端
    public class ProductApplication {
        public static void main(String[] args) {
        SpringApplication.run(ProductApplication.class,args);
        }
    }
    
    1. 使用openfeign进行调用
      a. 在服务调用方引入openFeign依赖

      <!--Open Feign依赖-->
      <dependency>
          <groupId>org.springframework.cloud</groupId>
          <artifactId>spring-cloud-starter-openfeign</artifactId>
      </dependency>
      

      b. 在服务调用方入口类加入注解 开启Feign调用支持
      @EnableFeignClients //开启openfein客户端调用

      c. 开发客户端接口

      @FeignClient(value="PRODUCT") //value: 用来书写调用服务服务id
      public interface ProductClient {
      
          //调用商品服务
          @GetMapping("/product")
          String product();
      
          @GetMapping("/list")
          String list();
      }
      
  • cloud.spring.io/spring-clou…
  • Feign是一个声明式的伪Http客户端,它使得写Http客户端变得更简单。使用Feign,只需要创建一个接口并注解。它具有可插拔的注解特性(可以使用springmvc的注解),可使用Feign 注解和JAX-RS注解。Feign支持可插拔的编码器和解码器。
  • Feign默认集成了Ribbon,默认实现了负载均衡的效果并且springcloud为feign添加了springmvc注解的支持。

1. openFeign服务调用

  1. 服务调用方引入依赖OpenFeign依赖
<!--Open Feign依赖-->
<dependency>
    <groupId>org.springframework.cloud</groupId>
    <artifactId>spring-cloud-starter-openfeign</artifactId>
</dependency>
  1. 入口类加入注解开启OpenFeign支持
@SpringBootApplication
@EnableFeignClients
public class Users9999Application {
    public static void main(String[] args) {
        SpringApplication.run(Users9999Application.class, args);
    }
}
  1. 创建一个客户端调用接口
//value属性用来指定:调用服务名称
@FeignClient("PRODUCTS")
public interface ProductClient {
  
    @GetMapping("/product/findAll") //书写服务调用路径
    String findAll();
}
  1. 使用feignClient客户端对象调用服务
//注入客户端对象
@Autowired
private ProductClient productClient;

@GetMapping("/user/findAllFeignClient")
public String findAllFeignClient(){
  log.info("通过使用OpenFeign组件调用商品服务...");
  String msg = productClient.findAll();
  return msg;
}
  1. 访问并测试服务

服务间通信之参数传递和响应处理

  1. 微服务架构中服务间通信手段
    http协议: springcloud
    两种方式:1.RestTemplate + Ribbon  2.OpenFeign  推荐

  2. 服务间通信, 参数传递和响应处理
    参数传递:1.传递零散类型参数  2.传递对象类型  3.数组或集合类型参数

  3. 零散类型参数传递 (OpenFeign:伪HttpClient对象

    queryString方式传递参数(请求参数):?id=wkk
    注意:在openfeign接口声明中必须给参数加入注解 @RequestParam

        //声明调用商品服务中test?name=xxx&age=23接口传递name,age 请求参数在(openfeign是伪Httpclient客户端)
        @GetMapping("/test")
        String test(@RequestParam("name") String name,@RequestParam("age") Integer age);
    

报错(解决方法:添加@RequestParam) image.png

路径传递参数: url/wkk/23
注意: 在openfeign接口声明中必须给参数加入注解 @PathVariable

```java
//声明调用商品服务中test1接口 路径传递数据
@GetMapping("/test1/{id}/{name}")
String test1(@PathVariable("id") Integer id, @PathVariable("name") String name);
```

4. 对象类型参数传递
a. form表单方式
b. application/json方式

//定义一个接受对象类型参数接口
@PostMapping("/test2")
public String test2(@RequestBody Product product){
    log.info("product:{}",product);
    return "test2 ok,当前服务端口为: "+port;
}

注意: 使用json方式在openfeign接口声明中必须给参数加入注解 @RequestBody

2. 调用服务并传参

GET方式调用服务传递参数

  1. 说明
  • 服务和服务之间通信, 不仅仅是调用, 往往在调用过程中还伴随着参数传递, 接下来重点来看看OpenFeign在调用服务时如何传递参数
// 1.商品服务中添加如下方法
 @GetMapping("/product/findOne")
public Map<String,Object> findOne(String productId){
  log.info("商品服务查询商品信息调用成功,当前服务端口:[{}]",port);
  log.info("当前接收商品信息的id:[{}]",productId);
  Map<String, Object> map = new HashMap<String,Object>();
  map.put("msg","商品服务查询商品信息调用成功,当前服务端口: "+port);
  map.put("status",true);
  map.put("productId",productId);
  return map;
}
//2.用户服务中在product客户端中声明方法
@FeignClient("PRODUCTS")
public interface ProductClient { 
	@GetMapping("/product/findOne")
 	String findOne(@RequestParam("productId") String productId);
}
//3.用户服务中调用并传递参数
//注入客户端对象
@Autowired
private ProductClient productClient;

@GetMapping("/user/findAllFeignClient")
public String findAllFeignClient(){
  log.info("通过使用OpenFeign组件调用商品服务...");
  String msg = productClient.findAll();
  return msg;
}

测试访问

post方式调用服务传递参数

2.post方式调用服务传递参数
- 在商品服务中加入需要传递参数的服务方法来进行测试
- 在用户服务中进行调用商品服务中需要传递参数的服务方法进行测试
//1.商品服务定义对象
@Data
public class Product {
    private Integer id;
    private String name;
    private Date bir;
}
//2.商品服务定义接收对象的方法
@PostMapping("/product/saveProduct")
public Map<String,Object> saveProduct(@RequestBody Product product){
  log.info("商品服务保存商品信息调用成功,当前服务端口:[{}]",port);
  log.info("当前接收商品名称:[{}]",product);
  Map<String, Object> map = new HashMap<String,Object>();
  map.put("msg","商品服务查询商品信息调用成功,当前服务端口: "+port);
  map.put("status",true);
  map.put("product",product);
  return map;
}
//3.将商品对象复制到用户服务中
//4.用户服务中在product客户端中声明方法
@FeignClient("PRODUCTS")
public interface ProductClient {
  @PostMapping("/product/saveProduct")
  String saveProduct(@RequestBody Product product);
}
// 5.在用户服务中调用保存商品信息服务
//注入客户端对象
@Autowired
private ProductClient productClient;

@GetMapping("/user/saveProduct")
public String saveProduct(Product product){
  log.info("接收到的商品信息:[{}]",product);
  String save = productClient.saveProduct(product);
  log.info("调用成功返回结果: "+save);
  return save;
}

测试

3. OpenFeign超时设置

  1. 超时说明
  • 默认情况下, openFiegn在进行服务调用时, 要求服务提供方处理业务逻辑时间必须在1S内返回, 如果超过1S没有返回则OpenFeign会直接报错, 不会等待服务执行, 但是往往在处理复杂业务逻辑是可能会超过1S, 因此需要修改OpenFeign的默认服务调用超时时间。
  • 调用超时会出现如下错误:

image.png

  1. 模拟超时
  • 服务提供方加入线程等待阻塞 image.png
  1. 进行客户端调用

  2. 修改OpenFeign默认超时时间

feign.client.config.PRODUCTS.connectTimeout=5000  #配置指定服务连接超时
feign.client.config.PRODUCTS.readTimeout=5000	#配置指定服务等待超时
#feign.client.config.default.connectTimeout=5000  	#配置所有服务连接超时
#feign.client.config.default.readTimeout=5000	#配置所有服务等待超时

4. OpenFeign调用详细日志展示

openFeign伪Httpcient客户端对象, 用来帮助我们完成服务间通信  底层用http协议  完成服务间调用

默认openFeign日志功能需要手动开启

OpenFeign细节

  1. OpenFeign默认超时处理
    默认的调用超时:  使用openFeign组件在进行服务间通信时要求被调用服务必须在1s内给予响应,一旦服务执行业务逻辑时间超过1s, OpenFeign组件将直接报错:  Read timed out executing GET http://PRODUCT/product

  2. 修改openFeign超时时间
    a. 指定服务修改某个服务调用超时时间

feign.client.config.PRODUCT.connectTimeout=5000
feign.client.config.PRODUCT.readTimeout=5000

b. 修改openfeign默认调用所有服务超时间

# 配置openfeign默认超时时间  默认时间 单位毫秒
feign.client.config.default.connectTimeout=5000
feign.client.config.default.readTimeout=5000
  1. OpenFeign日志展示
    OpenFeign伪Httpclient客户端对象,用来帮助我们完成服务间通信底层用http协议完成服务间调用
    日志: 更好方便在开发过程中调试OpenFeign数据传递, 和响应处理, OpenFeign在设计时添加了日志功能OpenFeign, 默认openFeign日志功能需要手动开启的

日志使用

  1. 说明
  • 往往在服务调用时我们需要详细展示feign的日志, 默认feign在调用是并不是最详细日志输出, 因此在调试程序时应该开启feign的详细日志展示。
    feign对日志的处理非常灵活可为每个feign客户端指定日志记录策略,每个客户端都会创建一个logger默认情况下logger的名称是feign的全限定名需要注意的是,feign日志的打印只会DEBUG级别做出响应。

  • 我们可以为feign客户端配置各自的logger.level对象,告诉feign记录那些日志logger.level有以下的几种值

    NONE 不记录任何日志
    BASIC 仅仅记录请求方法,url,响应状态代码及执行时间
    HEADERS 记录Basic级别的基础上,记录请求和响应的header
    FULL 记录请求和响应的header,body和元数据

  1. 开启日志展示
feign.client.config.PRODUCTS.loggerLevel=full  #开启指定服务日志展示
#feign.client.config.default.loggerLevel=full  #全局开启服务日志展示
logging.level.org.wkk.feignClient=debug
#指定feign调用客户端对象所在包,必须是debug级别
  1. 测试服务调用查看日志

image.png

OpenFeign默认将Ribbon作为负载均衡器,直接内置了 Ribbon