【SpringCloud组件——Feign(远程调用)】

news2025/1/12 16:00:19

前言:

我们在使用Nacos和Eureka的时候都需要使用远程调用开关RestTemplate发送http请求,但是这种方式在代码编写层面太不优雅了,因此我们可以采用Feign来代替RestTemplate发送http请求。

注:此小节同样使用订单系统和用户系统作为代码案例。 

一、RestTemlate和Feign的代码

1.1、RestTemplate

在订单系统调用用户系统的接口时我们之前编写的代码如下:

    public Order queryOrderById1(Long orderId) {
        // 1.查询订单
        Order order = orderMapper.findById(orderId);
        //2.利用RestTemplate发送http请求,查询用户
        //2.1、url路径
        String url = "http://userservice/user/" + order.getUserId();
        //2.2、发送http请求,实现远程调用
        User user = restTemplate.getForObject(url, User.class);
        //3.封装user到order
        order.setUser(user);
        // 4.返回
        return order;
    }

 以上代码存在的问题:

  • 代码可读性差,编程体验不统一
  • 参数复杂URL难以维护

总而言之:太不优雅了~

1.2、Feign 

1.2.1、导入Feign的依赖

        <!--feign客户端依赖-->
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-openfeign</artifactId>
        </dependency>

1.2.2、在启动类添加注解开启Feign的功能

@EnableFeignClients(basePackages = "cn.itcast.feign.clients")
public class OrderApplication {
        ......
}

 注解里面的参数我们先不讨论,后续会描述其功能。

1.2.3、编写Feign客户端

@FeignClient(value = "userservice",configuration = DefaultFeignConfiguration.class)//只针对userservice服务有效 全局有效在启动类的注解当中配置即可
public interface UserClient {

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

 这里主要是基于SpringMVC的注解来声明远程调用的信息,比如:

 对比我们之前使用的RestTemplate:

1.2.4、使用Feign客户端完成远程调用

    @Autowired
    private UserClient userClient;



    public Order queryOrderById(Long orderId) {
        // 1.查询订单
        Order order = orderMapper.findById(orderId);
        //基于Feign发送http请求(远程调用)
        User user = userClient.findById(order.getUserId());
        //3.封装user到order
        order.setUser(user);
        // 4.返回
        return order;
    }

二、Feign的自定义配置

我们配置Logger来看看:

方式1:基于配置文件的方式

①全局生效

 ②局部生效

 方式2:基于java代码的方式

先声明一个Bean

​public class DefaultFeignConfiguration {
    @Bean
    public Logger.Level logLevel(){
        return Logger.Level.FULL;
    }
}

声明完成后定义该Bean的作用域,即全局生效还是局部生效。

全局生效:在SpringBoot的启动类注解@EnableFeignClients添加如下参数,表明不论远程调用哪个微服务,都将采取配置类当中的配置。

@EnableFeignClients(defaultConfiguration = DefaultFeignConfiguration.class)

局部生效:在Feign客户端的类注解上添加如下参数,表明谁远程调用我这个微服务,将采用这个配置文件的信息。

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

 

 三、Feign的性能优化

优化点1:

由于Feign是一个声明式的http客户端,它能做的只是把我们的声明变成http请求,最终发http请求时还是会用到别的客户端,例如一下这几种:

 建立连接池的好处在于可以减少连接创建和销毁的性能损耗。(三次握手、四次挥手)

优化点2:

降低日志的级别,比如使用basic或none。

具体优化方式:

Feign添加httpClient的支持:

  • 引入依赖
        <!--引入httpClient依赖-->
        <dependency>
            <groupId>io.github.openfeign</groupId>
            <artifactId>feign-httpclient</artifactId>
        </dependency>
  • 配置连接池
feign:
  httpclient:
    enabled: true #支持httpClient的开关
    max-connections: 200 #最大连接数
    max-connections-per-route: 50 #单个请求路径的最大连接数

总结:

 四、Feign的最佳实践

方式一(继承):给消费者的FeignClient和提供者的controller定义统一的父接口作为标准。

我们先观察Feign客户端和服务提供者Controller的代码

    @GetMapping("/user/{id}")
    User findById(@PathVariable("id") Long id);
@Slf4j
@RestController
@RequestMapping("/user")
public class UserController {

    @Autowired
    private UserService userService;


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

}

可以观察到,两者的内容极其相似,因此我们可不可以让他们两都实现统一的接口?怎么做?

 那么问题又来了,这样又有一些弊端:

服务紧耦合

父接口参数列表中的映射不会被继承

方式二(抽取):将FeignClient抽取为独立模块,并且把接口有关的POJO、默认的Feign配置都放到这个模块中,提供给所有消费者使用。

先看图:

假设orderservice和payservice将来都调用userservice提供的服务,是不是需要在自己单独的模块当中写一遍userClient,这样一来,随着微服务的数量增加,userClient被写的次数也随之剧增。 解决方案:看图

 将userClient抽取出来组成一个单独的模块,以后不管哪个微服务远程调用时都从这来拿,我把实体类都给你定义了,你只管把我的依赖导入,别的你什么都不用操心,这样,不就皆大欢喜了嘛~

对比两种方式,方式一的弊端在于耦合度的问题,方式二的问题在于,假设我orderservice只需要userClient,但是我把你整个模块的依赖都到导进来了,未免有点小题大作了,我也用不了其他的哪些Client啊~因此,没有完美的解决方案,具体采用哪种还是需要结合实际选择。 

 

 

方式二具体操作:

  • 首先创建一个module,命名为feign-api,然后引入feign的starter依赖

 

  • 将order-service中编写的UserClient、User、DefaultFeignConfiguration都复制到feign-api项目中

 

  • 在order-service中引入feign-api的依赖
        <!--引入feign的统一api-->
        <dependency>
            <groupId>cn.itcast.demo</groupId>
            <artifactId>feign-api</artifactId>
            <version>1.0</version>
        </dependency>
  • 修改order-service中的所有与上述三个组件有关的import部分,改成导入feign-api中的包
    import cn.itcast.feign.clients.UserClient;
    import cn.itcast.feign.pojo.User;

    @Autowired
    private UserClient userClient;



    public Order queryOrderById(Long orderId) {
        // 1.查询订单
        Order order = orderMapper.findById(orderId);
        //基于Feign发送http请求(远程调用)
        User user = userClient.findById(order.getUserId());
        //3.封装user到order
        order.setUser(user);
        // 4.返回
        return order;
    }
  • 重启测试
  • 重启会失败,原因是Spring启动时并没有扫描到创建的这个模块的这些代码,因此也并不会创建他们的实例,怎么办?

 

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

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

相关文章

VXLAN技术了解

VXLAN是使用隧道技术的封装协议&#xff0c;常用于在物理层之上创建overlay网络&#xff0c;赋能虚拟网络。同时支持数据中心网络的虚拟化&#xff0c;并通过提供必要的分段满足多租户的需求。 优势在于 可伸缩性和灵活性&#xff1a;理论上可以使用1600万xlans&#xff0c;但…

读书笔记——《when breath becomes air》《超越自卑》

为啥要两本书一起写读后感&#xff1f; 读完这两本书本来应该分开来写点东西的&#xff0c;不过我认为这两本书应该写不了太多内容。虽然我也看了几本英文原著&#xff08;也写了点东西&#xff09;&#xff0c;但是我明显低估了《when breath becomes air》的难度&#xff0c…

SpringBoot学习之集成JWT(二十八)

一、什么是JWT WT (全称:Json Web Token)是一个开放标准(RFC 7519),它定义了一种紧凑的、自包含的方式,用于作为 JSON 对象在各方之间安全地传输信息。该信息可以被验证和信任,因为它是数字签名的。 比如我们常见的登录流程如下: 流程描述一下: 用户使用账号、密码登…

机器学习-3 K最近邻算法

K最近邻算法 算法概述分类什么是分类&#xff1f;分类需要什么&#xff1f; k近邻&#xff08;KNN&#xff09;分类 KNN算法关键问题k近邻模型的两个关键问题相似性度量——欧氏距离K值的选取 KNN算法流程算法原理算法步骤 数据标准化离差标准化数据标准差标准化数据小数定标标…

文献阅读-A Survey on Transfer Learning

期刊会议&#xff1a;IEEE TRANSACTIONS ON KNOWLEDGE AND DATA ENGINEERING 时间&#xff1a;2010 级别&#xff1a;CCF A 1、为什么需要迁移 许多机器学习和数据挖掘算法的一个主要假设是&#xff0c;训练数据和未来数据必须在相同的特征空间中&#xff0c;并且具有相同…

CSS的z-index属性

之前以为z-index越大&#xff0c;它的层级就越高&#xff0c;从我遇到的bug来看很显然不是这样。重新回顾一下z-index的知识&#xff1a; 1、z-index只对定义了position属性的&#xff0c;且属性值是非static元素有效。它的默认值是auto&#xff0c;auto的意思是游览器自动进行…

配置工具篇(tmux+ranger+lazygit)

Tmux 简介 官网解释&#xff1a;tmux是一个终端多路复用器&#xff1a;它允许在单个屏幕上创建、访问和控制多个终端。tmux可以从屏幕上分离出来&#xff0c;继续在后台运行&#xff0c;然后再重新连接。 此版本在Open BSD、Free BSD、Net BSD、Linux、mac OS和Solaris上运行…

数据结构 --- 堆

1、堆的基本概念 之前在学习优先级队列的时候&#xff0c; 学习到了堆的概念&#xff0c;现在重新回忆一下&#xff1a; 堆在逻辑上&#xff0c;是一颗完全二叉树堆在物理上&#xff0c;是存储在数组中的任意根节点值>子树节点值&#xff0c;叫做大顶堆。任意根节点值<…

学习RabbitMQ高级特性

目标&#xff1a; 了解熟悉RabbitMQ的高级特性 学习步骤&#xff1a; 高级特性主要分为以下几点, 官网介绍 1、消息可靠性投递 【confirm 确认模式、return 退回模式】 2、Consumer ACK 【acknowledge】 3、消费端限流 【prefetch】 4、TTL过期时间 【time to live】 5、死信队…

SQL注入 - Part 3(带外)

1、DNSLog注入 &#xff08;一种注入新思路&#xff09; 可以看到DNS的解析日志中包含了用户名。 基于此原理&#xff0c;可以手工构造注入点&#xff0c;让DNSlog显示库名、表名等&#xff0c;也可以使用自动化脚本Dnslogsqlinj进行获取。 2、SQL注入的防御 基于关键字&…

rollup打包react组件

这次主要简单实现用rollup打包react组件&#xff0c;组件的话简单写了一个弹窗组件&#xff0c;效果如下&#xff1a; 点击打开弹框&#xff0c;点击关闭按钮关闭弹框 首先创建react项目&#xff0c;这边还是用mfex-project脚手架创建 mfex-project create react-demo 然后编…

Linux·深入理解IO复用技术之epoll

目录 1.写在前面 2.初识复用技术和IO复用 3. Linux的IO复用工具概览 4. 初识epoll 5. epoll的底层细节 6.LT模式和ET模式 7.epoll的惊群问题 1.写在前面 今天一起来学习一下高并发实现的的重要基础&#xff1a;I/O复用技术 & epoll原理。 通过本文你将了解到以下内容…

【JavaScript】ES6,Proxy,Reflect,Promise,生成器,async/await

❤️ Author&#xff1a; 老九 ☕️ 个人博客&#xff1a;老九的CSDN博客 &#x1f64f; 个人名言&#xff1a;不可控之事 乐观面对 &#x1f60d; 系列专栏&#xff1a; 文章目录 ES6模板字符串&#xff0c;标签模板字符串函数的默认参数函数的剩余参数剩余参数和arguments有什…

为什么要学习C++软件调试技术?掌握调试技术都有哪些好处?

目录 1、为什么要学习C软件调试技术&#xff1f; 1.1、IDE调试手段虽必不可少&#xff0c;但还不够 1.2、通过查看日志和代码去排查异常崩溃问题&#xff0c;费时费力&#xff0c;很难定位问 1.3、有的问题很难复现&#xff0c;可能只在客户的环境才能复现 1.4、开发联调工…

使用git远程上传github

如果你不是很熟悉git&#xff0c;在使用git前请先对你的项目进行备份 进入本地文件目录&#xff0c;打开git的cmd界面&#xff08;Git Bash Here&#xff09;如果当面目录使用过git&#xff0c;有.git隐藏文件&#xff0c;则跳过第二步&#xff0c;没有则输入以下命令 git ini…

零基础如何自学网络安全?

第一阶段&#xff1a;学习一种或几种编程语言。 网络安全也属于计算机范畴&#xff0c;涉及到IT行业的&#xff0c;编程语言是不可难免的。 《Head First Python(第2版)》 作为一种高级编程语言&#xff0c;Python越来越受到网络专家的欢迎。它之所以吸引人&#xff0c;主要…

【Java 28岁了】一个有趣的例子,再推荐一些经典好书(文末惊喜福利)

文章目录 1 写在前面2 C语言与Java语言的互相调用2.1 C语言调用Java语言2.2 Java语言调用C语言 3 友情推荐4 更多分享 1 写在前面 众所周知&#xff0c;C语言和Java语言是两种不同的编程语言&#xff0c;它们的关系可以描述为Java语言是在C语言的基础上发展而来的一种高级编程…

内网如何映射到公网访问互联网

我们通常会根据本地应用场景来选择合适的中间件来搭建服务器。tomcat、 apache是比较常用的搭建服务器的中间件&#xff0c;它们之间还是有一些区别差异的。在内网本地部署搭建服务器后&#xff0c;还可以通过快解析端口映射方法&#xff0c;将内网应用地址发布到互联网&#x…

Springboot +spring security,使用过滤器方式实现验证码功能

一.简介 在前面文章章节通过自定义认证器实现了验证码功能&#xff0c;这篇文章使用过滤器来实现验证码功能。 二.思路分析 实现逻辑和通过过滤器实现json格式登录一样&#xff0c;需要继承UsernamePasswordAuthenticationFilter&#xff0c;所以文档这块主要记录下代码实现…

每日一题——两数之和(返回下标和返回数值两种情况)

每日一题 两数之和 题目链接 思路 注&#xff1a;本题只采用暴力解法&#xff0c;时间复杂度为O(n2)&#xff0c;如果采用哈希表&#xff0c;可以将时间复杂度降到O(n)&#xff0c;但由于笔者还未对哈希表展开学习&#xff0c;故不做讨论 我们直接用两层for循环来解决问题 第…