【Spring Cloud 五】OpenFeign负载均衡

这里写目录标题

  • 系列文章目录
  • 背景
  • 一、OpenFeign是什么
    • Feign是什么
      • Feign的局限性
    • OpenFeign是什么
  • 二、为什么要有OpenFeign
  • 三、如何使用OpenFeign
    • 服务提供者order-service
      • pom文件
      • yml配置文件
      • 启动类
      • 实体
      • ParamController
    • 服务消费者user-service
      • pom文件
      • yml配置文件
      • 启动类
      • 接口类
      • UserController
    • 运行效果
  • 调用超时配置
  • 五、OpenFeign调用参数的处理
  • 六、OpenFeign日志打印功能
  • 总结

系列文章目录

【Spring Cloud一】微服务基本知识
【Spring Cloud 三】Eureka服务注册与服务发现
【Spring Cloud 四】Ribbon负载均衡

背景

目前开发的项目其微服务之间的调用方式使用的就是OpenFeign的方式,为了更加的体会到它代码的便捷和高效,所以博主对OpenFeign进行了再次学习和实践,加强对OpenFeign的整体理解。

一、OpenFeign是什么

在了解OpenFeign之前我们先来了解Feign,因为OpenFeign和Feign之间是一种继承关系。

Feign是什么

Feign是一个声明式的模块化的HTTP客户端工具,他是由Netflix开发。它简化了在Java应用中编写HTTP请求的方式,能够让开发者可以通过简单的注解来定义对其他服务的RESTFul调用,从而避免编写繁琐的HTTP请求。

在传统的HTTP客户端中,我们通常需要手动构建HTTP请求,包括设置请求的URL,方法、请求头、请求体等。而使用Feign,你只需要定义一个接口,并在接口的方法上添加注解,就可以实现对其他服务的调用。Feign在运行时会根据接口定义自动创建代理实现,帮助你处理底层的HTTP请求细节。

Netflix的Feign默认集成了Eureka和Ribbon。

Feign的局限性

  1. NetFlix Feign不支持Spring MVC注解,如果在Spring Cloud使用Spring MVC注解的话,可以考虑使用Spring Cloud OpenFeign。
  2. NetFlix Feign在2018年宣布不再对其进行积极开发,虽然设计任然在维护和改进Feign但是毕竟不那么积极了。

OpenFeign是什么

OpenFeign也是一个HTTP客户端工具,它是基于Feign的封装和增强,使得在Spring Cloud环境中使用Feign更加强大和灵活。

  1. OpenFeign继承了Feign的声明式HTTP客户端的特性,允许开发者使用接口和注解来定义对其他服务的RESTful调用,从而简化了服务间通信的代码。

  2. OpenFeign还增加了一些功能,如自动负载均衡、而在Feign中,你需要手动使用Ribbon的相关注解来实现负载均衡。

  3. 支持熔断器:OpenFeign整合了Hystrix,提供了熔断器的功能,可以在服务不可用时快速失败,防止级联故障。这使得系统在面对服务故障时更加稳健。

在Spring Cloud项目中推荐使用OpenFeign来实现服务间通信,以获得更好的功能和集成性能。

二、为什么要有OpenFeign

为什么要有OpenFeign,它解决了什么问题。

  1. 相比较于传动发送HTTP请求,使用OpenFeign发送跨服务请求更加方便、灵活和高效。
  2. 更好的与Spring Cloud集成与其他组件(Eureka、Ribbon、Hystrix等)无缝集成,更加方便和高效。
  3. 自动负载均衡:OpenFeign整合了Ribbon,可以自动实现负载均衡,将请求分发给多个服务实例,提高了系统的可用性和性能。

三、如何使用OpenFeign

整个系统中有三个服务,Eurka服务,一个服务提供者,一个服务消费者。
在这里插入图片描述

如何搭建Eurka服务可以访问这篇博客【Spring Cloud 三】Eureka服务注册与服务发现

服务提供者order-service

pom文件

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd"><modelVersion>4.0.0</modelVersion><parent><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-parent</artifactId><version>2.3.12.RELEASE</version><relativePath/> <!-- lookup parent from repository --></parent><groupId>com.wangwei</groupId><artifactId>order-service</artifactId><version>0.0.1-SNAPSHOT</version><name>order-service</name><description>order-service</description><properties><java.version>8</java.version><spring-cloud.version>Hoxton.SR12</spring-cloud.version></properties><dependencies><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-web</artifactId></dependency><dependency><groupId>org.springframework.cloud</groupId><artifactId>spring-cloud-starter-netflix-eureka-client</artifactId></dependency><dependency><groupId>org.projectlombok</groupId><artifactId>lombok</artifactId><optional>true</optional></dependency><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-test</artifactId><scope>test</scope></dependency></dependencies><dependencyManagement><dependencies><dependency><groupId>org.springframework.cloud</groupId><artifactId>spring-cloud-dependencies</artifactId><version>${spring-cloud.version}</version><type>pom</type><scope>import</scope></dependency></dependencies></dependencyManagement><build><plugins><plugin><groupId>org.springframework.boot</groupId><artifactId>spring-boot-maven-plugin</artifactId><configuration><excludes><exclude><groupId>org.projectlombok</groupId><artifactId>lombok</artifactId></exclude></excludes></configuration></plugin></plugins></build></project>

yml配置文件

server:port: 8080spring:application:name: order-serviceeureka:client:service-url: defaultZone: http://localhost:8761/eurekaregister-with-eureka: true #设置为fasle 不往eureka-server注册fetch-registry: true #应用是否拉取服务列表到本地registry-fetch-interval-seconds: 10 #为了缓解服务列表的脏读问题,时间越短脏读越少 性能相应的消耗回答instance: #实例的配置instance-id: ${eureka.instance.hostname}:${spring.application.name}:${server.port}hostname: localhost #主机名称或者服务ipprefer-ip-address: true #以ip的形式显示具体的服务信息lease-renewal-interval-in-seconds: 10 #服务实例的续约时间间隔

启动类

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

实体

@Data
@AllArgsConstructor
@NoArgsConstructor
@Builder
public class Order {private Integer id;private String name;private Double price;private Date time;}

ParamController

@RestController
public class ParamController {@GetMapping("testUrl/{name}/and/{age}")public String testUrl(@PathVariable("name")String name ,@PathVariable("age")Integer age){System.out.println(name+":"+age);return "ok";}@GetMapping("oneParam")public String oneParam(@RequestParam(required = false)String name){System.out.println(name);return "ok";}@GetMapping("twoParam")public String twoParam(@RequestParam(required = false)String name,@RequestParam(required = false)Integer age){System.out.println(name+":"+age);return "ok";}@PostMapping("oneObj")public String oneObj(@RequestBody Order order){System.out.println(order);return "ok";}@PostMapping("oneObjOneParam")public String twoParam(@RequestBody Order order,@RequestParam("name")String name){System.out.println(order+":"+name);return "ok";}
}

服务消费者user-service

pom文件

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd"><modelVersion>4.0.0</modelVersion><parent><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-parent</artifactId><version>2.3.12.RELEASE</version><relativePath/> <!-- lookup parent from repository --></parent><groupId>com.wangwei</groupId><artifactId>user-service</artifactId><version>0.0.1-SNAPSHOT</version><name>user-service</name><description>user-service</description><properties><java.version>8</java.version><spring-cloud.version>Hoxton.SR12</spring-cloud.version></properties><dependencies><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-web</artifactId></dependency><dependency><groupId>org.springframework.cloud</groupId><artifactId>spring-cloud-starter-netflix-eureka-client</artifactId></dependency><dependency><groupId>org.springframework.cloud</groupId><artifactId>spring-cloud-starter-openfeign</artifactId></dependency><dependency><groupId>org.projectlombok</groupId><artifactId>lombok</artifactId><optional>true</optional></dependency><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-test</artifactId><scope>test</scope></dependency></dependencies><dependencyManagement><dependencies><dependency><groupId>org.springframework.cloud</groupId><artifactId>spring-cloud-dependencies</artifactId><version>${spring-cloud.version}</version><type>pom</type><scope>import</scope></dependency></dependencies></dependencyManagement><build><plugins><plugin><groupId>org.springframework.boot</groupId><artifactId>spring-boot-maven-plugin</artifactId><configuration><excludes><exclude><groupId>org.projectlombok</groupId><artifactId>lombok</artifactId></exclude></excludes></configuration></plugin></plugins></build></project>

yml配置文件

server:port: 8081spring:application:name: user-serviceeureka:client:service-url: defaultZone: http://localhost:8761/eurekaregister-with-eureka: true #设置为fasle 不往eureka-server注册fetch-registry: true #应用是否拉取服务列表到本地registry-fetch-interval-seconds: 10 #为了缓解服务列表的脏读问题,时间越短脏读越少 性能相应的消耗回答instance: #实例的配置instance-id: ${eureka.instance.hostname}:${spring.application.name}:${server.port}hostname: localhost #主机名称或者服务ipprefer-ip-address: true #以ip的形式显示具体的服务信息lease-renewal-interval-in-seconds: 10 #服务实例的续约时间间隔

启动类

package com.wangwei.userservice;import feign.Logger;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.client.loadbalancer.LoadBalanced;
import org.springframework.cloud.netflix.eureka.EnableEurekaClient;
import org.springframework.cloud.openfeign.EnableFeignClients;
import org.springframework.context.annotation.Bean;
import org.springframework.web.client.RestTemplate;@SpringBootApplication
@EnableEurekaClient
@EnableFeignClients //开启feign的客户端,才可以帮助我们发送调用
public class UserServiceApplication {public static void main(String[] args) {SpringApplication.run(UserServiceApplication.class, args);}
}

接口类

package com.wangwei.userservice.feign;import com.wangwei.userservice.domain.Order;
import org.springframework.cloud.openfeign.FeignClient;
import org.springframework.web.bind.annotation.*;/*** @FeignClient(value = "order-service")* value就是提供者的应用名称*/
@FeignClient(value = "order-service")
public interface UserOrderFeign {/*** 你需要调用哪个controller 就写它的方法签名(除了方法体的一个方法的所有属性* @return*/@GetMapping("doOrder")String doOrder();@GetMapping("testUrl/{name}/and/{age}")public String testUrl(@PathVariable("name")String name , @PathVariable("age")Integer age);@GetMapping("oneParam")public String oneParam(@RequestParam(required = false)String name);@GetMapping("twoParam")public String twoParam(@RequestParam(required = false)String name,@RequestParam(required = false)Integer age);@PostMapping("oneObj")public String oneObj(@RequestBody Order order);@PostMapping("oneObjOneParam")public String oneObjOneParam(@RequestBody Order order,@RequestParam("name")String name);
}

UserController

package com.wangwei.userservice.controller;import com.wangwei.userservice.domain.Order;
import com.wangwei.userservice.feign.UserOrderFeign;
import feign.Feign;
import org.apache.catalina.User;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.cloud.openfeign.FeignClient;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.client.RestTemplate;import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
import java.util.Date;@RestController
public class UserController {@Autowiredprivate UserOrderFeign userOrderFeign;/*** 总结:* feign的默认等待时间为1s* 超过1s就直接报错了** @return*/@GetMapping("userDoOrder")public String userDoOrder(){//这里发起远程调用String result = userOrderFeign.doOrder();return result;}@GetMapping("testParam")public String testParam(){String url = userOrderFeign.testUrl("David", 18);System.out.println(url);String david = userOrderFeign.oneParam("David");System.out.println(david);String wangwei = userOrderFeign.twoParam("wangwei", 18);System.out.println(wangwei);Order order = Order.builder().name("西蓝花").price(5D).time(new Date()).id(1).build();String s = userOrderFeign.oneObj(order);System.out.println(s);String wangwei1 = userOrderFeign.oneObjOneParam(order, "wangwei");System.out.println(wangwei1);return "ok";}
}

运行效果

先启动Eureka服务再启动服务提供者,最后启动服务消费者。

如下图所示已经调用成功。
在这里插入图片描述

在这里插入图片描述

调用超时配置

因为ribbon默认调用超时时长为1s,可以进行修改,可以查看DefaultClientConfigImpl。

我们在服务提供者order-service中新建一个controller,进行超时测试。

@RestController
public class OrderController {@GetMapping("doOrder")public String doOrder(){try{//模拟操作数据库等 耗时2sTimeUnit.SECONDS.sleep(2);}catch (InterruptedException e){e.printStackTrace();}return "牛奶-鸡蛋-麦片";}
}

然后我们通过服务消费者user-service进行调用测试:
可以发现出现了超时。
在这里插入图片描述
我们可以在消费者的配置文件中声明Ribbon的超时时间。

# feign只是帮你封装了远程调用的功能 底层还是ribbon 所以我们需要去修改ribbon的时间ribbon:ReadTimeout: 3000 # 3s超时时间(从服务器读取到可用资源所用的时间)ConnectTimeout: 3000 #连接服务超时时间

添加这个配置就行了。

五、OpenFeign调用参数的处理

首先传参确保消费者和提供者的参数列表一致,包括返回值,方法签名。

  1. 通过URL传参,GET请求,参数列表使用@PathVariable
  2. 如果是GET请求,每个基本参数必须加上@RequestParam
  3. 如果是POST请求,而且是对象集合等参数,必须加上@RequestBody或者@RequestParam

六、OpenFeign日志打印功能

OpenFeign还提供了日志打印功能,通过日志打印功能,能够清晰的看到发送的HTTP请求中的细节。

总结

在Spring Cloud中是OpenCluod的步骤主要是,引入openFeign依赖;启动类添加开启openFeign客户端;声明与服务端相同的方法并添加对应注册;需要注意根据项目情况配置调用服务的超时时间。

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

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

相关文章

怎么维护自己的电脑?

方向一&#xff1a;我的电脑介绍 我使用的是一台来自知名品牌的笔记本电脑。它具有高性能的核心配置&#xff0c;如快速处理器、大容量内存和高性能显卡&#xff0c;以及宽敞的存储空间。我选择这台电脑主要是因为它的出色性能和可靠性&#xff0c;能够满足我在学习和工作中的…

Bean的实例化方法

目录 1.工厂模式通常有三种形态&#xff1a; 2.简单工厂 2.1 静态工厂 2.1通过factory-bean实例化 2.3通过FactoryBean接口实例化 3.测试 关于容器的使用 3.1获得spring文件方式 3.2getBean方式 4.关闭容器 1.工厂模式通常有三种&#xff1a; 第一种&#xff1a;简单工…

(杭电多校)2023“钉耙编程”中国大学生算法设计超级联赛(5)

1001 Typhoon 计算几何 对于每一个避难点,计算其到所有线段的距离,取min即可 AC代码&#xff1a; #include<iostream> #include<algorithm> #include<cstring> #include<vector> #include<deque> #include<cmath> #include<cstdio&…

【Linux命令200例】whereis用于搜索以及定位二进制文件

&#x1f3c6;作者简介&#xff0c;黑夜开发者&#xff0c;全栈领域新星创作者✌&#xff0c;阿里云社区专家博主&#xff0c;2023年6月csdn上海赛道top4。 &#x1f3c6;本文已收录于专栏&#xff1a;Linux命令大全。 &#x1f3c6;本专栏我们会通过具体的系统的命令讲解加上鲜…

nexus迁移

数据和配置迁移 打包两个目录&#xff0c;配置nexus-2.13.0-01和数据sonatype-work 数据量大可以split分割之后迁移再合并 大概看下文件目录 [roottest nexus]# tree -L 3 . ├── nexus-2.13.0-01 │ ├── bin │ │ ├── jsw │ │ ├── nexus │ │ …

selenium 遇到更新chorme驱动

打开浏览器,在地址栏输入chrome://version/便可以查看到谷歌当前的版本号 谷歌浏览器驱动的下载网址 http://chromedriver.storage.googleapis.com/index.htmlhttp://chromedriver.storage.googleapis.com/index.html 解压后把chromedriver.exe 放到python安装的目录下&am…

谈一谈缓存穿透,击穿,雪崩

缓存穿透 缓存穿透是指在使用缓存系统时&#xff0c;频繁查询一个不存在于缓存中的数据&#xff0c;导致这个查询每次都要通过缓存层去查询数据源&#xff0c;无法从缓存中获得结果。这种情况下&#xff0c;大量的请求会直接穿透缓存层&#xff0c;直接访问数据源&#xff0c;…

电动自行车上架eBay的UL2849、16CFR1512测试标准

在奥运经济的带动下&#xff0c;今年以来运动自行车消费有较大幅度增长&#xff0c;其中高端消费者对进口自行车需求扩张&#xff0c;上半年竞赛型自行车进口量同比增长49.5%。另外&#xff0c;电助力自行车在国际市场也倍受追捧&#xff0c;国际自行车贸易总额的60%来自中国&a…

嵌入式入门教学——C51

一、前期准备 1、硬件设备 2、软件设备 二、预备知识 1、什么是单片机&#xff1f; 在一片集成电路芯片上集成微处理器、存储器、IO接口电路&#xff0c;从而构成了单芯片微型计算机&#xff0c;及单片机。STC89C52单片机&#xff1a; STC&#xff1a;公司89&#xff1a;所属…

【计算机网络】应用层协议 -- DNS协议

文章目录 1. DNS背景2. 域名简介3. 域名解析过程4. 使用dig查看DNS过程 1. DNS背景 DNS&#xff08;Domain Name System&#xff0c;域名系统&#xff09;协议&#xff0c;是一个用来将域名转化为IP地址的应用层协议。 TCP/IP当中通过IP地址和端口号的方式&#xff0c;来确定…

调试正在运行的程序(Keil)

大家好&#xff0c;我是惊觉。接上一篇调试正在运行的程序(STM32CubeIDE)&#xff0c;今天Keil的实现方法。调试正在运行的程序&#xff0c;属于附着调试&#xff0c;在启动调试器时不会重置单片机的运行状态&#xff0c;从而可以定位死机等问题。没看过上一篇的同学&#xff0…

SystemC的调度器

文章目录 前言调度器初始化evaluatewait updatenotify delta notificationtime notification仿真结束 前言 SystemC是基于C的库&#xff0c;主要用来对 IC 进行功能建模和性能建模。有时也被用来当做 RTL (register transfer level) 级的升级版 HLS(High Level synthesis) 直接…

力扣 416. 分割等和子集

题目来源&#xff1a;https://leetcode.cn/problems/partition-equal-subset-sum/description/ C题解&#xff08;思路来源代码随想录&#xff09; &#xff1a; 背包问题有多种背包方式&#xff0c;常见的有&#xff1a;01背包、完全背包、多重背包、分组背包和混合背包等等。…

JVM基础篇-虚拟机栈

JVM基础篇-虚拟机栈 定义 Java Virtual Machine Stacks &#xff08;Java 虚拟机栈&#xff09; 每个线程运行时所需要的内存&#xff0c;称为虚拟机栈每个栈由多个栈帧&#xff08;Frame&#xff09;组成&#xff0c;对应着每次方法调用时所占用的内存每个线程只能有一个活动…

Manim(一款强大的数学可视化动画引擎)学习历程

相逢情便深&#xff0c;恨不相逢早 第一眼看见上面这种类型的视频我就深深被它的简约清楚所折服&#xff0c;我觉得它完全符合我的审美&#xff0c;我也相信只要了解过制作这种视频的软件的人都会喜欢上它。运用这种风格比较有名的是b站里的一位up主名叫3Blue1Brown&#xff0…

C++ 模板初阶

泛型编程 泛型编程&#xff1a;编写与类型无关的通用代码&#xff0c;是代码复用的一种手段。模板是泛型编程的基础 模板分为&#xff1a;函数模板和类模板 函数模板 概念 函数模板代表了一个函数家族&#xff0c;该函数模板与类型无关&#xff0c;在使用时被参数化&a…

数据结构 | 搜索和排序——排序

目录 一、冒泡排序 二、选择排序 三、插入排序 四、希尔排序 五、归并排序 六、快速排序 排序是指将集合中的元素按照某种顺序排序的过程。 一、冒泡排序 冒泡排序多次遍历列表。它比较相邻的元素&#xff0c;将不合顺序的交换。每一轮遍历都将下一个最大值放到正确的位…

【抽水蓄能电站】基于粒子群优化算法的抽水蓄能电站的最佳调度方案研究(Matlab代码实现)

目录 &#x1f4a5;1 概述 &#x1f4da;2 运行结果 &#x1f389;3 参考文献 &#x1f308;4 Matlab代码、数据、文章讲解 &#x1f4a5;1 概述 文献来源&#xff1a; 摘要&#xff1a;抽水蓄能电站作为当前电力系统重要的储能和调峰电源同时具有填谷、调频、调相、事故备用以…

ETHERNET/IP 转ETHERCAT连接ethercat总线伺服如何控制

捷米JM-EIP-ECAT网关连接到ETHERNET/IP总线中做为从站使用&#xff0c;连接到ETHERCAT总线中做为从站使用&#xff0c;可以同时满足多种工业生产的需求。支持广泛的设备类型&#xff0c;可以和多种不同的设备进行通讯。 技术参数 ETHERNET/IP 技术参数 网关做为 ETHERNET/IP …

记一次 HTTPS 抓包分析和 SNI 的思考

日常听说 HTTPS 是加密协议&#xff0c;那现实中的 HTTPS 流量&#xff0c;是真的完全加密吗&#xff1f; ——答案是&#xff0c;不一定。原因嘛&#xff0c;抓个包就知道了。 我们用 curl 命令触发一下&#xff1a; curl -v https://s-api.37.com.cn/api/xxx * Trying 1…