SpringCloud-Feign解决模块之间的远程调用

简介: SpringCloud-Feign解决模块之间的远程调用

一、什么是 OpenFeign

OpenFeign (以下统一简称为 Feign) 是 Netflix 开源的声明式 HTTP 客户端,集成了 Ribbon 的负载均衡、轮询算法和 RestTemplate 的 HTTP 调用等特性,并对其进行封装,使用者只需要在此基础上,定义一个接口,并在接口上标注一个 FeignClient ,便可以实现 HTTP 远程调用,上面的声明式 HTTP 如何理解,可以理解为只需要声明一个接口,Feign 就会通过你定义的接口,自动给你构造请求的目标地址并请求。


下面介绍下如何在项目中集成 Feign 组件,只需要遵循 SpringBoot 开发三板斧(1、加依赖,2、加注解,3、加配置)即可

二、环境准备

1、加依赖

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

2、启动类配置

@SpringBootApplication
@EnableFeignClients
public class Application {
    public static void main(String[] args) {
        SpringApplication.run(Application.class, args);
    }
}

3、配置文件application.yml

server:
  port: 8081
spring:
  cloud:
    nacos:
      discovery:
        server-addr: localhost:8848
  # 微服务名称
  application:
    name: user

三、代码开发

1、Feign调用

@FeignClient(name = "user")
public interface UserFeignClient {
    @GetMapping("/users/{id}")
    UserDto findById(@PathVariable Integer id);
}

@FeignClient(name = "user") 这里的user就是指你要远程调用服务的名称。如上述配置文件中application:name:user

@Service
public class ArticleController {
 
    @Resource
    private UserFeignClient userFeignClient;
 
    public ArticleDto findByUserId(Integer userId) {
        ... ...
        ArticleDto articleDto = this.userFeignClient.findById(userId);
        ... ...
        return articleDto;
 
    }
 
}

以上,就是 openFeign 的基本使用。

2、Feign的日志配置

由于 Feign 在没有配置的情况下是不会打印任何日志,如果想要看到 Feign 的日志,需要额外的配置;但是在此之前,我们先了解下 Feign 的自定义日志级别。

Feign 的自定义日志级别

级别 打印内容
NONE(默认值) 不记录任何日志
BASIC 仅记录请求方法、URL、响应状态码以及执行时间
HEADERS 记录 BASIC 级别的基础上,记录请求和响应的 header
FULL 记录请求和响应的 header、body 和元数据

Feign 的自定义日志级别可以通过 Java 代码方式或配置属性方式来实现,下面我们先介绍下代码的实现方式

代码配置方式

  1. 编写一个 Configuration 的类
public class UserFeignConfiguration {
    @Bean
    public Logger.Level level() {
        //  生产上不建议使用FULL,这样会产生大量的日志,影响性能的同时还不好定位问题。
        //  建议使用 BASIC
        return Logger.Level.FULL;
    }
}

然后在对应的 Feign 接口设置 Configuration 类

@FeignClient(name = "user", configuration = UserFeignConfiguration.class)
public interface UserFeignClient {
    @GetMapping("/users/{id}")
    UserDto findById(@PathVariable Integer id);
}

最后还要将 Feign接口类的全路径设置在 yml 文件里面

logging:
  level:
  # Feign接口类的全路径 
  # Feign的日志级别是建立在Feign的接口 debug 级别之上的
    com.example.article.feignclient.UserFeignClient: debug

当调用接口时,输出日志结果如下

[UserFeignClient#findById] <--- HTTP/1.1 200 (794ms)
[UserFeignClient#findById] content-type: application/json;charset=UTF-8
[UserFeignClient#findById] date: Mon, 29 Aug 2022 10:56:27 GMT
[UserFeignClient#findById] transfer-encoding: chunked
[UserFeignClient#findById] 
[UserFeignClient#findById] {"id":1,"username":"张三","createTime":"2022-08-25T17:17:04.000+0000","updateTime":"2022-08-25T17:17:04.000+0000"}
[UserFeignClient#findById] <--- END HTTP (180-byte body)

这样,通过代码来设置 Feign 的日志自定义级别方式就配置好了。但是这样,并不是完美的解决方案,就相当于每次新建一个 Feign 接口,就要编写一个对应的 xxxFeignConfiguration 类,然后在 Feign 接口上指定,这样下来太繁琐了,下面看下全局的代码配置方式:


不需要在 每个 Feign 接口上面都要配置下 configuration = UserFeignConfiguration.class,我们只需要在 Application 启动类上面,指定 @EnableFeignClients(defaultConfiguration = GlobalFeignConfiguration.class),注:这里将 UserFeignConfiguration 已经更名为 GlobalFeignConfiguration

@SpringBootApplication
@EnableFeignClients(defaultConfiguration = GlobalFeignConfiguration.class)
public class Application {
    public static void main(String[] args) {
        SpringApplication.run(Application.class, args);
    }
}

属性配置方式

在 application.yml 加入只需要配置以下的属性既可以实现 Feign 的自定义级别

feign:
  client:
    config:
      # 微服务名称
      user:
        loggerLevel: full

同理,yml 文件也支持 全局的属性配置方式

feign:
  client:
    config:
      # 全局配置(default 默认就是适用于全部微服务)
      default:
        loggerLevel: full

3、Feign的多参数请求构造

GET 请求

请求多参数的URL,如请求地址为 http://www.xxx.me/admin/user/get?username=张三&school=阳光小学&birthDay=2012-08-01,SpringCloud 为 Feign 整合了 SpringMVC 的注解支持

@SpringQueryMap 注解

@FeignClient("user")
public interface UserFeignClient {
  @RequestMapping(value = "/get", method = RequestMethod.GET)
  public User get(@SpringQueryMap User user);
}

@RequestParam注解(表单传参)

@FeignClient("user")
public interface UserFeignClient {
  @RequestMapping(value = "/get", method = RequestMethod.GET)
  public User get(@RequestParam("username") String username, @RequestParam("school") String school, @RequestParam("birthDayDay") String birthDay);
}

@PathVariable注解(URL携带参数)

@FeignClient("user")
public interface UserFeignClient {
  @RequestMapping(value = "/get", method = RequestMethod.GET)
  public User get(@PathVariable("username") String username, @PathVariable("school") String school, @PathVariable("birthDayDay") String birthDay);
}

POST 请求

Feign 默认的传参方式就是 JSON 传参(@RequestBody),因此定义接口的时候可以不用@RequestBody注解标注,但为了开发规范,建议加上

  1. @RequestBody 注解
@FeignClient("user")
public interface UserFeignClient {
  @RequestMapping(value = "/post", method = RequestMethod.POST)
  public User post(@RequestBody User user);
}

4、超时设置

我们在通过 Feign 去调用接口,难免会遇到超时的问题,我们可以在 yml 文件设置超时属性,防止系统抛出超时异常

feign:
    client:
        config:
       # 全局配置(default 默认就是适用于全部微服务)
            default:
                connectTimeout: 100000
                readTimeout: 100000
            # 单独配置
            user:
                connectTimeout: 300000
                readTimeout: 300000

5、Feign 性能优化

默认情况下,Feign 使用的是 UrlConnetcion 去请求,这种原生的请求方式一旦遇到高并发的情况下,响应会变得很慢,所以我们可以考虑加入连接池技术来优化性能,下面介绍下如何集成 Apache 下的 HttpClient 的连接池


加入 httpclient 依赖

<dependency>
    <groupId>io.github.openfeign</groupId>
    <artifactId>feign-httpclient</artifactId>
</dependency>

设置 yml 文件属性

feign:
  # 这样就设置好了 feign 请求方式是 httpclient,而不是 UrlConnetcion 
    httpclient:
        enable: true
      # feign的最大连接数
        max-connection: 200
      # feign 单个路径的最大连接数
        max-connections-per-route: 50
相关实践学习
日志服务之使用Nginx模式采集日志
本文介绍如何通过日志服务控制台创建Nginx模式的Logtail配置快速采集Nginx日志并进行多维度分析。
相关文章
|
7月前
|
Java 机器人 Maven
【Java用法】微服务之间的相互调用方式之一,通过FeignClient客户端调用其他微服务的方法包含熔断器(Hystrix)
【Java用法】微服务之间的相互调用方式之一,通过FeignClient客户端调用其他微服务的方法包含熔断器(Hystrix)
87 0
|
6月前
|
负载均衡 Java Maven
微服务技术系列教程(23) - SpringCloud- 声明式服务调用Feign
微服务技术系列教程(23) - SpringCloud- 声明式服务调用Feign
75 0
|
9月前
SpringCloud-Feign-文件服务调用
SpringCloud-Feign-文件服务调用
38 0
|
9月前
|
Java 微服务 Spring
微服务之间的调用之openFeign。
在spring cloud项目中,微服务之间的调用使用openfegin注解的方式,可以简洁快速的实现微服务之间的调用。下面直接通过实战的方式让读者清晰明了,全是干货,没有一点废话。
143 0
|
10月前
|
负载均衡 算法 Java
springcloud中的RestTemplate实现微服务之间的调用
springcloud中的RestTemplate实现微服务之间的调用
Springcloud使用feign客户端调用服务接口
Springcloud使用feign客户端调用服务接口
|
存储 JavaScript 小程序
SpringCloud 三种服务调用方式,你学会了吗?
SpringCloud 三种服务调用方式,你学会了吗?
SpringCloud——Feign远程调用(一)
SpringCloud——Feign远程调用(一)
69 0
SpringCloud——Feign远程调用(一)
|
负载均衡 Java Nacos
基于 Fegin 实现服务调用|学习笔记
快速学习基于 Fegin 实现服务调用
137 0
|
Java Nacos 开发者
使用Openfeign客户端调用微服务接口|学习笔记
快速学习使用 Openfeign 客户端调用微服务接口
159 0