03-基于Feign的远程调用,详解Feign的自定义配置和优化,创建Feign模块

news2024/11/15 13:34:49

Feign远程调用

Feign替代RestTemplate

利用RestTemplate发起远程调用的代码的缺点

  • 代码可读性差编程体验不统一 , 面对参数复杂的URL难以维护
String url = "http://user-service/user/" + order.getUserId();
User user = restTemplate.getForObject(url, User.class);

Feign是一个声明式的http客户端,我们只需要把发请求需要的信息声明出来如请求方式,请求路径,请求参数等信息,剩下的由Fegin帮我们完成http请求的发送

第一步引入依赖:在order-service模块的pom文件中引入Feign的依赖spring-cloud-starter-openfeign

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

第二步开启Feign的功能:在order-service模块的启动类上添加@EnableFeignClients注解

第三步编写Feign客户端代码:在order-service模块的com.itcast.order.client包下新建UserClient接口,基于SpringMVC的注解来声明远程调用的信息

请求信息举例
请求的服务名称user-service
请求的方式GET或POST
请求的路径/user/{id}
请求的参数如用户的d
请求响应的返回值类型如User对象
// 封装了对user-service服务的远程调用的信息
@FeignClient("user-service")
public interface UserClient {
    @GetMapping("/user/{id}")
    User findById(@PathVariable("id") Long id);
}

第四步编写业务逻辑代码: 在order-service模块的OrderService类中的queryOrderById方法使用Feign客户端代替RestTemplate

第五步: 使用浏览器发起请求http://localhost:8080/order/101实现Fegin的远程调用

  • 观察user-service服务对应的多个实例的控制台信息,可以发现Feign不仅实现了远程调用还实现了负载均衡功能(因为内部集成了Ribbo组件)
@Service
public class OrderService {
    @Autowired
    private OrderMapper orderMapper;
    // 注入Feign的客户端
    @Autowired
    private UserClient userClient;

    public Order queryOrderById(Long orderId) {
        // 1. 查询订单
        Order order = orderMapper.findById(orderId);
        // 2. 利用Feign的客户端发起http请求访问user-service查询用户信息
        User user = userClient.findById(order.getUserId());
        // 3. 封账user对象到order对象的user属性中
        order.setUser(user);
        // 4. 返回order对象
        return order;
    }
}

Feign的自定义配置

Feign可以支持很多的自定义配置但一般情况下默认值就能满足我们的使用,如果需要自定义配置只需要创建自定义的@Bean覆盖默认的Bean即可

类型作用说明
feign.Logger.Level修改日志级别,包含四种不同的级别NONE(默认值,不记录任何日志信息,提升性能)
BASIC(仅记录请求的方法,URL以及响应状态码和执行时间)
HEADERS(在BASIC的基础上额外记录了请求和响应头的信息)
FULL(记录所有请求和响应的明细包括头信息、请求体、元数据,调试时使用)
feign.codec.Decoder响应结果的解析器http远程调用的结果做解析,例如解析json字符串为java对象
feign.codec.Encoder请求参数编码将请求参数编码便于通过http请求发送
feign. Contract支持的注解格式默认是SpringMVC的注解
feign. Retryer失败重试机制(某个服务实例查询不到就换个服务实例)请求失败的重试机制(默认是没有),不过会使用Ribbon的重试

基于order-service模块的application,yml配置文件自定义日志配置

# 针对某个微服务的配置
feign:  
  client:
    config: 
      user-service: # 针对配置的服务名称
        loggerLevel: FULL #  日志级别
# 针对所有服务的配置        
feign:  
  client:
    config: 
      default: # default就是全局配置针对所有服务
        loggerLevel: FULL #  日志级别         

基于Java代码自定义日志配置: 先声明一个配置类(不用加注解), 然后声明一个Logger.Level的对象

  • 全局生效: 将配置类放到启动类的@EnableFeignClients注解中@EnableFeignClients(defaultConfiguration = DefaultFeignConfiguration.class)
  • 局部生效: 将配置类放到对应@FeignClient注解中@FeignClient(value = "user-service", configuration = DefaultFeignConfiguration.class)
public class DefaultFeignConfiguration {
    @Bean
    public Logger.Level feignLogLevel(){
        return Logger.Level.BASIC; //日志级别设置为 BASIC
    }
}

Feign的使用优化

Feign底层发起http请求需要依赖于其他框架, 其底层客户端实现包括三种,提高Frign的性能主要手段就是使用连接池代替默认的URLConnection

  • URLConnection: Feign底层默认会使用JDK自带的客户端但不支持连接池
  • Apache HttpClient: 支持连接池
  • OKHttp: 支持连接池

优化Feign性能的两种方式

  • 日志级别尽量使用BASIC或NONE
  • 使用支持连接池的HttpClient或OKHttp代替URLConnection

第一步引入依赖: 在order-service模块的pom文件中引入Apache的HttpClient依赖

<!--httpClient的依赖 -->
<dependency>
    <groupId>io.github.openfeign</groupId>
    <artifactId>feign-httpclient</artifactId>
</dependency>

第二步配置连接池: 在order-service模块的application.yml文件中添加配置,开启httpclient功能设置相关的连接池参数

feign:
  client:
    config:
      default: # default全局的配置
        logger-level: BASIC # 日志级别,BASIC就是基本的请求和响应信息
  httpclient:
    enabled: true # 开启feign对HttpClient的支持(默认是true,即如果引入了HttpClient依赖就可以使用)
    max-connections: 200 # 请求的最大的连接数
    max-connections-per-route: 50 # 分配给每个请求路径的最大连接数	

继承(面向契约思想)

由于Feign的客户端方法与服务提供者user-servie模块中UserController中对应的接口方法的代码除了方法名不同其余几乎一模一样

  • order-service模块基于Feign的客户端UserClient中定义的方法发起请求,user-servie模块接收并处理order-service模块发起的请求
@FeignClient(value = "user-service",configuration = DefaultFeignConfiguration.class)
public interface UserClient {
    @GetMapping("/user/{id}")
    User findById(@PathVariable("id") Long id);
}
@RestController
@RequestMapping("/user")
@RefreshScope
public class UserController {
    @Autowired
    private UserService userService;

    @GetMapping("/{id}")
    public User queryById(@PathVariable("id") Long id) {
        return userService.queryById(id);
    }
}

第一步: 通过继承来共享Feign客户端和Controller中相同的代码,先定义一个API接口, 通过定义接口方法并基于SpringMVC注解的方式声明发送Http请求的信息

public interface UserAPI{
    @GetMapping("/user/{id}")
    User findById(@PathVariable("id") Long id); 
}

第二步: Feign的客户端UserClient继承定义好的UserAPI接口,而UserController实现UserAPI接口

@FeignClient(value = "user-service")
public interface UserClient extends UserAPI{}
@RestController
public class UserController implents UserAPI{
    public User findById(@PathVariable("id") Long id){
        // ...实现业务逻辑
    }
}

基于继承方式的优缺点

  • 优点: 简单并且实现了代码共享

  • 缺点: 服务提供方和服务消费方紧耦合, 参数列表中的注解映射并不会继承,所以Controller中需要再次声明方法、参数列表、注解

基于抽取的最佳实践

Feign的客户端抽取为独立模块,并且把接口有关的POJO和默认的Feign配置都放到这个模块中,服务消费者引用该依赖包后即可使用

  • 缺点: 如果某个微服务只想要使用模块的部分功能也要把整个模块引入

在这里插入图片描述

第一步: 创建一个新的modulefeign-api模块并在pom.xml文件中引入feign的starter依赖spring-cloud-starter-openfeign

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

第二步: 将order-service模块中编写的UserClient、User、DefaultFeignConfiguration都转移到feign-api模块中
第三步: 在order-service模块中的pom.xml文件中引入我们自己编写的依赖feign-api

<dependency>
    <groupId>cn.itcast.demo</groupId>
    <artifactId>feign-api</artifactId>
    <version>1.0</version>
</dependency>

解决自动注入失败问题: order-service模块的@EnableFeignClients注解是在cn.itcast.order包下显然无法扫描到cn.itcast.feign.clients包下的UserClient

// 方式一:指定Feign应该扫描的包
@EnableFeignClients(basePackages = "cn.itcast.feign.clients")

// 方式二: 指定需要加载的XxxClient接口
@EnableFeignClients(clients = {UserClient.class})

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1236063.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

idea中的sout、psvm快捷键输入,不要太好用了

目录 一、操作环境 二、psvm、sout 操作介绍 2.1 psvm&#xff0c;快捷生成main方法 2.2 sout&#xff0c;快捷生成打印方法 三、探索 psvm、sout 底层逻辑 一、操作环境 语言&#xff1a;Java 工具&#xff1a; 二、psvm、sout 操作介绍 2.1 psvm&#xff0c;快捷生成m…

pytorch中gather函数的理解

pytorch函数gather理解 torch.gather(input, dim, index, outNone) → Tensor Parameters: input (Tensor) – 源张量dim (int) – 索引的轴index (LongTensor) – 聚合元素的下标(index需要是torch.longTensor类型)out (Tensor, optional) – 目标张量 公式含义 这个函数的…

STM32 寄存器配置笔记——系统时钟配置 HSE as PLL

一、概述 本文主要介绍使用HSE高速外部时钟通过PLL倍频输出72MHZ的时钟作为系统时钟。下图为时钟树。 使用正点原子的开发板调试OSC_IN、OSC_OUT接的是8MHZ的晶振即为HSE时钟。 二、配置流程 1&#xff09;复位RCC相关的所有寄存器 复位内容是参考正点原子例程&#xff0c;按照…

家政保洁预约小程序app开发特点有哪些?

家政预约服务小程序APP开发的特点介绍&#xff1b; 1. 低成本&#xff1a;用户通过手机APP下单&#xff0c;省去了中介费用&#xff0c;降低了雇主的雇佣成本。 2. 高收入&#xff1a;家政服务人员通过手机APP接单&#xff0c;省去了中介费用&#xff0c;从而提高了服务人员的…

2023.11.20使用flask做一个简单图片浏览器

2023.11.20使用flask做一个简单图片浏览器 功能&#xff1a; &#xff08;1&#xff09;输入指定路径&#xff0c;打开文件夹 &#xff08;2&#xff09;判断文件格式为图片 &#xff08;3&#xff09;在前端进行预览 &#xff08;4&#xff09;使用bootstrap进行简单美化 ma…

Android Studio 引入Xui框架-简单应用

Android Studio Flamingo | 2022.2.1 Patch 2 Android 11开发、Gradle Version 8.0、 jdk17 源代码&#xff1a;GitHub - xuexiangjys/XUI: &#x1f48d;A simple and elegant Android native UI framework, free your hands! (一个简洁而优雅的Android原生UI框架&#xff…

Centos8部署LNMP架构

LNMP架构 LNMP是指一组通常一起使用来运行动态网站或者服务器的自由软件名称首字母缩写。L指Linux&#xff0c;N指Nginx&#xff0c;M一般指MySQL&#xff0c;也可以指MariaDB&#xff0c;P一般指PHP&#xff0c;也可以指Perl或Python。 1.Linux是一类Unix计算机操作系统的统称…

13 redis中的复制的拓扑结构

1、一主一从 为了性能考虑&#xff0c;主节点可以不开启AOF&#xff0c;但是要避免重启。 2、一主多从 适用于读操作的场景。由于从节点多&#xff0c;所以主的复制压力大 3、树状主从 数据先同步到redisB,redisC从节点C,E来看&#xff0c;redisB相当于主机了&#xff0c;可以…

微服务 Spring Cloud 8,开源RPC框架如何选型?

目录 一、开源RPC框架有哪些&#xff1f;1、跟语言平台绑定的开源RPC框架2、跨语言平台的开源RPC框架 二、跟语言平台绑定的开源RPC框架 -- Dubbo1、Dubbo的架构主要包含四个角色2、Dubbo的调用框架是如何实现的&#xff1f; 三、如何选择&#xff1f;四、跨语言平台的开源RPC框…

Linux shell编程学习笔记27:tput

除了stty命令&#xff0c;我们还可以使用tput命令来更改终端的参数和功能。 1 tput 命令的功能 tput 命令的主要功能有&#xff1a;移动更改光标、更改文本显示属性&#xff08;如颜色、下划线、粗体&#xff09;&#xff0c;清除屏幕特定区域等。 2 tput 命令格式 tput [选…

基于SSM的校园活动资讯网设计与实现

末尾获取源码 开发语言&#xff1a;Java Java开发工具&#xff1a;JDK1.8 后端框架&#xff1a;SSM 前端&#xff1a;Vue 数据库&#xff1a;MySQL5.7和Navicat管理工具结合 服务器&#xff1a;Tomcat8.5 开发软件&#xff1a;IDEA / Eclipse 是否Maven项目&#xff1a;是 目录…

OceanBase:OBServer节点管理

目录 1.查看节点 2.添加节点 2.1 创建数据目录 2.2.OceanBase 运行时所依赖的部分三方动态库 2.3.安装 OceanBase 数据库的 RPM 包 2.4.启动节点 observer 进程 2.5.向集群中添加节点 3.隔离节点 4.重启节点 4.1 停止服务 4.2 转储 4.3 关闭进程 4.4 启动进程 4.…

单体进化微服务:拆分、注册、调用、网关、过滤、治理、分布式事务

这里写目录标题 基本介绍生产-消费-网关父依赖生产者服务消费者服务网关服务common服务 感想 基本介绍 Spring Cloud 是一个用于构建分布式系统和微服务架构的开发工具包。它提供了一系列的功能和组件&#xff0c;用于解决微服务架构中的常见问题&#xff0c;如服务注册与发现…

Python---函数的应用案例(多个)

案例&#xff1a;使用print方法打印一条横线 print(- * 40) 案例&#xff1a;对上个案例进行升级&#xff0c;可以根据输入的num数值&#xff0c;生成指定数量的横线 def print_lines(num, length):""" print_lines函数主要作用用于生成多条指定长度的横线&…

Windows安装MongoDB

1、下载MongoDB的zip&#xff0c;解压 2、创建目录 mkdir D:\JavaSoftware\Database\MongoDB\mongodb-win32-x86_64-windows-5.0.8\data\db mkdir D:\JavaSoftware\Database\MongoDB\mongodb-win32-x86_64-windows-5.0.8\data\log 3、创建一个配置文件mongod.cfg&#xff0c…

【JavaEE】Servlet实战案例:表白墙网页实现

一、功能展示 输入信息&#xff1a; 点击提交&#xff1a; 二、设计要点 2.1 明确前后端交互接口 &#x1f693;接口一&#xff1a;当用户打开页面的时候需要从服务器加载已经提交过的表白数据 &#x1f693;接口二&#xff1a;当用户新增一个表白的时候&#xff0c;…

Self-Supervised Exploration via Disagreement论文笔记

通过分歧进行自我监督探索 0、问题 使用可微的ri直接去更新动作策略的参数的&#xff0c;那是不是就不需要去计算价值函数或者critic网络了&#xff1f; 1、Motivation 高效的探索是RL中长期存在的问题。以前的大多数方式要么陷入具有随机动力学的环境&#xff0c;要么效率…

1.Qt5.15及其以上的下载

Qt5.15及其以上的下载 简介&#xff1a; ​ Qt是一个跨平台的C库&#xff0c;允许开发人员创建在不同操作系统&#xff08;如Windows、macOS、Linux/Unix&#xff09;和设备上具有本地外观和感觉的应用程序。Qt提供了一套工具和库&#xff0c;用于构建图形用户界面&#xff0…

C语言基础---函数、数组

目录 一、函数 二、数组​ 一、函数 交换两个数&#xff1a; 发现这样并没有交换a和b的值&#xff0c;只是交换了x和y的值&#xff0c;这是因为&#xff1a; //当实参传递给形参的时候&#xff0c;形参是实参的一份临时拷贝 //对形参的修改不能改变实参 实参与形参是…

linux高性能服务器

第一部分、TCP/IP协议详解 TCP协议为应用层提供可靠的、面向连接的和基于流的服务 可靠 使用超时重传(发送端在发送报文后启动一个定时器&#xff0c;若定时器在规定时间内没有收到应答就会重发该报文)&#xff0c;发送应答机制(发送端发送的每个TCP报文都必须得到接收方的应答…