优雅的实现服务调用 -- OpenFeign

文章目录

  • 1. RestTemplate存在问题
  • 2. OpenFeign介绍
  • 3. 快速上手
    • 引入依赖
    • 添加注解
    • 编写OpenFeign的客户端
    • 远程调用
  • 4. OpenFeign参数传递
    • 从URL中获取参数
    • 传递单个参数
    • 传递多个参数
    • 传递对象
    • 传递JSON
  • 5. 最佳实践
    • Feign继承方式
      • 创建一个新的模块
      • 引入依赖
      • 编写接口
      • 打jar包
      • 服务实现方实现ProductApi接口
      • 服务消费方继承接口
    • Feign抽取方式
      • 创建一个module
      • 引入依赖
      • 编写API
      • 打jar包
      • 服务消费方使用接口
      • 测试
  • 6. 服务部署到Linux注意事项
    • 修改pow.xml文件

1. RestTemplate存在问题

之前我们写过的远程调用的代码:

@Autowired
private RestTemplate restTemplate;
public OrderInfo getOrderById(int id) {OrderInfo orderInfo = orderMapper.getOrderById(id);String url = "http://product-service/product/getProductById?id=" + orderInfo.getProductId();ProductInfo productInfo = restTemplate.getForObject(url, ProductInfo.class);orderInfo.setProductInfo(productInfo);return orderInfo;
}
  • URL需要拼接,灵活性高,但是封装臃肿,容易出错
  • 代码可读性差,风格不统一

微服务之间的通信,通常有两种:RCP和HTTP

在Spring Cloud中,默认是使用HTTP来进行微服务的通信,最常用的实现形式有两种:

  • RestTemplate
  • OpenFeign

2. OpenFeign介绍

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

Feign是Netflix公司的一个组件,16年Netflix将Feign捐献给社区,2016年7月OpenFeign的首个版本9.0.0发布

可以理解为 Netflix Feign是Open Feign的祖先,或者说OpenFeign是NetFlix Feign的升级版

Spring Cloud Feign是Spring 对 Feign的封装,将Feign项目集成到Spring Cloud生态系统中

3. 快速上手

引入依赖

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

添加注解

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

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

编写OpenFeign的客户端

基于SpringMVC的注解来声明远程调用的信息

@FeignClient(value = "product-service",path = "/product/getProductBuId")
public interface ProductApi {@RequestMapping("/{id}")ProductInfo getProductBuId(@PathVariable("id") Integer id);
}

参数说明:

  • name/value:指定FeignClient的名称,也就是微服务的名称,用于服务发现.Feign底层会使用Spring Cloud LoadBalance进行负载均衡,也可以使用url属性指定一个具体的url
  • path:定义当前FeignClient的统一前缀

远程调用

@Service
public class OrderService {@Autowiredprivate OrderMapper orderMapper;@Autowiredprivate ProductApi productApi;@Autowiredprivate RestTemplate restTemplate;public OrderInfo getOrderById(int id) {OrderInfo orderInfo = orderMapper.getOrderById(id);
//        String url = "http://product-service/product/getProductById?id=" + orderInfo.getProductId();ProductInfo productInfo = productApi.getProductById(orderInfo.getProductId());orderInfo.setProductInfo(productInfo);return orderInfo;}
}

Feign 简化了与HTTP服务交互的过程, 把REST客户端的定义转换为Java接⼝, 并通过注解的⽅式来声

明请求参数,请求⽅式等信息, 使远程调⽤更加方便和间接.

4. OpenFeign参数传递

从URL中获取参数

服务提供方product-service

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

OpenFeign客户端

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

服务消费方order-service

@RestController
@RequestMapping("testOpenFeign")
public class TestFeignController {@Autowiredprivate ProductApi productApi;@RequestMapping("/o1")public String o1(Integer id) {return productApi.p1(id);}
}

测试:

传递单个参数

服务提供方product-service

@RequestMapping("/p2")
public String p2(@RequestParam("id") int id) {return "p2接受到参数" + id;
}

OpenFeign客户端

@RequestMapping("/p2")
String p2 (@RequestParam("id") Integer id);// 这里的@RequestParam做参数绑定,不能省略

服务消费方order-service

@RequestMapping("/o2")public String o2(Integer id) {return productApi.p2(id);
}

测试:

传递多个参数

需要使用多个@RequestParam进行参数绑定

服务提供方product-service

    @RequestMapping("/p3")public String p3(Integer id,String name) {return "p3接受到参数" + id + ": " + name;}

OpenFeign客户端

    @RequestMapping("/p3")String o3 (@RequestParam("id")Integer id, @RequestParam("name")String name);

服务消费方order-service

@RequestMapping("/o3")public String o3(Integer id,String name) {return productApi.o3(id,name);}

测试:

传递对象

服务提供方product-service

    @RequestMapping("/p4")public String p4(ProductInfo productInfo) {return "接收到参数" + productInfo;}

OpenFeign客户端

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

服务消费方order-service

    @RequestMapping("/o4")public String o4(ProductInfo productInfo) {return productApi.p4(productInfo);}

测试:

传递JSON

服务提供方product-service

     @RequestMapping("/p5")public String p5(@RequestBody ProductInfo productInfo) {return "接收到参数" + productInfo;}

OpenFeign客户端

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

服务消费方order-service

@RequestMapping("/o5")public String o5(@RequestBody ProductInfo productInfo) {return productApi.p5(productInfo);}

测试:

在这里插入图片描述

5. 最佳实践

不难发现,Feign的客户端代码和服务提供者的代码有很大的相似性

提出两种解决方法

Feign继承方式

我们可以将一些常见的操作封装到接口里,服务提供方实现这个接口,服务消费方编写Feign接口的时候,直接继承这个接口

创建一个新的模块

将接口放在一个公共的jar包里面,供服务提供方和服务消费方使用

引入依赖

<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>

编写接口

public interface ProductInterface {@RequestMapping("/getProductById")ProductInfo getProductById(@RequestParam("id") Integer id);@RequestMapping("/p1/{id}")String p1 (@PathVariable("id") Integer id);@RequestMapping("/p2")String p2 (@RequestParam("id") Integer id);@RequestMapping("/p3")String p3 (@RequestParam("id")Integer id, @RequestParam("name")String name);@RequestMapping("/p4")String p4 (@SpringQueryMap ProductInfo productInfo);@RequestMapping("/p5")String p5 (@RequestBody ProductInfo productInfo);
}

注意:这里的ProductInfo需要在product-api抽取出来,因此可以将order-service以及product-service里面的ProductInfo删除

打jar包

此时就会将product-api的jar包放到本地的maven仓库,供product-service以及order-service使用

服务实现方实现ProductApi接口

package org.JWCB.controller;import org.JWCB.api.ProductInterface;
import org.JWCB.model.ProductInfo;
import org.JWCB.service.ProductService;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.*;@RequestMapping("product")
@RestController
public class ProductController implements ProductInterface {private static final Logger log = LoggerFactory.getLogger(ProductController.class);@Autowiredprivate ProductService productService;@RequestMapping("getProductById")public ProductInfo getProductById(@RequestParam Integer id) {log.info("getProductById");return productService.getProductById(id);}@RequestMapping("/p1/{id}")public String p1(@PathVariable("id") Integer id) {return "p1接收到参数" + id;}@RequestMapping("/p2")public String p2(@RequestParam("id") Integer id) {return "p2接受到参数" + id;}@RequestMapping("/p3")public String p3(Integer id,String name) {return "p3接受到参数" + id + ": " + name;}@RequestMapping("/p4")public String p4(ProductInfo productInfo) {return "接收到参数" + productInfo;}@RequestMapping("/p5")public String p5(@RequestBody ProductInfo productInfo) {return "接收到参数" + productInfo;}
}

此时需要将本地Maven仓库的ProductApi导入,可以先将接口名完整打出来,由idea自己导入

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

注意:这里的ProductInfo是来自于product-api这个包

服务消费方继承接口

package org.JWCB.api;
import org.JWCB.model.ProductInfo;
import org.springframework.cloud.openfeign.FeignClient;
import org.springframework.cloud.openfeign.SpringQueryMap;
import org.springframework.web.bind.annotation.*;@FeignClient(value = "product-service",path = "/product")
public interface ProductApi extends ProductInterface{@RequestMapping("/getProductById")ProductInfo getProductById(@RequestParam("id") Integer id);@RequestMapping("/p1/{id}")String p1 (@PathVariable("id") Integer id);@RequestMapping("/p2")String p2 (@RequestParam("id") Integer id);@RequestMapping("/p3")String o3 (@RequestParam("id")Integer id, @RequestParam("name")String name);@RequestMapping("/p4")String p4 (@SpringQueryMap ProductInfo productInfo);@RequestMapping("/p5")String p5 (@RequestBody ProductInfo productInfo);
}

测试:

Feign抽取方式

做法实际上与继承的方式相似,但是理念不同,这种方式是将Feign抽取成一个独立的模块

就是将Feign的Client抽取为一个独立的模块,并把涉及的实体类都放入这个模块里面,打成一个jar包. 服务消费方只需要依赖该jar包即可

创建一个module

引入依赖

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

编写API

@FeignClient(value = "product-service",path = "/product")
public interface ProductInterface {@RequestMapping("/getProductById")ProductInfo getProductById(@RequestParam("id") Integer id);@RequestMapping("/p1/{id}")String p1 (@PathVariable("id") Integer id);@RequestMapping("/p2")String p2 (@RequestParam("id") Integer id);@RequestMapping("/p3")String o3 (@RequestParam("id")Integer id, @RequestParam("name")String name);@RequestMapping("/p4")String p4 (@SpringQueryMap ProductInfo productInfo);@RequestMapping("/p5")String p5 (@RequestBody ProductInfo productInfo);
}

打jar包

服务消费方使用接口

删除ProductApi以及ProductInfo

引入依赖:

<dependency><groupId>org.JWCB</groupId><artifactId>product-api</artifactId><version>1.0-SNAPSHOT</version>
</dependency>

修改order-service代码

指定扫描类

测试

在这里插入图片描述

6. 服务部署到Linux注意事项

使用Maven进行打包的时候.默认是从远程中央仓库进行下载的,但是product-api这个包在本地,我们可以制定从本地读取jar包

修改pow.xml文件

<dependency><groupId>org.JWCB</groupId><artifactId>product-api</artifactId><version>1.0-SNAPSHOT</version><scope>system</scope><systemPath>C:/Users/31127/.m2/repository/org/JWCB/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>

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

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

相关文章

javacpp调用pdfium的c++动态库

1、.h头文件 2、生成java代码的conf PdfiumDocumentConfigure.java package org.swdc.pdfium.conf;import org.bytedeco.javacpp.annotation.Platform; import org.bytedeco.javacpp.annotation.Properties; import org.bytedeco.javacpp.tools.InfoMap; import org.byte…

物联网:一种有能力重塑世界的技术

物联网&#xff08;IoT&#xff09;近年来对我们的日常生活产生了如此积极的影响&#xff0c;以至于即使是不懂技术的人也开始相信它所带来的便利以及敏锐的洞察力。 物联网是一场数字技术革命&#xff0c;其意义甚至比工业革命更为重大。物联网是仍处于起步阶段的第四次工业革…

SldWorks问题 2. 矩阵相关接口使用上的失误

问题 在计算三维点在图纸&#xff08;DrawingDoc&#xff09;中的位置时&#xff0c;就是算不对&#xff0c;明明就4、5行代码&#xff0c;怎么看都是很“哇塞”的&#xff0c;毫无问题的。 但结果就是不对。 那就调试一下吧&#xff0c;调试后发现生成的矩阵很不对劲&#…

电力设备图像分割系统源码&数据集分享

电力设备图像分割系统系统源码&#xff06;数据集分享 [yolov8-seg-efficientViT&#xff06;yolov8-seg-C2f-DCNV2等50全套改进创新点发刊_一键训练教程_Web前端展示] 1.研究背景与意义 项目参考ILSVRC ImageNet Large Scale Visual Recognition Challenge 项目来源AAAI G…

分治算法(7)_归并排序_计算右侧小于当前元素的个数

个人主页&#xff1a;C忠实粉丝 欢迎 点赞&#x1f44d; 收藏✨ 留言✉ 加关注&#x1f493;本文由 C忠实粉丝 原创 分治算法(7)_归并排序_计算右侧小于当前元素的个数 收录于专栏【经典算法练习】 本专栏旨在分享学习算法的一点学习笔记&#xff0c;欢迎大家在评论区交流讨论&…

鸿蒙微内核IPC数据结构

鸿蒙内核IPC数据结构 内核为任务之间的通信提供了多种机制&#xff0c;包含队列、事件、互斥锁、信号量等&#xff0c;其中还有Futex(用户态快速锁)&#xff0c;rwLock(读写锁)&#xff0c;signal(信号)。 队列 队列又称为消息队列&#xff0c;是一种常用于任务间通信的数据…

ASP.NET MVC-懒加载-逐步加载数据库信息

环境&#xff1a; win10, .NET 6.0 目录 问题描述解决方案基础版数据库查询部分&#xff08;Entity Framework&#xff09;控制器前端页面 加载到表格版 问题描述 假设我数据库中有N个表&#xff0c;当我打开某页面时&#xff0c;每个表都先加载一部分&#xff08;比如20条&am…

Chainlit集成Dashscope实现语音交互网页对话AI应用

前言 本篇文章讲解和实战&#xff0c;如何使用Chainlit集成Dashscope实现语音交互网页对话AI应用。实现方案是对接阿里云提供的语音识别SenseVoice大模型接口和语音合成CosyVoice大模型接口使用。针对SenseVoice大模型和CosyVoice大模型&#xff0c;阿里巴巴在github提供的有开…

有关vue路由的学习

导言 由于很久没碰前端了&#xff0c;碰到路由都不太会了。趁着后端对接来记录一下&#xff0c;就当复习。不过由于个人能力有限&#xff0c;这篇会偏向整个过程的实现逻辑&#xff0c;其中有很多具体的方法不会给来&#xff0c;有兴趣的可以去看一下源码~ 目的&#xff1a; …

基于springboot vue 校园失物招领平台的设计与实现

博主介绍&#xff1a;专注于Java&#xff08;springboot ssm springcloud等开发框架&#xff09; vue .net php phython node.js uniapp小程序 等诸多技术领域和毕业项目实战、企业信息化系统建设&#xff0c;从业十五余年开发设计教学工作☆☆☆ 精彩专栏推荐订阅☆☆☆☆…

SAP_SD模块-销售订单抬头折扣金额分摊到行项目的业务记录

前言&#xff1a; 本文主要是记录24年9月份支持财务月结过程中&#xff0c;用户提出的一个问题&#xff1a;“为什么KE30有部分物料9月份的销售数量少于FAGLL03H的销售数量&#xff1f;&#xff1f;”&#xff0c;主要包括以下两个内容&#xff1b; 1、问题发生的场景复现&am…

毕设分享 基于协同过滤的电影推荐系统

文章目录 0 简介1 设计概要2 课题背景和目的3 协同过滤算法原理3.1 基于用户的协同过滤推荐算法实现原理3.1.1 步骤13.1.2 步骤23.1.3 步骤33.1.4 步骤4 4 系统实现4.1 开发环境4.2 系统功能描述4.3 系统数据流程4.3.1 用户端数据流程4.3.2 管理员端数据流程 4.4 系统功能设计 …

【hot100-java】二叉树的最近公共祖先

二叉树篇 我觉得是比两个节点的深度&#xff0c;取min&#xff08;一种情况&#xff09; DFS解题。 /*** Definition for a binary tree node.* public class TreeNode {* int val;* TreeNode left;* TreeNode right;* TreeNode(int x) { val x; }* }*/ clas…

Apache Flink Dashboard

1、Overview Apache Flink Web Dashboardhttp://110.40.130.231:8081/#/overview 这张图片显示的是Apache Flink的Web UI界面&#xff0c;其中包含了以下几个部分&#xff1a; Available Task Slots: 显示当前可用的任务槽位数量。任务槽位是指Flink集群中可用于运行任务的资…

Django makemigrations时出现ModuleNotFoundError: No module named ‘MySQLdb‘

使用Python 3.11、Django 5.1.2 写完model进行makemigrations时出现报错 查找资料发现说是mysqldb适用于Python2&#xff0c;不支持Python3&#xff1b;python3可以使用pymysql 安装pymsql pip install pymysql 然后要在项目的__init__.py中加如下代码&#xff1a; import …

K8s(学习笔记)

swap分区是什么呀&#xff1f; 什么是ipvs呀&#xff1f; yaml是什么呀&#xff1f;&#xff1f;&#xff1f; p20看不下去了&#xff01;&#xff01;&#xff01;

【LeetCode】修炼之路-0004-Median of Two Sorted Arrays【python】

题目 Given two sorted arrays nums1 and nums2 of size m and n respectively, return the median of the two sorted arrays. The overall run time complexity should be O(log (mn)). Example 1: Input: nums1 [1,3], nums2 [2] Output: 2.00000 Explanation: merged…

SPIE出版-EI会议-人机交互 虚拟现实 <<< 11月杭州

EI、Scopus检索|人机交互与虚拟现实国际会议征稿进行中❗会议已通过SPIE出版❗ 2024人机交互与虚拟现实国际会议 ✅大会时间&#xff1a;2024年11月15-17日 ✅大会地点&#xff1a;中国-杭州 ✅报名/截稿&#xff1a;2024年10月15日&#xff08;团队投稿可享优惠&#xff…

实现std::sort,replace,fill,accumulate,equal等函数

std::sort /// <summary>/// std::sort 是从小到大排列的/// </summary>/// <typeparam name"IteratorClass"></typeparam>/// <typeparam name"ComparingFunctions"></typeparam>/// <param name"itBegin&qu…

基于IDEA+SpringBoot+Vue+Uniapp的投票评选小程序系统的详细设计和实现

2. 详细视频演示 文章底部名片&#xff0c;联系我获取更详细的演示视频 3. 论文参考 4. 项目运行截图 代码运行效果图 代码运行效果图 代码运行效果图 代码运行效果图 代码运行效果图 5. 技术框架 5.1 后端采用SpringBoot框架 Spring Boot 是一个用于快速开发基于 Spring 框…