详解SpringCloud微服务技术栈:Feign远程调用、最佳实践、错误排查

👨‍🎓作者简介:一位大四、研0学生,正在努力准备大四暑假的实习
🌌上期文章:详解SpringCloud微服务技术栈:Nacos配置管理
📚订阅专栏:微服务技术全家桶
希望文章对你们有所帮助

之前使用RestTemplate来实现远程调用,这种方式存在了一些问题,更优的解决方式是使用Feign来实现远程调用。
这里将会讲解如何用Feign实现远程调用,并进行最佳实践。

Feign的远程调用与最佳实践

  • 基于Feign实现远程调用
  • 自定义配置
  • 性能优化
  • Feign最佳实践
    • 分析
    • 实现

基于Feign实现远程调用

RestTemplate的问题:

1、代码可读性差,变成体验不统一
2、参数比较复杂的url,难以维护

Feign是一个声明式的http客户端,官方地址:Feign官网
声明式在Spring中开始提到,是利用配置文件来加事务。而声明式http客户端也是类似,我们只需要把发http请求所需要的信息声明出来即可,剩下的东西都交给Feign来实现。

使用Feign的步骤:
1、引入依赖:

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

2、在order-service的启动类添加开启Feign的功能:加注解@EnableFeignClients
3、做声明(编写Feign客户端):

@FeignClient("userservice") //声明出服务名称
public interface UserClient {@GetMapping("/user/{id}")User findById(@PathVariable("id") Long id);
}

主要是基于SpringMVC的注解来声明远程调用的信息,如服务名称、 请求方式、请求路径、请求参数、返回值类型等,直接声明这些信息就行。
这样的方式会简单很多,注解开发太方便了,节约了很多学习成本,即便url的参数很复杂,我们利用注解开发写参数列表也是很方便的。

现在我们可以直接使用这个客户端了,直接修改order查询的接口:

    @Resourceprivate OrderMapper orderMapper;@Resourceprivate UserClient userClient;public Order queryOrderById(Long orderId){//查询订单Order order = orderMapper.findById(orderId);//根据用户id来查询用户,用Feign实现远程调用User user = userClient.findById(order.getUserId());//将用户注入到order中order.setUser(user);// 4.返回return order;}

同时多次刷新网址,可以验证出Feign还集成了Ribbon负载均衡,是比较强大的。

总结Feign使用步骤:

引入依赖
添加@EnableFeignClients注解
编写FeignClient接口
使用FeignClient中定义的方法来代替RestTemplate

自定义配置

Feign可以让我们自定义配置来覆盖默认配置,一般需要配置的是日志级别的类型feign.Logger.Level。
配置Feign日志有2种方式。

方式一:配置文件
1、全局生效

feign:client:config:default:loggerLevel: FULL # 最高级别,日志中会包含发起的请求,以及远程调用等信息

在这里插入图片描述

2、局部生效

feign:client:config:userservice:loggerLevel: FULL

方式二:Java代码
先声明一个Bean:

public class DefaultFeignConfiguration {@Beanpublic Logger.Level LogLevel(){return Logger.Level.BASIC;}
}

想要这个类生效,需要配置。
1、全局配置:把它放到@EnableFeignClients这个注解中:

@EnableFeignClients(defaultConfiguration = DefaultFeignConfiguration.class)

2、局部配置:把它放到@FeignClient这个注解中:

@FeignClient(value = "userservice", configuration = DefaultFeignConfiguration.class)

重启order-service,访问网址后查看控制台的日志,除了SQL语句之外,还有关于Feign的日志信息(只有请求行和相应行)

性能优化

Feign其实性能一直很不错了,但是还是可以被优化,Feign底层的客户端实现:

URLConnection:默认实现,不支持连接池
Apache HttpClient:支持连接池
OKHttp:支持连接池

Feign底层还是会用到其他的客户端,默认使用URLConnection,但是它不支持连接池,这就会使得性能不是太好。因此更推荐使用其他两种。

Feign的性能优化主要包括:

使用连接池代替默认的URLConnection
日志级别,最好用BASIC或NONE,日志级别太高也会造成一些性能损耗

将URLConnection换成Apache HttpClient:
1、引入依赖:

	<!--引入HttpClient依赖--><dependency><groupId>io.github.openfeign</groupId><artifactId>feign-httpclient</artifactId></dependency>

2、配置连接池:

feign:httpclient:enabled: true # 支持HttpClient的开关max-connections: 200 # 最大连接数max-connections-per-route: 50 # 单个路径的最大连接数

其中,最大连接数和单个路径最大连接数并不能那么容易确定,具体的连接数需要根据业务的情况,对于不同的业务,可以用jmeter进行压力测试。

Feign最佳实践

分析

方式一:继承

给消费者的FeignClient和提供者的controller定义统一的父接口作为标准

乍一看还是有点抽象的,但是我们可以打开一下order-service的UserClient接口与user-service的UserController:
在这里插入图片描述
在这里插入图片描述
这两个的函数其实是差不多的,因为消费者要通过Feign解析网址请求,就需要带上相应的信息(请求方式、网址、参数等),而提供者则需要提供正确的方式给消费者,因此信息上两者基本上都是差不多的。
所以理论上可以定义一个统一的父接口来作为标准。

public interface UserAPI{@GetMappingUser findById(@PathVariable("id") Long id);
}

而消费者和提供者只需要分别继承和实现这个接口就可以了。
但是这种方式有一定的问题,Spring官方也不推荐让客户端和服务器端共用一个接口,因为这样的耦合度太高了。

方式二:抽取

将FeignClient抽取为独立模块,并且把接口有关的pojo、默认的Feign都放到这个模块中,提供给所有消费者使用。

解析一下,在之前的代码中,order-service的UserClient会去调用user-service中的UserController,但是如果还有很多模块的UserClient都要调用,可能就会有很多地方重复写了,因此可以专门定义一个feign-api,在里面声明UserClient,并且涉及到的实体类、默认配置都在feign-api中实现。而order-service要使用的时候,只需要引入feign-api的依赖就可以了。

实现

这里将会实现方式二,步骤如下:
1、新建module,命名为feign-api,然后引入feign的starter依赖

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

2、将order-service中编写的UserClient、User、DefaultFeignConfiguration都复制到feign-api项目中
在这里插入图片描述
上面拥有的部分,在order-service里面都可以直接删除了,以后需要直接去用feign-api里面的东西就可以了。

3、在order-service中引入feign-api的依赖

	<dependency><!--groupId是你创建api的这个module时候的相关包--><groupId>com.wang</groupId><artifactId>feign-api</artifactId><version>1.0</version></dependency>

4、修改order-service中的所有与上述组件有关的import部分,改成导入feign-api的包

5、重启测试

运行后发现会报错,查看报错信息:
在这里插入图片描述
没有找到UserClient的对象,但是编译没有报错,只是运行报错了,查看OrderService:
在这里插入图片描述
可以想到,Spring没有获得这个容器的对象,这种情况的发生是因为扫描包出现了问题,只是因为启动类指定的Mapper是在cn.itcast.order下面的,然而UserClient是在cn.itcast.feign下面的。
在这里插入图片描述
简单粗暴的解决方式是直接把MapperScan扫描范围扩大,但是这肯定是不合适的,启动类应该默认扫描的范围就是所在的包下面的,应该想想别的办法。

方式一:指定FeignClient所在包(全盘拿来)

@EnableFeignClients(basePackages = "cn.itcast.feign.clients", defaultConfiguration = DefaultFeignConfiguration.class)

方式二:指定FeignClient字节码(精准定位,推荐方案)

@EnableFeignClients(clients = {UserClient.class}, defaultConfiguration = DefaultFeignConfiguration.class)

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

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

相关文章

Python src/pyaudio/device_api.c:9:10: fatal error: portaudio.h: 没有那个文件或目录

在安装Pyaudio的时候报错&#xff0c;portaudio.h: 没有那个文件或目录&#xff0c;解决办法如下&#xff1a; sudo apt-get install libasound-dev portaudio19-dev libportaudio2 libportaudiocpp0 安装Pyaudio pip install PyAudio -i https://mirrors.bfsu.edu.cn/pypi/…

积木游戏

题目描述 小云和小吉在玩积木游戏&#xff0c;他们手上有很多积木&#xff0c;每个积木上面都有一个字母。 现在他们把所有的积木都排在一条队列上&#xff0c;队列有一个完美值&#xff0c;这个完美值就是积木队列上的字母组成的字符串的字典序&#xff0c;字典序越大完美值…

MyBatis - DAO 接口(Mapper.xml)支持方法重载吗?

方法重载&#xff08;Method Overloading&#xff09;是指在同一个类中定义多个方法&#xff0c;它们具有相同的方法名但参数列表不同。 Dao 在 MyBatis 的 DAO 层接口中&#xff0c;是允许方法重载的。 在 DAO 层接口中&#xff0c;可以根据不同的需求和条件定义多个方法&am…

蓝桥杯青少年创意编程大赛:激发少儿编程潜能,培养未来科技之星

随着科技的飞速发展&#xff0c;编程已经成为了当今世界的一项重要技能。为了培养更多的编程人才&#xff0c;蓝桥杯官网显示&#xff0c;蓝桥杯青少年创意编程大赛应运而生。作为国内有影响力的少儿编程赛事之一&#xff0c;蓝桥杯青少年创意编程大赛旨在激发青少年对编程的兴…

​Portkey AI网关:一个用来连接多种人工智能模型的开源工具

简介 它允许开发者通过一个简单的API接口来访问超过100种不同的大语言模型。包括OpenAI、Anthropic、Mistral、LLama2、Anyscale、Google Gemini等。安装体积只有45kb&#xff0c;处理速度提升了9.9倍&#xff0c;可以在多个不同的AI模型中来回切换。可以根据自己的需要进行灵…

找不到mfc100.dll的解决方法,怎么修复mfc100.dll文件

当我们在使用电脑时&#xff0c;时常可能会遇到各类系统提示的错误信息。"找不到mfc100.dll" 就是这些错误之一&#xff0c;该错误提示会妨碍我们执行一些应用程序或特定代码。为了帮助读者克服这个技术障碍&#xff0c;本篇文章将详尽阐明导致该问题的根本原因&…

【Flutter 问题系列第 80 篇】TextField 输入框组件限制可输入的最大长度后,输入的内容中包含表情符号时,获取输入的内容数还是会超出限制的问题

这是【Flutter 问题系列第 80 篇】&#xff0c;如果觉得有用的话&#xff0c;欢迎关注专栏。 博文当前所用 Flutter SDK&#xff1a;3.10.5、Dart SDK&#xff1a;3.0.5 一&#xff1a;问题描述 在输入用户名称、简介等内容时&#xff0c;一般我们都会限制输入框内最大可输入…

The Feast and the Bus

JebTrains的员工正在庆祝一年中的第256天&#xff01;JebTrains有 n 名员工和 k 个团队。每个员工都是某个&#xff08;恰好是一个&#xff09;团队的成员。所有队伍的编号从 1 到 k。您将得到一个数字数组 t1、t2、…、tn&#xff0c;其中ti是第i个员工的团队编号。 JebTrains…

FFMPEG解码实时流,支持cpu、gpu解码

官网下载的ffmpeg目前只能下载到X64版本的库&#xff0c;具体编译请参考windows编译ffmpeg源码&#xff08;32位库&#xff09;_windows 32位ffmpeg动态库-CSDN博客 直接上代码 int VideoDecodeModule::Open(std::string strUrl) {AVFormatContext *pFormatCtx nullptr;AVCo…

Python 学习笔记——一认识Python

Python 简介 Python 是一种解释型、面向对象、动态数据类型的高级程序设计语言。 Python 由 Guido van Rossum 于 1989 年底发明&#xff0c;第一个公开发行版发行于 1991 年。 像 Perl 语言一样, Python 源代码同样遵循 GPL(GNU General Public License) 协议。 Python 特点 1…

电脑本地连接不见了怎么恢复?5个方法轻松解决问题!

“我在使用电脑时&#xff0c;突然发现我的本地连接不见了&#xff0c;这是怎么回事呢&#xff1f;有什么方法可以解决这个问题吗&#xff1f;” 电脑的本地连接是一种将电脑与局域网连接的方式。局域网是一种小型的网络&#xff0c;通常在建筑物内或地理位置相近的少量计算机之…

Python数据分析案例33——新闻文本主题多分类(Transformer, 组合模型) 模型保存

案例背景 对于海量的新闻&#xff0c;我们可能需要进行文本的分类。模型构建很重要&#xff0c;现在对于自然语言处理基本都是神经网络的方法了。 本次这里正好有一组质量特别高的新闻数据&#xff0c;涉及 教育 科技 社会 时政 财经 房产 家居 七大主题&#xff0c;基本涵盖…

Grafana(三)Grafana 免密登录-隐藏导航栏-主题变换

一. 免密登录 Grafana 的常用方式&#xff1a; 将配置好的Grafana图嵌入到系统页面中 为了实现可免登录访问&#xff0c;可以通过如下方式进行设置&#xff1a; 1. 修改Grafana配置文件 在Grafana的配置文件 /etc/grafana/grafana.ini 中&#xff0c;找到 [auth.anonymous] 配…

深度剖析 ThreadLocal 内存泄露问题及解决方案

引言 在多线程编程中&#xff0c;ThreadLocal 是一个常用的工具&#xff0c;用于在每个线程中维护独立的变量&#xff0c;避免了线程间的数据共享问题。然而&#xff0c;使用不当时&#xff0c;ThreadLocal 可能引发内存泄露&#xff0c;这是一个开发者们常常需要面对的难题。…

SaaS 与 AWS 云:协同创新的崭新时代

在云计算的潮流下&#xff0c;SaaS&#xff08;Software as a Service&#xff09;模型和AWS&#xff08;Amazon Web Services&#xff09;云平台的结合为企业带来了前所未有的灵活性、可扩展性和效率。这两者的协同作用开启了一场数字化时代的创新浪潮&#xff0c;重新定义着企…

记一次Log记录大对象导致的CPU异常和磁盘打满

代码里有个大对象Map&#xff0c;缓存了100M数据&#xff0c;在多线程任务中记录异常的任务时错误地记录了这个Map&#xff0c;导致JSON序列化时疯狂刷磁盘写入数据&#xff0c;导致磁盘被打满&#xff0c;CPU100%&#xff0c;机器拒绝访问。

P9842 [ICPC2021 Nanjing R] Klee in Solitary Confinement 题解(SPJ!!!)

[ICPC2021 Nanjing R] Klee in Solitary Confinement 题面翻译 给定 n , k n,k n,k 和一个长为 n n n 的序列&#xff0c;你可以选择对区间 [ l , r ] [l, r] [l,r] 的数整体加上 k k k&#xff0c;也可以不加。最大化众数出现次数并输出。 题目描述 Since the travele…

MySQL命令大全和实例

文章目录 1. 数据库管理2. 表操作3. 数据操作&#xff08;CRUD&#xff09;4. 条件查询与排序5. 聚合函数和分组6. 用户权限管理7. 其他操作8. 视图操作9. 索引操作10. 子查询与连接查询11. 插入多行数据12. 删除满足特定条件的表中所有数据13. 清空表&#xff08;保留表结构&a…

rust跟我学五:是否安装双系统

图为RUST吉祥物 大家好,我是get_local_info作者带剑书生,这里用一篇文章讲解get_local_info是怎么得到检测双系统的。 首先,先要了解get_local_info是什么? get_local_info是一个获取linux系统信息的rust三方库,并提供一些常用功能,目前版本0.2.4。详细介绍地址:[我的Ru…