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

本文涉及的产品
日志服务 SLS,月写入数据量 50GB 1个月
简介: 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日志并进行多维度分析。
相关文章
|
5月前
|
SpringCloudAlibaba Dubbo Java
【五】SpringCloud Alibaba之整合Dubbo(实现远程调用)
【五】SpringCloud Alibaba之整合Dubbo(实现远程调用)
126 0
|
Java Spring
Spring Cloud OpenFeign 远程调用传递请求头信息
import feign.RequestInterceptor; import feign.RequestTemplate; import lombok.extern.slf4j.Slf4j; import org.springframework.util.Assert; import org.springframework.web.context.request.RequestContextHolder; import org.springframework.web.context.request.ServletRequestAttributes;
286 0
|
2月前
|
负载均衡 网络协议 小程序
SpringCloud远程调用为啥要采用HTTP,而不是RPC?
【8月更文挑战第28天】在微服务架构日益盛行的今天,SpringCloud凭借其强大的生态系统和灵活的集成能力,成为了众多企业构建微服务系统的首选框架。在微服务之间的远程调用中,一个常见的问题是选择HTTP还是RPC(远程过程调用)作为通信协议。本文将深入探讨SpringCloud为何更倾向于采用HTTP而非RPC进行远程调用。
209 5
|
2天前
|
负载均衡 Java 开发者
Spring Cloud 远程调用:为何选择 HTTP 而非 RPC?
【10月更文挑战第1天】在微服务架构中,远程服务调用是一个核心环节。面对HTTP和RPC(Remote Procedure Call,远程过程调用)这两种通信协议,Spring Cloud 选择了HTTP作为其主要通信手段。本文将深入探讨Spring Cloud选择HTTP而非RPC的原因,以及这一选择在实际工作中的优势。
18 0
|
1月前
|
负载均衡 Java Nacos
SpringCloud基础1——远程调用、Eureka,Nacos注册中心、Ribbon负载均衡
微服务介绍、SpringCloud、服务拆分和远程调用、Eureka注册中心、Ribbon负载均衡、Nacos注册中心
SpringCloud基础1——远程调用、Eureka,Nacos注册中心、Ribbon负载均衡
|
2月前
|
前端开发 Java API
SpringCloud跨微服务的远程调用,如何发起网络请求,RestTemplate
SpringCloud跨微服务的远程调用,如何发起网络请求,RestTemplate
73 2
|
3月前
|
JSON 前端开发 Java
SpringCloud怎么搭建GateWay网关&统一登录模块
本文来分享一下,最近我在自己的项目中实现的认证服务,目前比较简单,就是可以提供一个公共的服务,专门来处理登录请求,然后我还在API网关处实现了登录拦截的效果,因为在一个博客系统中,有一些地址是可以不登录的,比方说首页;也有一些是必须登录的,比如发布文章、评论等。所以,在网关处可以支持自定义一些不需要登录的地址,一些需要登录的地址,也可以在网关处进行校验,如果未登录,可以返回JSON格式的出参,前端可以进行相关处理,比如跳转到登录页面等。
|
3月前
|
消息中间件 负载均衡 Java
最容易学会的springboot gralde spring cloud 多模块微服务项目
最容易学会的springboot gralde spring cloud 多模块微服务项目
|
5月前
|
网络协议 Java 程序员
SpringCloud 远程调用为啥要采用HTTP,而不是RPC?
关于SpringCloud远程调用采用HTTP而非RPC。
112 0
|
5月前
|
JSON Java Apache
spring cloud 整合Feign经行远程调用
spring cloud 整合Feign经行远程调用
72 0

热门文章

最新文章