[Spring] OpenFeign的使用

news2025/1/23 17:46:06

🌸个人主页:https://blog.csdn.net/2301_80050796?spm=1000.2115.3001.5343
🏵️热门专栏:
🧊 Java基本语法(97平均质量分)https://blog.csdn.net/2301_80050796/category_12615970.html?spm=1001.2014.3001.5482
🍕 Collection与数据结构 (93平均质量分)https://blog.csdn.net/2301_80050796/category_12621348.html?spm=1001.2014.3001.5482
🧀线程与网络(96平均质量分) https://blog.csdn.net/2301_80050796/category_12643370.html?spm=1001.2014.3001.5482
🍭MySql数据库(93平均质量分)https://blog.csdn.net/2301_80050796/category_12629890.html?spm=1001.2014.3001.5482
🍬算法(97平均质量分)https://blog.csdn.net/2301_80050796/category_12676091.html?spm=1001.2014.3001.5482
🍃 Spring(97平均质量分)https://blog.csdn.net/2301_80050796/category_12724152.html?spm=1001.2014.3001.5482
🎃Redis(97平均质量分)https://blog.csdn.net/2301_80050796/category_12777129.html?spm=1001.2014.3001.5482
🐰RabbitMQ(97平均质量分) https://blog.csdn.net/2301_80050796/category_12792900.html?spm=1001.2014.3001.5482
感谢点赞与关注~~~
在这里插入图片描述

目录

  • 1. RestTemplate存在的问题
  • 2. OpenFeign介绍
    • 2.1 引入依赖
    • 2.2 添加注解
    • 2.3 编写OpenFeign客户端
    • 2.4 远程调用
    • 2.5 测试
  • 3. OpenFeign参数传递
    • 3.1 传递单个参数
    • 3.2 传递多个参数
    • 4.3 传递对象
    • 3.4 传递Json
  • 4. 最佳实践
    • 4.1 Feign继承方式
    • 4.2 Feign抽取方式

1. RestTemplate存在的问题

观察我们之前远程调用的代码

public OrderInfo selectOrder(Integer id){
    OrderInfo orderInfo = orderMapper.selectOrderById(id);
    //把获取到的服务URL拼接到远程调用的URL中
    String url = "http://product-service/product/select?id=" + orderInfo.getProductId();
    ProductInfo productInfo = restTemplate.getForObject(url, ProductInfo.class);
    orderInfo.setProductInfo(productInfo);
    return orderInfo;
}

虽然说RestTemplate对HTTP封装之后,已经比直接使用HTTP Client方便很多,但是还是存在一些问题的.

  1. 需要拼接URL,灵活性高,但是封装臃肿,URL复杂的时候,容易出错.
  2. 代码可读性差,风格不统一.

微服务之间的通行主要有两种方式,一种是RPC,一种是HTTP.在SpringCloud中,默认是使用HTTP进行通信的,最常用的实现形式有两种:

  • RestTemplate
  • OpenFeign

接下来我们就来详细介绍一下OpenFeign.

2. OpenFeign介绍

OpenFeign是一个声明式的Web Service客户端.它让微服务之间的调用变得更加简单,类似与Controller调用Service,只需要创建一个接口,然后再添加注解就可以使用OpenFeign.

2.1 引入依赖

首先我们需要在服务调用方(order-service)中引入依赖

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

2.2 添加注解

在order-service的启动类添加注解,@EnableFeignClients,开启OpenFeign的功能.

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

2.3 编写OpenFeign客户端

在调用其他服务的客户端之下,编写API调用接口,基于SpringMVC的注解来声明远程调用的信息.
在这里插入图片描述

@FeignClient(name = "product-service")
public interface ProductApi {
    @RequestMapping("/product/select")
    ProductInfo getProductInfo(@RequestParam("id")Integer id);
}

[注意]:在接口的参数前面必须使用@RequestParam加上所调用服务接口的对应参数,否则参数无法传入,就相当于在请求的后面加上了?参数=xxx.
在这里插入图片描述

也可以把该服务的接口的统一前缀(放在类上的@RequestMapping)统一放到FeignClient注解的Path参数中.

@FeignClient(name = "product-service",path = "/product")
public interface ProductApi {
    @RequestMapping("/select")
    ProductInfo getProductInfo(@RequestParam("id")Integer id);
}

@FeignClient注解作用在接口上,参数说明:

  • name/value: 指定OpenFeign的名称,也就是被调用的微服务的名称,用于服务发现,Feign底层会使用SpringLoadBalance进行负载均衡.
    当然也可以使用URL属性指定一个具体的URL.
  • Path: 定义当前FeignClient的统一前缀,一般是被调用方Controller层的类注解.

2.4 远程调用

修改远程调用方法

@Service
public class OrderService {
    @Autowired
    private OrderMapper orderMapper;
    @Autowired
    private ProductApi api;
    //设置原子类
    public OrderInfo selectOrder(Integer id){
        OrderInfo orderInfo = orderMapper.selectOrderById(id);
        //把获取到的服务URL拼接到远程调用的URL中
        Integer productId = orderInfo.getProductId();
        ProductInfo productInfo = api.getProductInfo(productId);
        orderInfo.setProductInfo(productInfo);
        return orderInfo;
    }
}

2.5 测试

启动服务.访问接口,测试远程调用.
在这里插入图片描述

3. OpenFeign参数传递

3.1 传递单个参数

我们上面2.4的例子就是单个参数的调用.下面我们再来举一个例子

  1. 服务提供方product-service
@RestController
@RequestMapping("/product")
public class ProductController {
    @RequestMapping("/p1")
    public String p1(Integer id){
        return "接收到参数"+id;
    }
}
  1. FeginClient
@FeignClient(value = "product-service")
public interface ProductApi {
    @RequestMapping("/product/p1")
    String p1(@RequestParam("id") Integer id);
}

和我们上面提到的一样,@RequestParam是用来做参数绑定的,不能省略.
3. order-service

@RequestMapping("/order")
@RestController
public class OrderController {
    @Autowired
    private ProductApi api;
    @RequestMapping("/p1")
    public String p1(Integer id){
        return api.p1(id);
    }
}

远程测试调用:GET http://127.0.0.1:8080/order/p1?id=1
在这里插入图片描述

3.2 传递多个参数

使用多个@RequestParam进行参数绑定即可

  1. 服务提供方product-service
@RestController
@RequestMapping("/product")
public class ProductController {
    @RequestMapping("/p2")
    public String p2(Integer id1,Integer id2){
        return "接收到参数1:" + id1 + ",接收到参数2:" + id2;
    }
}
  1. FeignClient
@FeignClient(value = "product-service")
public interface ProductApi {
    @RequestMapping("/product/p2")
    String p2(@RequestParam("id1") Integer p1,@RequestParam("id2") Integer p2);
}
  1. 服务消费方order-service
@RequestMapping("/order")
@RestController
public class OrderController {
    @Autowired
    private ProductApi api;
    @RequestMapping("/p2")
    public String p2(Integer p1,Integer p2){
        return api.p2(p1,p2);
    }
}

调用接口进行测试:GET http://127.0.0.1:8080/order/p2?p1=1&p2=2
在这里插入图片描述

4.3 传递对象

  1. 服务提供方product-service
@RequestMapping("/p3")
public String p3(ProductInfo productInfo){
    return "接收到对象:" + productInfo;
}
  1. Feign
@RequestMapping("/product/p3")
String p3(@SpringQueryMap ProductInfo productInfo);

其中@SpringQueryMap注解表示的是:可以方便地将一个对象的属性作为请求的查询参数添加到请求的 URL中,避免了手动构建查询参数字符串(如json)的繁琐过程.
3. order-service

@RequestMapping("/p3")
public String p3(ProductInfo productInfo){
    return api.p3(productInfo);
}

测试远程调用:GET http://127.0.0.1:8080/order/p3?id=5&productName=zhangsan
在这里插入图片描述

3.4 传递Json

和我们之前学习SpringBoot的时候一样,同样是使用@RequestBody注解进行绑定.
注意由于数据在服务之间一直是按照Json格式传递的,所以服务方,服务调用方,FeignClient的参数上都需要加上注解.

  1. 服务提供方product-service
@RequestMapping("/p4")
public String p4(@RequestBody ProductInfo productInfo){
    return "接收到对象:" + productInfo;
}
  1. FeignClient
@RequestMapping("/product/p4")
String p4(@RequestBody ProductInfo productInfo);
  1. 服务消费方order-service
@RequestMapping("/p4")
public String p4(@RequestBody ProductInfo productInfo){
    return api.p4(productInfo);
}

测试远程调用:http://127.0.0.1:8080/order/p4
在这里插入图片描述

4. 最佳实践

通过观察,我们也能看出来,Feign的客户端与服务提供者的controller代码非常相似.
Feign客户端:

@FeignClient(value = "product-service")
public interface ProductApi {
    @RequestMapping("/product/p1")
    String p1(@RequestParam("id") Integer id);
}

服务提供方Controller

@RestController
@RequestMapping("/product")
public class ProductController {
    @RequestMapping("/p1")
    public String p1(Integer id){
        return "接收到参数"+id;
    }
}

有没有一种方法可以简化这种写法呢?

4.1 Feign继承方式

Feign支持继承的方式,我们可以把一些常见的操作封装到接口里.
我可以定义好一个接口,服务提供方实现这个接口,服务消费方编写Feign接口的时候,直接继承这个接口.
接口可以放在一个公共的jar包中,供服务提供方和服务消费方使用.

  1. 新建一个模块
    在这里插入图片描述
  2. 引入依赖
<dependencies>
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-web</artifactId>
    </dependency>
    <dependency>
        <groupId>org.springframework.cloud</groupId>
        <artifactId>spring-cloud-starter-openfeign</artifactId>
    </dependency>
</dependencies>
  1. 编写接口
    复制ProductInfo类和ProductApi到product-api模块中.把ProductApi改名为ProductInterface
    在这里插入图片描述
  2. 打jar包,并安装到本地Maven仓库
    在这里插入图片描述
    点击install.该模块就会被安装到本地的Maven仓库.
    在这里插入图片描述
    由于jar包中已经有了ProductInfo类,所以我们就可以把product-service和order-service的ProductInfo类注掉了.
  3. 服务提供方
    需要先在服务方中引入对应模块的依赖.
<dependency>
    <groupId>org.example</groupId>
    <artifactId>product-api</artifactId>
    <version>1.0-SNAPSHOT</version>
    <scope>compile</scope>
</dependency>

服务方product-service直接实现接口ProductInterface.

@RestController
@RequestMapping("/product")
public class ProductController implements ProductInterface {
    @Autowired
    private ProductService productService;
    @RequestMapping("/select")
    public ProductInfo getProductInfo(Integer id){
        return productService.selectById(id);
    }
    @RequestMapping("/p1")
    public String p1(Integer id){
        return "接收到参数"+id;
    }
    @RequestMapping("/p2")
    public String p2(Integer id1,Integer id2){
        return "接收到参数1:" + id1 + ",接收到参数2:" + id2;
    }
    @RequestMapping("/p3")
    public String p3(ProductInfo productInfo){
        return "接收到对象:" + productInfo;
    }
    @RequestMapping("/p4")
    public String p4(@RequestBody ProductInfo productInfo){
        return "接收到对象:" + productInfo;
    }
}
  1. 服务消费方
    同样,首先先添加依赖.
    之后让FeignClient继承ProductInterface
@FeignClient(value = "product-service")
public interface ProductApi extends ProductInterface {

}

注意在上述步骤中,把ProductInfo类引入包的路径全部改为之前打包的product-api模块下ProductInfo类的路径.

  1. 测试接口
    http://127.0.0.1:8080/order/select?id=1
    在这里插入图片描述

4.2 Feign抽取方式

官方推荐Feign的使用方式为继承的方式,但是企业开发中,更多是把Feign接口抽取为⼀个独立的模块(做法和继承相似,但理念不同).
操作方法:
将Feign的Client抽取为⼀个独立的模块,并把涉及到的实体类等都放在这个模块中,打成⼀个Jar.服务消费方只需要依赖该Jar包即可.这种方式在企业中比较常见,Jar包通常由服务提供方来实现.
前4步和前面继承的方式一样.只不过接口ProductApi在复制到新模块的时候不用修改名字
在这里插入图片描述

  1. 服务消费方使用product-api
    首先引入依赖,之后把该模块中原有的ProductApi接口注掉.
<dependency>
	<groupId>org.example</groupId>
	<artifactId>product-api</artifactId>
	<version>1.0-SNAPSHOT</version>
</dependency>

之后指定扫描类
在启动类中添加需要加载的Feign客户端.

@SpringBootApplication
@EnableFeignClients(clients = ProductApi.class)
public class OrderServiceApplication {
    public static void main(String[] args) {
        SpringApplication.run(OrderServiceApplication.class,args);
    }
}
  1. 测试
    远程调用接口http://127.0.0.1:8080/order/select?id=1
    在这里插入图片描述

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

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

相关文章

LangChain + llamaFactory + Qwen2-7b-VL 构建本地RAG问答系统

单纯仅靠LLM会产生误导性的 “幻觉”&#xff0c;训练数据会过时&#xff0c;处理特定知识时效率不高&#xff0c;缺乏专业领域的深度洞察&#xff0c;同时在推理能力上也有所欠缺。 正是在这样的背景下&#xff0c;检索增强生成技术&#xff08;Retrieval-Augmented Generati…

SpringCloud Gateway 集成 Sentinel 详解 及实现动态监听Nacos规则配置实时更新流控规则

目录 一、前言二、版本选择和适配2.1、本文使用各组件版本2.2、官方推荐版本 三、部署sentinel-dashboard3.1、下载 sentinel-dashboard jar包3.2、启动 sentinel-dashboard 四、Gateway 集成 Sentinel实现控制台配置流控规则测试4.1、添加Gateway 集成 Sentinel 包4.2、添加 G…

三相电变为家庭220V,市电火线和零线关系,为什么用三相电输送

参考&#xff1a; https://www.zhihu.com/question/30555841/answer/85723024 上面是电力系统的主要组成&#xff0c;发电站发电后升压传输&#xff0c;然后到各大城市再降压使用。 我们看到电塔上都是三根线&#xff0c;那么因为整个过程都是三相电。 为什么用三相电&#xff…

YOLOv8改进,YOLOv8检测头融合DSConv(动态蛇形卷积),并添加小目标检测层(四头检测),适合目标检测、分割等

精确分割拓扑管状结构例如血管和道路,对各个领域至关重要,可确保下游任务的准确性和效率。然而,许多因素使任务变得复杂,包括细小脆弱的局部结构和复杂多变的全局形态。在这项工作中,注意到管状结构的特殊特征,并利用这一知识来引导 DSCNet 在三个阶段同时增强感知:特征…

DNS未响应服务问题的解决(电脑连着网但浏览器访问不了网页)

天行健&#xff0c;君子以自强不息&#xff1b;地势坤&#xff0c;君子以厚德载物。 每个人都有惰性&#xff0c;但不断学习是好好生活的根本&#xff0c;共勉&#xff01; 文章均为学习整理笔记&#xff0c;分享记录为主&#xff0c;如有错误请指正&#xff0c;共同学习进步。…

鸿蒙Harmony json转对象(1)

案例1 运行代码如下 上图的运行结果如下: 附加1 Json_msg interface 案例2 import {JSON } from kit.ArkTS; export interface commonRes {status: numberreturnJSON: ESObject;time: string } export interface returnRes {uid: stringuserType: number; }Entry Component …

Transformer详解:Attention机制原理

前言 Hello&#xff0c;大家好&#xff0c;我是GISer Liu&#x1f601;&#xff0c;一名热爱AI技术的GIS开发者&#xff0c;本系列文章是作者参加DataWhale2025年1月份学习赛&#xff0c;旨在讲解Transformer模型的理论和实践。&#x1f632; 本文将详细探讨Attention机制的原理…

SpringBoot为什么要禁止循环依赖?

大家好&#xff0c;我是锋哥。今天分享关于【SpringBoot为什么要禁止循环依赖?】面试题。希望对大家有帮助&#xff1b; SpringBoot为什么要禁止循环依赖? 1000道 互联网大厂Java工程师 精选面试题-Java资源分享网 Spring Boot 禁止循环依赖的原因与 Spring 框架本身的设计…

利用Qt5.15.2编写Android程序时遇到的问题及解决方法

文章目录 背景1.文件读写 背景 目前我用的是Qt5.15.2来编写Qt程序&#xff0c;环境的配置看我这篇文章【Qt5.15.2配置Android开发环境】 项目中的一些配置的截图&#xff1a; 1.文件读写 假如直接用 QFileDialog::getExistingDirectory来获取路径的话&#xff0c;会得到类…

RV1126+FFMPEG推流项目源码

源码在我的gitee上面&#xff0c;感兴趣的可以自行了解 nullhttps://gitee.com/x-lan/rv126-ffmpeg-streaming-projecthttps://gitee.com/x-lan/rv126-ffmpeg-streaming-project

三维扫描赋能文化:蔡司3D扫描仪让木质文化遗产焕发新生-沪敖3D

挪威文化历史博物馆在其修复工作中融入现代3D扫描技术&#xff0c;让数百年的历史焕发新生。 文化历史博物馆的工作 文化历史博物馆是奥斯陆大学的一个院系。凭借其在文化历史管理、研究和传播方面的丰富专业知识&#xff0c;该博物馆被誉为挪威博物馆研究领域的领先机构。馆…

2024年美赛C题评委文章及O奖论文解读 | AI工具如何影响数学建模?从评委和O奖论文出发-O奖论文做对了什么?

模型假设仅仅是简单陈述吗&#xff1f;允许AI的使用是否降低了比赛难度&#xff1f;还在依赖机器学习的模型吗&#xff1f;处理题目的方法有哪些&#xff1f;O奖论文的优点在哪里&#xff1f; 本文调研了当年赛题的评委文章和O奖论文&#xff0c;这些问题都会在文章中一一解答…

Text2Sql:开启自然语言与数据库交互新时代(30/30)

一、Text2Sql 简介 在当今数字化时代&#xff0c;数据处理和分析的需求日益增长。对于众多非技术专业人员而言&#xff0c;数据库操作的复杂性常常成为他们获取所需信息的障碍。而 Text2Sql 技术的出现&#xff0c;为这一问题提供了有效的解决方案。 Text2Sql&#xff0c;即文…

初阶5 排序

本章重点 排序的概念常见排序的算法思想和实现排序算法的复杂度以及稳定性分析 1.排序的概念 排序: 所谓排序&#xff0c;就是使一串记录&#xff0c;按照其中的某个或某些关键字的大小&#xff0c;递增或递减的排列起来的操作。稳定性: 假定在待排序的记录序列中&#xff0…

【优选算法】6----查找总价格为目标值的两个商品

这道题相对于前寄到算法题较为容易~ 同样也是使用了双指针的算法哦~ ----------------------------------------begin-------------------------------------- 题目解析&#xff1a; 题目也是很简单地一句话&#xff0c;但是意图还是很明确~ 讲解算法原理&#xff1a; 同样的&…

windows11关闭系统更新详细操作步骤

文章目录 1.打开注册表2.修改注册表内容2.1 新建文件2.2 修改值 3.修改设置 1.打开注册表 winR输入regedit(如下图所示) 2.修改注册表内容 进HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\WindowsUpdate\UX\Settings 2.1 新建文件 右侧界面右键即可 2.2 修改值 重命名为如下…

HTML5使用favicon.ico图标

目录 1. 使用favicon.ico图标 1. 使用favicon.ico图标 favicon.ico一般用于作为网站标志&#xff0c;它显示在浏览器的地址栏或者标签上 制作favicon图标 选择一个png转ico的在线网站&#xff0c;这里以https://www.bitbug.net/为例。上传图片&#xff0c;目标尺寸选择48x48&a…

C++打字模拟

改进于 文宇炽筱_潜水 c版的打字效果_c自动打字-CSDN博客https://blog.csdn.net/2401_84159494/article/details/141023898?ops_request_misc%257B%2522request%255Fid%2522%253A%25227f97863ddc9d1b2ae9526f45765b1744%2522%252C%2522scm%2522%253A%252220140713.1301023…

图像处理基础(3):均值滤波器及其变种

均值滤波器可以归为低通滤波器&#xff0c;是一种线性滤波器&#xff0c;其输出为邻域模板内的像素的简单平均值&#xff0c;主要用于图像的模糊和降噪。 均值滤波器的概念非常的直观&#xff0c;使用滤波器窗口内的像素的平均灰度值代替图像中的像素值&#xff0c;这样的结果就…

《2024年度网络安全漏洞威胁态势研究报告》

2024年&#xff0c;全球网络安全领域继续面对日益严峻的挑战。在数字化转型的大背景下&#xff0c;漏洞利用成为网络攻击的重中之重。根据统计&#xff0c;全球新增漏洞数量再创新高&#xff0c;漏洞的复杂性加剧&#xff0c;修复周期也在不断缩短。然而&#xff0c;攻击者的手…