概述

由来

在实际开发中,被调用方一般是将需要提供给外部的代码再次进行封装,而调用方则是根据提供的URL来进行调用开发。

在前面的组件介绍中,我们远程调用使用的是RestTemplate类中的方法。但是,使用此类来实现远程调用,我们需要在调用方进行拼接URL、封装请求等内容,并且每个程序猿的代码风格不同,这样不仅导致容易出错,还导致后期维护成本难,容易造成屎山代码。

综上所述,一种新型的组件横空出世。在调用方,它简单到像controller层调用service层一样;在被调用方,它只需一个注解就可以将被调用的服务和封装的接口绑定。这样,无论是服务提供方还是服务调用方,都大大减少了代码的开发。这个组件就是OpenFeign。

微服务之间的通信方式,通常有两种:RPC和HTTP。

在SpringCloud中,默认是使用HTTP来进行微服务的通信,最常用的实现形式有两种:

  • RestTemplate。
  • OpenFeign

功能

  • 支持SpringCloudLoadBalancer的负载均衡
  • 支持Sentinel和它的Fallback

代码案例

搭建商品服务

建模块

 写pom文件

采用的是Nacos + OpenFeign的组件。

<?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>
    <parent>
        <groupId>com.wbz</groupId>
        <artifactId>spring-cloud-test</artifactId>
        <version>1.0-SNAPSHOT</version>
    </parent>

    <artifactId>cloud-provider-product-open-feign-8401</artifactId>

    <properties>
        <maven.compiler.source>17</maven.compiler.source>
        <maven.compiler.target>17</maven.compiler.target>
        <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
    </properties>

    <dependencies>

        <!--SpringBoot通用模块-->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>

        <!--Lombok-->
        <dependency>
            <groupId>org.projectlombok</groupId>
            <artifactId>lombok</artifactId>
        </dependency>

        <!--Druid-->
        <dependency>
            <groupId>com.alibaba</groupId>
            <artifactId>druid-spring-boot-starter</artifactId>
        </dependency>

        <!--MySQL驱动-->
        <dependency>
            <groupId>com.mysql</groupId>
            <artifactId>mysql-connector-j</artifactId>
        </dependency>

        <!--MP-->
        <dependency>
            <groupId>com.baomidou</groupId>
            <artifactId>mybatis-plus-spring-boot3-starter</artifactId>
        </dependency>

        <!--注册中心-->
        <dependency>
            <groupId>com.alibaba.cloud</groupId>
            <artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId>
        </dependency>

        <!--配置中心-->
        <dependency>
            <groupId>com.alibaba.cloud</groupId>
            <artifactId>spring-cloud-starter-alibaba-nacos-config</artifactId>
        </dependency>

        <!--BootStrap.yml-->
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-bootstrap</artifactId>
        </dependency>

    </dependencies>

</project>

写yml文件

使用的是bootstrap.yml文件

server:
  port: 8401

spring:
  application:
    name: cloud-provider-product-open-feign-8401

  cloud:
    nacos:
      server-addr: 127.0.0.1:8848
      discovery:
        service: ${spring.application.name}
      config:
        prefix: ${spring.application.name}
        file-extension: yml

  profiles:
    active: dev

  mvc:
    pathmatch:
      matching-strategy: ant_path_matcher

  datasource:
    url: jdbc:mysql://127.0.0.1:3306/cloud_product?characterEncoding=utf8&useSSL=false&allowPublicKeyRetrieval=true&allowMultiQueries=true
    username: root
    password: root
    driver-class-name: com.mysql.cj.jdbc.Driver

mybatis-plus:
  configuration:
    map-underscore-to-camel-case: true
    log-impl: org.apache.ibatis.logging.stdout.StdOutImpl
  mapper-locations: classpath:mapper/**Mapper.xml
  type-aliases-package: com.wbz.domain

写主启动类

@MapperScan("com.wbz.mapper")
@SpringBootApplication
public class OpenFeignProductServerApplication8401 {

    public static void main(String[] args) {
        SpringApplication.run(OpenFeignProductServerApplication8401.class, args);
    }

}

写业务类

// JavaBean
@Data
@AllArgsConstructor
@NoArgsConstructor
@TableName("product_detail")
public class Product {

    @TableId
    private Long id;

    @TableField
    private String productName;

    @TableField
    private Long productPrice;

    @TableField
    private Integer state;

    @TableField
    @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss", timezone = "GMT+8")
    private LocalDateTime createTime;

    @TableField
    @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss", timezone = "GMT+8")
    private LocalDateTime updateTime;

}

// mapper接口
public interface ProduceMapper extends BaseMapper<Product> {
}

// service接口
public interface ProductService extends IService<Product> {

    Product getProductById(Long productId);

}

// service实现类
@Service
public class ProductServiceImpl extends ServiceImpl<ProduceMapper, Product> implements ProductService {

    @Override
    public Product getProductById(Long productId) {
        return this.getById(productId);
    }

}

// controller类
@RestController
@RequestMapping("/product")
public class ProductController {

    @Resource
    private ProductService productService;

    @GetMapping("/query/{productId}")
    public Product getProductById(@PathVariable Long productId) {
        return this.productService.getProductById(productId);
    }

}

项目启动之后,在Nacos的管理界面出现改服务就表示启动成功。 

搭建commons服务

在微服务开发中,一般某一个类可能会在多个服务中被调用,例如实体类。因此,我们就要自定义一个或者多个模块,把一些常用的,基础的类拿出来,封装成一个模块。这样,当我们其他服务进行使用时,引入一个pom依赖即可。

在个人开发中,我们直接install就会将构建好的模块放到本地maven仓库中,直接调用即可。在企业开发中,则是将写好的jar包放入到私服中,这样其他开发人员也可以进行调用。

由于我们的学习过程中的代码量非常小,因此我们就不建多个模块了,直接建一个模块,把远程调用的接口和实体类放到一起。

建模块

写pom文件 

<?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>
    <parent>
        <groupId>com.wbz</groupId>
        <artifactId>spring-cloud-test</artifactId>
        <version>1.0-SNAPSHOT</version>
    </parent>

    <artifactId>cloud-commons</artifactId>

    <properties>
        <maven.compiler.source>17</maven.compiler.source>
        <maven.compiler.target>17</maven.compiler.target>
        <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
    </properties>

    <dependencies>

        <!--Lombok-->
        <dependency>
            <groupId>org.projectlombok</groupId>
            <artifactId>lombok</artifactId>
        </dependency>

        <!--OpenFeign-->
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-openfeign</artifactId>
        </dependency>

        <!--MP-->
        <dependency>
            <groupId>com.baomidou</groupId>
            <artifactId>mybatis-plus-spring-boot3-starter</artifactId>
        </dependency>

        <dependency>
            <groupId>com.fasterxml.jackson.core</groupId>
            <artifactId>jackson-annotations</artifactId>
        </dependency>

    </dependencies>

</project>

写业务类

// 商品类
@Data
@AllArgsConstructor
@NoArgsConstructor
@TableName("product_detail")
public class Product {

    @TableId
    private Long id;

    @TableField
    private String productName;

    @TableField
    private Long productPrice;

    @TableField
    private Integer state;

    @TableField
    @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss", timezone = "GMT+8")
    private LocalDateTime createTime;

    @TableField
    @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss", timezone = "GMT+8")
    private LocalDateTime updateTime;

}
// 订单表
@Data
@NoArgsConstructor
@AllArgsConstructor
@TableName("order_detail")
public class Order {

    @TableId
    private Long id;

    @TableField
    private Long userId;

    @TableField
    private Long productId;

    @TableField
    private Integer num;

    @TableField
    private Long price;

    @TableField
    private Integer deleteFlag;

    @TableField
    @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss", timezone = "GMT+8")
    private LocalDateTime createTime;

    @TableField
    @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss", timezone = "GMT+8")
    private LocalDateTime updateTime;

    @TableField(exist = false)
    private Product product;

}
// 远程调用的接口,服务调用方直接引入该模块的依赖,然后调用即可
@FeignClient(value = "cloud-provider-product-open-feign-8401", path = "/product")
public interface ProductFeignApi {

    @GetMapping("/query/{productId}")
    Product getProductById(@PathVariable("productId") Long productId);

}

在cloud-commons模块搭建完成之后,在商品服务中删除实体类,然后引入该模块的依赖,观察是否够启动并调用成功。 

搭建订单服务

建模块

写pom文件

<?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>
    <parent>
        <groupId>com.wbz</groupId>
        <artifactId>spring-cloud-test</artifactId>
        <version>1.0-SNAPSHOT</version>
    </parent>

    <artifactId>cloud-consumer-order-open-feign-84</artifactId>

    <properties>
        <maven.compiler.source>17</maven.compiler.source>
        <maven.compiler.target>17</maven.compiler.target>
        <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
    </properties>

    <dependencies>

        <!--注册中心-->
        <dependency>
            <groupId>com.alibaba.cloud</groupId>
            <artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId>
        </dependency>

        <!--配置中心-->
        <dependency>
            <groupId>com.alibaba.cloud</groupId>
            <artifactId>spring-cloud-starter-alibaba-nacos-config</artifactId>
        </dependency>

        <!--bootstrap-->
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-bootstrap</artifactId>
        </dependency>

        <!--OpenFeign-->
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-openfeign</artifactId>
        </dependency>

        <!--负载均衡-->
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-loadbalancer</artifactId>
        </dependency>

        <!--web-->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>

        <!--MySQL驱动-->
        <dependency>
            <groupId>com.mysql</groupId>
            <artifactId>mysql-connector-j</artifactId>
        </dependency>

        <!--MP-->
        <dependency>
            <groupId>com.baomidou</groupId>
            <artifactId>mybatis-plus-spring-boot3-starter</artifactId>
        </dependency>

        <!--cloud-commons-->
        <dependency>
            <groupId>com.wbz</groupId>
            <artifactId>cloud-commons</artifactId>
            <version>1.0-SNAPSHOT</version>
        </dependency>

    </dependencies>

</project>

新增的pom文件有OpenFeign的依赖和cloud-commons的依赖,并且因为OpenFeign也实现了负载均衡,所以要把父子均衡的依赖也加上去。

        <!--OpenFeign-->
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-openfeign</artifactId>
        </dependency>

        <!--cloud-commons-->
        <dependency>
            <groupId>com.wbz</groupId>
            <artifactId>cloud-commons</artifactId>
            <version>1.0-SNAPSHOT</version>
        </dependency>

写yml文件

server:
  port: 84

spring:
  application:
    name: cloud-consumer-order-open-feign-84

  cloud:
    nacos:
      server-addr: 127.0.0.1:8848
      discovery:
        service: ${spring.application.name}
      config:
        prefix: ${spring.application.name}
        file-extension: yml

  profiles:
    active: dev

  mvc:
    pathmatch:
      matching-strategy: ant_path_matcher

  datasource:
    url: jdbc:mysql://127.0.0.1:3306/cloud_order?characterEncoding=utf8&useSSL=false&allowPublicKeyRetrieval=true&allowMultiQueries=true
    username: root
    password: root
    driver-class-name: com.mysql.cj.jdbc.Driver

mybatis-plus:
  configuration:
    map-underscore-to-camel-case: true
    log-impl: org.apache.ibatis.logging.stdout.StdOutImpl
  mapper-locations: classpath:mapper/**Mapper.xml
  type-aliases-package: com.wbz.domain

改主启动类

@MapperScan("com.wbz.mapper")
@SpringBootApplication
@EnableFeignClients // 服务调用
public class OpenFeignOrderConsumerApplication84 {

    public static void main(String[] args) {
        SpringApplication.run(OpenFeignOrderConsumerApplication84.class, args);
    }

}

新增一个@EnableFeignClients注解用来开启服务调用。 

写业务类

// mapper接口
public interface OrderMapper extends BaseMapper<Order> {
}

// service接口
public interface OrderService extends IService<Order> {

    Order getOrderById(Integer id);

}

// service实现类
@Slf4j
@Service
public class OrderServiceImpl extends ServiceImpl<OrderMapper, Order> implements OrderService {

    @Resource
    private ProductFeignApi productFeignApi;

    @Override
    public Order getOrderById(Integer id) {
        // 获取订单
        Order order = this.getById(id);
        // 远程调用
        Product product = this.productFeignApi.getProductById(order.getProductId());
        order.setProduct(product);
        // 返回结果
        return order;
    }

}

// controller实现类
@RestController
@RequestMapping("/order")
public class OrderController {

    @Resource
    private OrderService orderService;

    @GetMapping("/query/{id}")
    public Order getOrderById(@PathVariable Integer id) {
        return this.orderService.getOrderById(id);
    }

}

在上述的service实现类中可以看到,远程调用真的就像层与层之间的调用一样简单。

启动服务之后,输入127.0.0.1:84/product/query/1,出现下述结果就算成功:

 总结

到这里,使用OpenFeign进行远程调用的服务就搭建完成了。很容易能够看出,OpenFeign使用一行代码就实现了远程调用,所以相较于RestTemplate来说,更见简单方便。

在使用OpenFeign组件时,只需要引入对应依赖,然后在调用方使用@EnableFeignClients的注解,以及在客户端使用@FeignClient就能轻松解决问题。

OpenFeign参数传递

在OpenFeign的客户端接口中,进行参数绑定时不能省略,省略之后就会报错。

商品服务

@RestController
@RequestMapping("/product")
public class ProductController {

    @Resource
    private ProductService productService;

    @GetMapping("/query/{productId}")
    public Product getProductById(@PathVariable Long productId) {
        return this.productService.getProductById(productId);
    }

    @GetMapping("/test1")
    public String test1(Long productId) {
        return "商品服务 - 测试传递单个参数成功";
    }

    @GetMapping("/test2")
    public String test2(Long productId, Long id) {
        return "商品服务 - 测试传递多个参数成功";
    }

    @GetMapping("/test3")
    public String test3(Order order) {
        return "商品服务 - 测试传递对象成功";
    }

    @PostMapping("/test4")
    public String test4(@RequestBody Order order) {
        return "商品服务 - 测试传递json成功";
    }

}

cloud-commons

// 在OpenFeign中进行参数绑定时,不能省略。
@FeignClient(value = "cloud-provider-product-open-feign-8401", path = "/product")
public interface ProductFeignApi {

    // 传递URL上的参数
    @GetMapping("/query/{productId}")
    Product getProductById(@PathVariable("productId") Long productId);

    // 传递单个参数
    @GetMapping("/test1")
    String test1(@RequestParam("productId") Long productId);

    // 传递多个参数
    @GetMapping("/test2")
    String test2(@RequestParam("productId") Long productId,
                 @RequestParam("id") Long id);

    // 传递对象
    @GetMapping("/test3")
    String test3(@SpringQueryMap Order order);

    // 传递json
    @PostMapping("/test4")
    String test4(@RequestBody Order order);

}

订单服务

// controller类
@RestController
@RequestMapping("/order")
public class OrderController {

    @Resource
    private OrderService orderService;

    @GetMapping("/query/{id}")
    public Order getOrderById(@PathVariable Integer id) {
        return this.orderService.getOrderById(id);
    }

    @GetMapping("/test1/{id}")
    public String test1(@PathVariable Integer id) {
        return this.orderService.test1(id);
    }

    @GetMapping("/test2/{id}")
    public String test2(@PathVariable Integer id) {
        return this.orderService.test2(id);
    }

    @GetMapping("/test3/{id}")
    public String test3(@PathVariable Integer id) {
        return this.orderService.test3(id);
    }

    @GetMapping("/test4/{id}")
    public String test4(@PathVariable Integer id) {
        return this.orderService.test4(id);
    }

}

// serive接口
public interface OrderService extends IService<Order> {

    Order getOrderById(Integer id);

    String test1(@PathVariable Integer id);

    String test2(@PathVariable Integer id);

    String test3(@PathVariable Integer id);

    String test4(@PathVariable Integer id);

}

// service实现类
@Slf4j
@Service
public class OrderServiceImpl extends ServiceImpl<OrderMapper, Order> implements OrderService {

    @Resource
    private ProductFeignApi productFeignApi;

    @Override
    public Order getOrderById(Integer id) {
        // 获取订单
        Order order = this.getById(id);
        // 远程调用
        Product product = this.productFeignApi.getProductById(order.getProductId());
        order.setProduct(product);
        // 返回结果
        return order;
    }

    @Override
    public String test1(Integer id) {
        // 获取订单
        Order order = this.getById(id);
        // 远程调用
        return this.productFeignApi.test1(order.getProductId());
    }

    @Override
    public String test2(Integer id) {
        // 获取订单
        Order order = this.getById(id);
        // 远程调用
        return this.productFeignApi.test2(order.getProductId(), order.getId());
    }

    @Override
    public String test3(Integer id) {
        // 获取订单
        Order order = this.getById(id);
        // 远程调用
        return this.productFeignApi.test3(order);
    }

    @Override
    public String test4(Integer id) {
        // 获取订单
        Order order = this.getById(id);
        // 远程调用
        return this.productFeignApi.test4(order);
    }

}

高级特性

大致原理

在OpenFeign组件中,主要使用的两个注解就是在启动类上的@EnableFeignClients注解以及在客户端接口上的@FeignClient注解。

首先,主启动类上的@EnableFeignClients注解开启对Feign接口代理对象的构建以及装配。在这个注解中,导入了一个FeignClientsRegistrar的类,这个类会扫描添加了FeignClient注解的接口,并且创建远程调用的对象,然后将该对象注入到Spring容器中。这样,在我们进行远程调用的代码就可以直接进行注入,并且对于注入的内容来说,会生产一个RequestTemplate的请求模板实例,在其中存储了请求路径、请求参数等内容。在请求调用时,会生成一个Request请求实例,然后根据Feign.Client的负载均衡实例,选择合适的服务进行调用。

这只是大概的过程,并且我也没有翻阅源码,在网上找的一段教程来看从而给出的方法。

@EnableFeignClients

basePackages表示扫描指定的包;

basePackageClasses表示扫描指定的类或接口对应的包;

defaultConfiguration表示自定义的FeignClient配置;

clients表示扫描指定的接口,配置之后,不会根据类路径进行扫描。

这几个定义扫描的都是用来查找FeignClient接口所在的位置,原因是因为如果cloud-commons的包结构和订单服务的包结构不相同的话,那么就无法进行扫描,所以就得自己配置扫描路径。

@FeignClient

value是用来定义服务名称,当多实例部署时,需要名称去拉取服务列表,然后再进行负载均衡,从而找到合适的服务。

url是用来给出服务地址,当只有一个服务时,直接给出URL,然后就可以进行调用。

fallback和fallbackFactory都是用来进行服务降级等功能的,后续在Sentinel中会进行介绍。

path是用来表示统一前缀的,例如都是商品服务中一个类下都是以product为前缀的,就可以直接放在path中,减少代码。

超时处理

在SpringCloud微服务架构中,大部分公司都是利用OpenFeign进行服务间的调用,而比较简单的业务使用默认配置是不会出现问题的,但是如果业务比较复杂,服务间要进行比较繁杂的业务计算,那后台很有可能会出现ReadException这个依次,因此就要定制化配置超时时间。

测试:首先在商品服务让其睡眠10秒,然后在订单服务中配置超时时间为3秒:

spring:
  application:
    name: cloud-consumer-order-open-feign-84

  cloud:
    nacos:
      server-addr: 127.0.0.1:8848
      discovery:
        service: ${spring.application.name}
      config:
        prefix: ${spring.application.name}
        file-extension: yml

    openfeign:
      client:
        config:
          default:
            #连接超时时间
            connectTimeout: 3000
            #读取超时时间
            readTimeout: 3000

项目启动之后,输入127.0.0.1:84/query/product/1,等待一段时间发现如下报错:

官方默认的等待时间为60秒钟,服务端超过规定时间就会导致Feign客户端返回报错。为了避免这样的情况,我们就需要设置Feign客户端的超时控制。

我们不仅可以控制所有的超时时间,还可以针对不同的服务来设置不同的超时时间:

spring:

  cloud:
    nacos:
      server-addr: 127.0.0.1:8848
      discovery:
        service: ${spring.application.name}
      config:
        prefix: ${spring.application.name}
        file-extension: yml

    openfeign:
      client:
        config:
          default:
            #连接超时时间
            connectTimeout: 3000
            #读取超时时间
            readTimeout: 3000
          # 配置商品服务的超时时间,会覆盖全局的默认时间
          cloud-provider-product-open-feign-8401:
            #连接超时时间
            connectTimeout: 3000
            #读取超时时间
            readTimeout: 3000

 重试机制

OpenFeign默认没有开重试机制,可以通过配置类开启:

@Configuration
public class FeignConfig {

    @Bean
    public Retryer retryer() {
        // 初识间隔时间为100毫秒
        // 重试间最大间隔时间为1秒
        // 最大请求次数为3次
        return new Retryer.Default(100, 1, 3);
    }

}

为了测试,将订单服务中的代码进行如下修改:

项目启动之后,产生的日志为:

通过日志可以判断得出,我们添加的重试机制生效了。

请求/响应压缩

OpenFeign支持对请求/响应进行GZIP压缩,以减少通信过程中的性能损耗。

通过如下配置就可以实现相对应的压缩功能,并且还对请求压缩做了一些更细致的设置,比如下面的指定压缩数据类型以及指定触发压缩的大小。

spring:
    openfeign:
      client:
        config:
          default:
            #连接超时时间
            connectTimeout: 3000
            #读取超时时间
            readTimeout: 3000
          # 配置商品服务的超时时间,会覆盖全局的默认时间
          cloud-provider-product-open-feign-8401:
            #连接超时时间
            connectTimeout: 3000
            #读取超时时间
            readTimeout: 3000
      compression: # 压缩
        request:
          enabled: true
          min-request-size: 2048 #最小触发压缩的大小
          mime-types: text/xml,application/xml,application/json #触发压缩数据类型
        response:
          enabled: true

日志打印功能

Feign提供了日志打印功能,我们可以通过配置来调整日志级别,从而了解Feign中Http请求的细节。说白了就是对Feign接口的调用情况进行监控和输出。

Feign的日志级别有四种:

  • NONE:默认的,不显示任何日志;
  • BASIC:仅记录请求方法、URL、响应状态码及执行时间;
  • HEADERS:包含上述信息以及请求和响应的头信息;
  • FULL:包含上述信息以及请求和响应的正文及元数据。

想要开启日志打印功能,首先要进行配置类的配置,然后再写配置文件:

@Configuration
public class FeignConfig {

    @Bean
    Logger.Level feignLoggerLevel() {
        return Logger.Level.FULL;
    }

}
logging:
  level:
    com:
      wbz:
        api:
          ProductFeignApi: debug

点赞(0) 打赏

评论列表 共有 0 条评论

暂无评论

微信公众账号

微信扫一扫加关注

发表
评论
返回
顶部