SpringCLoud OpenFeign的使用介绍

news2024/12/24 21:06:25

Spring Cloud OpenFeign使用介绍

文章目录

  • Spring Cloud OpenFeign使用介绍
    • 导引
    • 1. 简单介绍
    • 2. 操作方式
    • 3. 参数传递
      • 3.1 传递单个参数
      • 3.2 传递多个参数
      • 3.3 传递对象
      • 3.4 传递JSON类型参数
    • 4. 最佳实践

导引

在之前的文章中,我们使用过RestTemplate来进行远程调用:

@Service
public class OrderServiceImpl implements OrderService {

    @Autowired
    private OrderMapper orderMapper;

    @Autowired
    private RestTemplate restTemplate;
    @Override
    public OrderInfo selectOrderById(Integer orderId) {
        OrderInfo orderInfo = orderMapper.selectOrderById(orderId);
        String url = "http://product-service/product/" + orderInfo.getProductId();
        ProductInfo productInfo = restTemplate.getForObject(url, ProductInfo.class);
        orderInfo.setProductInfo(productInfo);
        return orderInfo;
    }
}

虽说RestTemplate对HTTP封装后已经比直接使用HTTPClient简单方便很多,但还是存在这一些问题:

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

于是,我们可以使用OpenFeign来更”优雅“的实现远程通信!

1. 简单介绍

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

OpenFeign 官方文档:GitHub - OpenFeign/feign: Feign makes writing java http clients easier

2. 操作方式

当前代码基于Nacos配置完成的基础上进行编写【代码获取】:

  1. 先给order-service(哪个实例需要进行远程调用就给谁加)引入依赖

    <!--feign-->
    <dependency>
        <groupId>org.springframework.cloud</groupId>
        <artifactId>spring-cloud-starter-openfeign</artifactId>
    </dependency>
    
  2. order-service的启动类上添加注解@EnableFeignClients,开启OpenFeign功能

    package com.order;
    
    import org.springframework.boot.SpringApplication;
    import org.springframework.boot.autoconfigure.SpringBootApplication;
    import org.springframework.cloud.openfeign.EnableFeignClients;
    
    @EnableFeignClients
    @SpringBootApplication
    public class OrderServiceApplication {
        public static void main(String[] args) {
            SpringApplication.run(OrderServiceApplication.class, args);
        }
    }
    
  3. 编写OpenFeign的客户端(接口),且只需进行方法声明,基于SpringMVC的注解来声明远程调用的信息

    package com.order.api;
    
    import com.order.model.ProductInfo;
    import org.springframework.cloud.openfeign.FeignClient;
    import org.springframework.cloud.openfeign.SpringQueryMap;
    import org.springframework.web.bind.annotation.PathVariable;
    import org.springframework.web.bind.annotation.RequestBody;
    import org.springframework.web.bind.annotation.RequestMapping;
    import org.springframework.web.bind.annotation.RequestParam;
    
    import java.util.Date;
    
    @FeignClient(value = "product-service" , path = "/product")
    public interface ProductApi {
    
        @RequestMapping("/{productId}")
        ProductInfo getProductById(@PathVariable("productId") Integer productId);
    
    }
    

    • value:指定FeignClient的名称,也就是微服务的名称,用于服务发现
    • path:定义当前FeignClient的统一前缀
  4. 修改远程调用的方法

    package com.order.service.Impl;
    
    import com.order.api.ProductApi;
    import com.order.mapper.OrderMapper;
    import com.order.model.OrderInfo;
    import com.order.model.ProductInfo;
    import com.order.service.OrderService;
    import org.springframework.beans.factory.annotation.Autowired;
    import org.springframework.stereotype.Service;
    import org.springframework.web.client.RestTemplate;
    
    @Service
    public class OrderServiceImpl implements OrderService {
    
        @Autowired
        private OrderMapper orderMapper;
    
        @Autowired
        private RestTemplate restTemplate;
    
        @Autowired
        private ProductApi productApi;
        @Override
        public OrderInfo selectOrderById(Integer orderId) {
            OrderInfo orderInfo = orderMapper.selectOrderById(orderId);
    //        String url = "http://product-service/product/" + orderInfo.getProductId();
    //        ProductInfo productInfo = restTemplate.getForObject(url, ProductInfo.class);
            ProductInfo productInfo = productApi.getProductById(orderInfo.getProductId());
            orderInfo.setProductInfo(productInfo);
            return orderInfo;
        }
    }
    

完成上述配置后,启动服务,访问接口测试远程调用:

在这里插入图片描述

远程调用测试成功,同时远程调用的代码也变的更加简洁了!

3. 参数传递

在上述例子中,介绍了从Feign从URL中获取参数,接下来介绍Feign参数传递的其它方式.

3.1 传递单个参数

服务提供方 product-service (ProductController)

package com.product.controller;

import com.product.service.model.ProductInfo;
import com.product.service.ProductService;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

import java.util.Date;

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

    @RequestMapping("p1")
    public String p1(Integer id) {
        return "p1接受单个参数Id = " + id;
    }
}

Feign客户端

package com.order.api;

import com.order.model.ProductInfo;
import org.springframework.cloud.openfeign.FeignClient;
import org.springframework.cloud.openfeign.SpringQueryMap;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;

import java.util.Date;

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

@RequestParam作参数绑定,不能省略

服务消费方 order-service (FeignController)

package com.order.controller;

import com.order.api.ProductApi;
import com.order.model.ProductInfo;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

@Slf4j
@RequestMapping("/feign")
@RestController
public class FeignController {

    @Autowired
    private ProductApi productApi;

    @RequestMapping("/o1")
    public String o1(Integer id) {
        log.info("调用o1");
        return productApi.p1(id);
    }
}

测试远程调用:http://127.0.0.1:8080/feign/o1?id=5

在这里插入图片描述

3.2 传递多个参数

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

服务提供方 product-service (ProductController)

@RequestMapping("p2")
public String p2(Integer id, String productName) {
    return "p2接收多个参数:id = " + id + " productName = " + productName;
}

Feign客户端

@RequestMapping("p2")
String p2(@RequestParam("id") Integer id, @RequestParam("productName") String productName);

服务消费方 order-service (FeignController)

@RequestMapping("/o2")
public String o2(Integer id, String productName) {
    log.info("调用o2");
    return productApi.p2(id, productName);
}

这里我们使用Postman进行远程调用测试:

在这里插入图片描述

3.3 传递对象

服务提供方 product-service (ProductController)

@RequestMapping("/p3")
public String p3(ProductInfo productInfo) {
    // 这里我们只给对象传入 id 和 productName,剩下的由内部封装如下
    productInfo.setProductPrice(99);
    productInfo.setState(0);
    productInfo.setCreateTime(new Date(System.currentTimeMillis()));
    productInfo.setUpdateTime(new Date(System.currentTimeMillis()));
    return productInfo.toString();
}

Feign客户端

@RequestMapping("/p3")
String p3(@SpringQueryMap ProductInfo productInfo);

:传入对象参数的话需要加上注解 @SpringQueryMap

服务消费方 order-service (FeignController)

@RequestMapping("/o3")
public String o3(ProductInfo productInfo) {
    log.info("调用o3");
    return productApi.p3(productInfo);
}

进行远程调用测试:

在这里插入图片描述

3.4 传递JSON类型参数

服务提供方 product-service (ProductController)

@RequestMapping("/p4")
public String p4(@RequestBody ProductInfo productInfo) {
    productInfo.setProductPrice(99);
    productInfo.setState(0);
    productInfo.setCreateTime(new Date(System.currentTimeMillis()));
    productInfo.setUpdateTime(new Date(System.currentTimeMillis()));
    return productInfo.toString();
}

Feign客户端

@RequestMapping("/p4")
String p4(@RequestBody ProductInfo productInfo);

服务消费方 order-service (FeignController)

@RequestMapping("/o4")
    public String o4(@RequestBody ProductInfo productInfo) {
        log.info("调用o4");
        return productApi.p4(productInfo);
    }
}

进行远程调用测试:

在这里插入图片描述

4. 最佳实践

最佳实践,其实就是经过历史的迭代,在项目的实际过程中总结出来的最好的使用方式。

在上文配置Feign客户端时也能看出,它与服务提供方的代码非常相似:

在这里插入图片描述

如果需要在每个模块中都配置重复的代码,一旦数量上来则会造成一定的代码冗余!

对此我们可以对其做出简化,将Feign的客户端抽取为一个独立的模块,并把涉及到的实体类等都放在这个模块中,打成一个jar包,消费方只需要依赖该jar包即可(jar包通常由服务提供方来实现)

具体操作如下:

  1. 先创建一个模块 product-api

    在这里插入图片描述

  2. 给刚创建的模块product-api引入依赖

    <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>
    
  3. 复制ProductApiProductInfoproduct-api模块中

    在这里插入图片描述

  4. 通过Maven将该模块打包到本地Maven仓库

    在这里插入图片描述

    在这里插入图片描述

    在这里插入图片描述

  5. 删除 order-service 中的ProductApi与ProductInfo

  6. 为服务消费方 order-service引入依赖

    <dependency>
        <groupId>org.example</groupId>
        <artifactId>product-api</artifactId>
        <version>1.0-SNAPSHOT</version>
    	<scope>compile</scope>
    </dependency>
    

    会出现报错信息,此时需要修改项目中ProductApi与ProductInfod 路径product-api中的路径

  7. 给服务消费方 order-service启动类添加扫描路径

    @EnableFeignClients(basePackages = {“com.api”}, clients = {ProductApi.class})

    其中basePackages为扫描路径,clients为需要加载的Feign客户端

    package com.order;
    
    import com.api.ProductApi;
    import org.springframework.boot.SpringApplication;
    import org.springframework.boot.autoconfigure.SpringBootApplication;
    import org.springframework.cloud.openfeign.EnableFeignClients;
    
    @EnableFeignClients(basePackages = {"com.api"}, clients = {ProductApi.class})
    @SpringBootApplication
    public class OrderServiceApplication {
        public static void main(String[] args) {
            SpringApplication.run(OrderServiceApplication.class, args);
        }
    }
    

完成上述配置后即可进行远程测试调用:

在这里插入图片描述

:若需要将服务部署到服务器上,需要修改服务消费方的pom文件,因为其使用了部署在本地Maven仓库的jar包:

<dependency>
     <groupId>org.example</groupId>
     <artifactId>product-api</artifactId>
     <version>1.0-SNAPSHOT</version>
<!--  <scope>compile</scope>-->
     <scope>system</scope>
     <systemPath>D:/maven_test/.m2/repository/org/example/product-api/1.0-SNAPSHOT/product-api-1.0-SNAPSHOT.jar</systemPath>
</dependency>

<plugins>
    <plugin>
      <groupId>org.springframework.boot</groupId>
      <artifactId>spring-boot-maven-plugin</artifactId>
      <configuration>
          <includeSystemScope>true</includeSystemScope>
      </configuration>
    </plugin>
</plugins>

以上便是对OpenFeign的使用介绍了!!如果内容对大家有帮助的话请给这篇文章一个三连关注吧💕( •̀ ω •́ )✧( •̀ ω •́ )✧✨

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

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

相关文章

云动态摘要 2024-07-23

给您带来云厂商的最新动态,最新产品资讯和最新优惠更新。 最新优惠与活动 数据库上云优选 阿里云 2024-07-04 RDS、PolarDB、Redis、MongoDB 全系产品新用户低至首年6折起! [免费体验]智能助手ChatBI上线 腾讯云 2024-07-02 基于混元大模型打造,可通过对话方式生成可视化…

docker笔记4-部署

docker笔记4-部署 一、部署nginx二、部署Tomcat三、部署ESKibana3.1 部署ES3.2 部署kibana 一、部署nginx docker search nginx #搜索nginx的最新版本docker pull nginx #这里可以指定nginx版本&#xff0c;如果不指定&#xff0c;那么就拉取最新版本latestdocker run -d --na…

pikachu Fileinclusion(local)

随便选择一个都试试 发现url上数字会变 发现文件名确实是file1.php~file5.php 那么会不会还有别的burp抓包选中数字 设置6-100的爆破 strat attack 678异常还有个100也是 先改一下试试看 其他的会报错 但是通过这我们可以得到路径 先写一个 下一步 读取系统文件 windows系统肯定…

TCP客户端connect断线重连

文章目录 TCP客户端connect断线重连1、为什么要断线重连2、实现代码 TCP客户端connect断线重连 1、为什么要断线重连 客户端会面临服务器崩溃的情况&#xff0c;我们可以试着写一个客户端重连的代码&#xff0c;模拟并理解一些客户端行为&#xff0c;比如游戏客户端等. 考虑到…

并发编程面试题0

并发编程 1、并行和并发有什么区别&#xff1f; 并行和并发都是指多个任务同时执行的概念&#xff0c;但是它们之间有着明显的区别 并行&#xff1a;多个任务在同一时间同时执行&#xff0c;通常需要使用多个处理器或者多核处理器来实现。例如&#xff0c;一个多核CPU的计算机…

国内大陆地区huggingface连接不上的解决方案

简介 本文主要介绍国内大陆地区huggingface连接不上的解决方案,希望能对学习大模型的同学们有所帮助。 1. 背景 最近有不少同学反应无法正常下载huggingface的模型文件,亲自尝试使用git clone下载huggingface上的大模型文件时,也同样无法正常下载,以Meta-Llama-3-8B为例…

美食地图开发

调用地图接口展示数据库录入的不同类别地址信息&#xff0c;提供导航服务&#xff0c;手机端电脑端自适应。 语音介绍使用微软的tts接口可选不同语音性别生成

【数据结构】AVL树(图文解析 + 代码实现)

目录 1、AVL树的概念 2、AVL树结点的定义 3、AVL树的插入 4、AVL树的旋转 4.1 左单旋 4.2 右单旋 4.3 右左双旋 4.4 左右双旋 5、AVL树的验证 6、AVL树的性能 前面对map/multimap/set/multiset进行了简单的介绍&#xff0c;会大仙&#xff0c;这几个容器有个共同点是…

力扣 二分查找

二分查找基础篇。 题目 class Solution {public int searchInsert(int[] nums, int target) {int l 0, r nums.length - 1;while(l < r) {int mid l((r-l)>>1);//(lr)/2if(nums[mid]<target)lmid1;else rmid-1;}return l;//处理边界&#xff0c;设定数组的左半…

剪画小程序:相册里的视频变成微信动图表情包,很简单!

Hello&#xff0c;各位小伙伴们好啊&#xff01; 今天小画告诉大家怎么把微信里的视频变成微信专属表情包 让你的聊天变得更加有趣&#xff01; 一、首先&#xff0c;我们要将那些有趣的视频保存到手机相册里 在微信聊天时遇到眼前一亮的视频或在短视频平台上刷到的有趣的视…

linux虚拟机主机配置网卡

问题复现 我的虚拟主机了连不上远程工具windTerm ,但是我的另一台虚拟主机可以连上 我的解决思路 ping ip 地址 发现能够 ping 通 查看 ifconfig 配置信息 我对比另一个虚拟主机 发现了我的子网掩码netmask有问题 解决方式 第一种 连接配置 配置 ipv4.addresses 192.168.1…

JAVA毕业设计153—基于Java+Springboot+小程序的校园维修管理系统小程序(源代码+数据库)

毕设所有选题&#xff1a; https://blog.csdn.net/2303_76227485/article/details/131104075 基于JavaSpringboot小程序的校园维修管理系统小程序(源代码数据库)153 一、系统介绍 本项目分为用户、维修员、管理员三种角色 1、用户&#xff1a; 注册、登录、报修申报、报修…

顺序表和单链表的经典算法题

目录 前言 一、基础思想&#xff08;数组&#xff09; 1. 移除元素 2.删除有序元素的重复项 3.合并两个有序数组 二、单链表算法 1.移除链表元素 2.翻转链表 3.合并两个有序的链表 前言 Hello,小伙伴们&#xff0c;今天我们来做一个往期知识的回顾&#xff0c;今天我将…

Spring源码(六)--BeanFactory 实现与继承关系

BeanFactory 实现与继承关系 这些接口和类的源码&#xff0c; 每一个都可以看一下。 ListableBeanFactory 由bean工厂实现的BeanFactory接口的扩展&#xff0c;这些bean工厂可以枚举它们所有的bean实例&#xff0c;而不是按客户端请求逐个按名称进行bean查找。 Hierarchic…

C# yaml 配置文件的用法(一)

目录 一、简介 二、yaml 的符号 1.冒号 2.短横杆 3.文档分隔符 4.保留换行符 5.注释 6.锚点 7.NULL值 8.合并 一、简介 YAML&#xff08;YAML Aint Markup Language&#xff09;是一种数据序列化标准&#xff0c;广泛用于配置文件、数据交换和存储。YAML的设计目标是…

Kotlin 协程 — 基础

Kotlin 协程 — 基础 协程已经存在一段时间了&#xff0c;关于它的各种文章也很多。但我发现想要了解它还比较费时&#xff0c;所以我花了一段时间才真正理解了协程的基础知识以及它的工作原理。因此&#xff0c;我想分享一些我理解到的内容。 什么是协程&#xff1f; 协程代表…

【MySQL进阶之路 | 高级篇】事务的ACID特性

1. 数据库事务概述 事务是数据库区别于文件系统的重要特性之一&#xff0c;当我们有了事务就会让数据库始终保持一致性&#xff0c;同时我们还能通过事务的机制恢复到某个时间点&#xff0c;这样可以保证给已提交到数据库的修改不会因为系统崩溃而丢失。 1.1 基本概念 事务&…

企业微信获客助手广告平台深度回传/双回传设置教程参考

很多商家在使用【转化宝】进行推广时只采用了单回传&#xff0c;其实很多情况下单回传即可满足推广模型优化需求&#xff1b;但是最近很多专业化广告运营的代投或运营都开始采用双回传&#xff0c;【转化宝】支持抖音巨量引擎、百度营销广告、快手广告、腾讯广告等均支出深度优…

微信小程序开发:项目程序代码构成

✨✨ 欢迎大家来访Srlua的博文&#xff08;づ&#xffe3;3&#xffe3;&#xff09;づ╭❤&#xff5e;✨✨ &#x1f31f;&#x1f31f; 欢迎各位亲爱的读者&#xff0c;感谢你们抽出宝贵的时间来阅读我的文章。 我是Srlua小谢&#xff0c;在这里我会分享我的知识和经验。&am…

开源模型应用落地-LangChain高阶-记忆组件-ConversationBufferMemory正确使用(一)

一、前言 LangChain 的记忆组件发挥着至关重要的作用&#xff0c;其旨在协助大语言模型&#xff08;LLM&#xff09;有效地留存历史对话信息。通过这一功能&#xff0c;使得大语言模型在对话过程中能够更出色地维持上下文的连贯性和一致性&#xff0c;进而能够像人类的记忆运作…