SpringCloud学习笔记-3
声明:笔记来源于网络,如有侵权联系删除
1 openfeign
1)openfeign远程调用声明式实现
1.启动类中添加注解 @EnableFeignClients
@EnableFeignClients
@SpringBootApplication
public class OrderMainApplication {public static void main(String[] args){SpringApplication.run(OrderMainApplication.class,args);}//项目启动时执行@BeanApplicationRunner applicationRunner(NacosConfigManager nacosConfigManager){return args->{System.out.println("=========");ConfigService configService = nacosConfigManager.getConfigService();configService.addListener("service-order.properties", "DEFAULT_GROUP", new Listener() {@Overridepublic Executor getExecutor() {return Executors.newFixedThreadPool(4);}@Overridepublic void receiveConfigInfo(String configInfo) {System.out.println("变化的信息为:"+configInfo);//模拟邮件发送System.out.println("邮件发送:"+configInfo+"变量发生变化请注意");}});};}
}
2.创建feignclient接口
输入feign.ProductFeignClient
@FeignClient(value = "service-product")
public interface ProductFeignClient {@GetMapping("/product/{id}")//标注在controller里面是接收请求,标注在FeignClient上是发送请求Product getProductById(@PathVariable("id") Long id);}
@Slf4j
@Service
public class OrderServiceImpl implements OrderService {@AutowiredDiscoveryClient discoveryClient;@AutowiredRestTemplate restTemplate;@AutowiredLoadBalancerClient loadBalancerClient;@AutowiredProductFeignClient productFeignClient;@Overridepublic Order createOrder(Long productId, Long userId) {//Product product = getProductFromRemoteWithLoadBalanceAnnotation(productId);//使用openfeignProduct product = productFeignClient.getProductById(productId);Order order = new Order();order.setId(1L);order.setAddress("京海");//金额order.setTotalAmount(product.getPrice().multiply(BigDecimal.valueOf(product.getNum())));order.setUserId(userId);order.setNickName("张三");order.setProductList(Arrays.asList(product));return order;}//普通的调用private Product getProductFromRemote(Long productId){//获取所有商品微服务实例所在的ip和端口号List<ServiceInstance> instanceList = discoveryClient.getInstances("service-product");//获取第一个实例ServiceInstance instance = instanceList.get(0);//拼接远程调用地址 http://localhost:9000/product/4String url = "http://"+instance.getHost()+":"+instance.getPort()+"/product/"+productId;//打印日志log.info("请求地址{}",url);//给远程发送请求Product pro = restTemplate.getForObject(url, Product.class);return pro;}//LoadBalancerClient实现负载均衡private Product getProductFromRemoteWithLoadBalancer(Long productId){ServiceInstance instance = loadBalancerClient.choose("service-product");//拼接远程调用地址 http://localhost:9000/product/4String url = "http://"+instance.getHost()+":"+instance.getPort()+"/product/"+productId;//打印日志log.info("请求地址{}",url);//给远程发送请求Product pro = restTemplate.getForObject(url, Product.class);return pro;}//注解实现负载均衡private Product getProductFromRemoteWithLoadBalanceAnnotation(Long productId){String url = "http://service-product/product/"+productId;//给远程发送请求 此时 restTemplate会动态替换url的值Product pro = restTemplate.getForObject(url, Product.class);return pro;}}
重启服务,然后浏览器输入http://localhost:8000/create?userId=5&productId=88,然后回车,之后再刷新2次,这样相当于调用了3次接口。
可以看到返回数据成功,并且product微服务3个实例每个实例都打印了hello,自动做到了负载均衡。
2)openfeign远程调用,第三方api
这个只是简单讲解下
如果@FeignClient里面没有url这个参数,那么就是需要在注册中心找到接口的地址进行调用。上图中有url这个参数,所以不用去注册中心找,直接拼接PostMapping里面的后缀,然后调用三方接口了。这是个获取天气的接口,可以看到里面有token,Authorization,cityId等入参。这就是调用第三方api的方法,利用feign也可以实现
3)openfeign远程调用小技巧
1.如果是调用自己写的微服务的接口,写feign接口的时候,直接复制controller里面的方法拿到feign接口里面,基本上是完全一样的。如下图:
可以看到基本一样,直接复制controller里面的方法放到feign接口里面就可以了。
2. 如果是第三方api
如上图,这个就需要看下三方接口文档了,按照上面这种格式进行编写就行,url拼接,参数按照三方接口文档的要求来传就行。
3.面试题 服务端负载均衡和客户端负载均衡的区别。
如上图第一个,发起调用的时候,需要通过注册中心获取地址,然后自己通过负载均衡选择具体调用地址调用,这就是客户端负载均衡。
第二个,直接调用固定的地址访问墨迹天气,墨迹天气对外暴漏一个固定地址,接收请求时,自己根据负载均衡选择调用自己的具体微服务,这就是被调用方(服务端)负载均衡
4)openfeign日志配置
1.yml文件配置日志级别
logging:level:com.atguigu.order.feign: debug
注意包名要换成自己的feign所在的包哈
2. 创建logger的bean类,注意引入的包是feign下的
@Configuration
public class ProductServiceConfig {@BeanLogger.Level feignLoggerLevel(){return Logger.Level.FULL;}
}
重启服务,然后浏览器输入http://localhost:8000/create?userId=5&productId=88
可以看到打印了如下日志:
5)openfeign超时控制
服务调用时,如果被调用方宕机,而调用方还在一直请求和等待响应时,如果一直有新的请求进来也是等待,那么就会造成资源耗尽,服务雪崩。因此需要有超时控制。
如果未超时,返回正确结果。如果超时了,1.返回错误信息 2.返回兜底数据
这里超时就需要做出配置。
超时有两种情况:
1connectTimeout 连接超时 就是A向B请求建立连接,从开始请求到连接成功的时间,如上图1.建立连接的耗时。生活中的例子就是A给B打电话,从拨通号码到B接听,这段时间的耗时就是连接时间。
2readTimeout 读取超时 就是A发送请求给B后,B处理自己的业务,处理后把结果返回给A的耗时,也就是上图中B处理业务的耗时。生活中的例子就是A给B打电话,B接听后,A问:吃了没。B过了5S回答:吃了。那么这5S就是读取耗时。
openFeign默认的连接超时时间是10秒,读取超时时间是60秒。
下面我们测试下这个时间。
我们改下product服务的接口处理时间是100秒
@Service
public class ProductServiceImpl implements ProductService {@Overridepublic Product getById(Long productId) {Product product = new Product();product.setId(productId);product.setPrice(new BigDecimal("99"));product.setProductName("苹果-"+productId);product.setNum(2);//设置休眠100秒try {TimeUnit.SECONDS.sleep(100);} catch (InterruptedException e) {throw new RuntimeException(e);}return product;}
}
重启服务,然后浏览器输入http://localhost:8000/create?userId=5&productId=88
可以看到浏览器一直转圈,60s左右后报错(因为我们设置的是处理返回结果需要100S,但是feign之间调用的默认超时设置的是60S)
下面我们来修改这个超时时间
输入 application-feign.yml 回车
里面配置如下代码:
spring:cloud:openfeign:client:config:default:logger-level: fullconnect-timeout: 3000read-timeout: 5000service-product:logger-level: fullconnect-timeout: 3000read-timeout: 5000
default表示默认配置。service-product表示 product这个微服务特定的配置,如果找不到微服务特定配置,就按默认配置
application.yml中,添加包含feign.yml的配置 include:feign表示导入application-feign.yml这个配置
server:port: 8000
spring:profiles:active: devinclude: feignapplication:name: service-ordercloud:nacos:server-addr: 127.0.0.1:8848config:import-check:enabled: falsenamespace: ${spring.profiles.active:dev}
logging:level:com.atguigu.order.feign: debug
---
spring:config:import:- nacos:common.properties?group=order- nacos:database.properties?group=orderactivate:on-profile: dev
---
spring:config:import:- nacos:common.properties?group=order- nacos:database.properties?group=orderactivate:on-profile: test
---
spring:config:import:- nacos:common.properties?group=order- nacos:database.properties?group=orderactivate:on-profile: prod
重启服务器后,再次刷新页面,http://localhost:8000/create?userId=5&productId=88
可以看到,只过了5S左右就返回错误信息了,表示超时时间配置成功。
注意以上都是测试的readTimeout的配置。
6)openfeign重试机制
上面超时失败了后,需要重新调用接口(总不能不返回正确的数据吧,需要再次尝试下),这就引入了重试的机制。
如上图,默认配置是NEVER_RETRY,就是从不重试。但是可以改下配置。上图中的100,指的是第一次重试间隔100毫秒,后面的1指的是重试的最大间隔是1秒,后面的5是指的重试5次。当第一次重试时是过了100毫秒,如果还是失败,第二次重试就是100乘以1.5,也是150毫秒,如果耗时失败,那第三次重试是100乘以1.5再乘以1.5,第四次就是100*1.5*1.5*1.5,依次类推,最多尝试5次,且如果这个乘机大于1秒(1000毫秒),那就按照1S算,也就是最大间隔是1秒。
下面我们配置下这个参数
创建bean类
@Configuration
public class ProductServiceConfig {@LoadBalanced//注解式负载均衡@Beanpublic RestTemplate restTemplate(){return new RestTemplate();}@BeanLogger.Level feignLoggerLevel(){return Logger.Level.FULL;}//重试机制@BeanRetryer retryer(){return new Retryer.Default(100,1,5);}
}
修改下product,让其打印hello
@RestController
public class ProductController {@AutowiredProductService productService;//查询商品@GetMapping("/product/{id}")public Product getProduct(@PathVariable("id")Long productId){System.out.println("hello");Product product = productService.getById(productId);return product;}
}
重启2个服务,注意product只启动一个实例哈。然后浏览器发送http://localhost:8000/create?userId=5&productId=88
可以看到浏览器一共等待了大概25秒(5秒*5次),控制台打印了5次hello
而请求端的错误日志也是5次(5次请求日志+1次抛出异常日志)
总结:最大请求次数,包含了最初的第一次。也就是一共最多请求5次。
7)openfeign拦截器
openfeign在请求之前和获取结果后都可以进行业务处理。响应拦截器用的较少,我们看下请求拦截器。
创建拦截器类
输入interceptor.XTokenRequestInterceptor
@Component
public class XTokenRequestInterceptor implements RequestInterceptor {/***请求拦截器* @param requestTemplate 请求模版*/@Overridepublic void apply(RequestTemplate requestTemplate) {System.out.println("XTokenRequestInterceptor ... = " + requestTemplate);requestTemplate.header("X-Token", UUID.randomUUID().toString());}
}
上图中代码是生成一个随机的字符作为请求头X-Token
把商品的休眠100秒逻辑注释掉
@Service
public class ProductServiceImpl implements ProductService {@Overridepublic Product getById(Long productId) {Product product = new Product();product.setId(productId);product.setPrice(new BigDecimal("99"));product.setProductName("苹果-"+productId);product.setNum(2);//设置休眠100秒
/* try {TimeUnit.SECONDS.sleep(100);} catch (InterruptedException e) {throw new RuntimeException(e);}*/return product;}
}
修改商品的controller如下:打印接收到的token
@RestController
public class ProductController {@AutowiredProductService productService;//查询商品@GetMapping("/product/{id}")public Product getProduct(@PathVariable("id")Long productId, HttpServletRequest httpServletRequest){String header = httpServletRequest.getHeader("X-Token");System.out.println("hello token=【"+header+"】");Product product = productService.getById(productId);return product;}
}
重启两个微服务,然后调用http://localhost:8000/create?userId=5&productId=88
可以看到两个微服务都打印了token的值,且完全相等。说明拦截器生效了。
8)openfeign Fallback:兜底返回
如上图,前面我们说过,如果被调用服务超时或者错误,那么2个情况,1:返回错误信息,2返回兜底数据。如果返回错误信息,那么可能就影响用户体验或者整个流程的继续往下流转,这时候我们更希望返回一个兜底数据,拿到数据后,我们进行兜底逻辑的处理,使得系统更加健壮。
兜底返回的目的就是为了在远程调用失败的时候拿到一个默认数据,使得业务继续往下推进。
下面开始编写代码
在order微服务的feign包,鼠标右键,创建一个类,输入 fallbak.ProductFeignClientFallback,回车
@Component
public class ProductFeignClientFallback implements ProductFeignClient {@Overridepublic Product getProductById(Long id) {System.out.println("兜底回调。。。");Product product = new Product();product.setId(id);product.setPrice(new BigDecimal("0"));product.setProductName("未知商品");product.setNum(0);return product;}
}
同时在feignclient里面指定这个类
@FeignClient(value = "service-product",fallback = ProductFeignClientFallback.class)
public interface ProductFeignClient {@GetMapping("/product/{id}")//标注在controller里面是接收请求,标注在FeignClient上是发送请求Product getProductById(@PathVariable("id") Long id);}
这样就可以了。同时我们把重试机制去掉,便于观察兜底回调生效。
@Configuration
public class ProductServiceConfig {@LoadBalanced//注解式负载均衡@Beanpublic RestTemplate restTemplate(){return new RestTemplate();}@BeanLogger.Level feignLoggerLevel(){return Logger.Level.FULL;}//重试机制
/* @BeanRetryer retryer(){return new Retryer.Default(100,1,5);}*/
}
此时还没完。如果需要兜底回调,还需要Sentinel。我们引入这个依赖
在order的pom中引入依赖,右上角刷新应用
<dependencies><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-web</artifactId></dependency><dependency><groupId>org.springframework.cloud</groupId><artifactId>spring-cloud-starter-loadbalancer</artifactId></dependency><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-test</artifactId><scope>test</scope></dependency><dependency><groupId>com.alibaba.cloud</groupId><artifactId>spring-cloud-starter-alibaba-sentinel</artifactId></dependency></dependencies>
我们在feign.yml中把sentinel开启
spring:cloud:openfeign:client:config:default:logger-level: fullconnect-timeout: 3000read-timeout: 5000service-product:logger-level: fullconnect-timeout: 3000read-timeout: 5000
feign:sentinel:enabled: true
这时候准备就绪,重启order服务,同时停掉product服务。
页面输入http://localhost:8000/create?userId=5&productId=88回车
可以看到返回了配置的兜底商品数据(未知商品)。
当我们把product服务启动时,再次刷新页面,可以看到如下图,又返回了正确数据:
相关文章:

SpringCloud学习笔记-3
声明:笔记来源于网络,如有侵权联系删除 1 openfeign 1)openfeign远程调用声明式实现 1.启动类中添加注解 EnableFeignClients EnableFeignClients SpringBootApplication public class OrderMainApplication {public static void main(St…...
【时时三省】(C语言基础)局部变量和全局变量
山不在高,有仙则名。水不在深,有龙则灵。 ----CSDN 时时三省 以前所见到的程序大多数是一个程序只包含一个main函数,变量是在函数的开头处定义的。这些变量在本函数范围内有效,即在本函数开头定义的变量,在本函数中可…...
An improved YOLACT algorithm for instance segmentation of stacking parts
【一种用于堆叠零件实例分割的改进 YOLACT 算法】 摘要 实例分割在众多应用场景中均是一项至关重要的任务。对于计算机视觉而言,堆叠物体的实例分割是一项挑战。为应对这一挑战,我们提出了一种改进的 YOLACT(You Only Look At CoefficienTs)算法。为提高密集堆叠场景下特…...
使用API网关Kong配置反向代理和负载均衡
简介 Kong 是一个微服务API网关。 Kong是一个云原生,快速,可扩展和分布式微服务抽象层(也称为API网关,API中间件或在某些情况下为Service Mesh)。 作为2015年的开源项目,其核心价值在于高性能和可扩展性。…...

BugKu Web渗透之eval
启动场景,打开网页,显示的是一段代码。 步骤一: 分析代码。 代码大概意思是: <?php//包含"flag.php"的文件include "flag.php"; //获取网页请求的hello数据$a $_REQUEST[hello]; //显示变量a的详…...

DAY45 可视化
DAY 45 Tensorborad 之前的内容中,我们在神经网络训练中,为了帮助自己理解,借用了很多的组件,比如训练进度条、可视化的loss下降曲线、权重分布图,运行结束后还可以查看单张图的推理效果。 如果现在有一个交互工具可…...

11.RV1126-ROCKX项目 API和人脸检测画框
一.ROCKX的API 1.ROCKX的作用 ROCKX的AI组件可以快速搭建 AI的应用,这些应用可以是车牌识别、人脸识别、目标识别,人体骨骼识别等等。主要用于各种检测识别。例如下图: 2.ROCKX人脸识别的API rockx_ret_t rockx_create(rockx_handle_t *han…...

超构光学与 AR 的深度融合 | 攻克 VAC 与眼动范围难题
原文信息 原文标题:“Three-dimensional varifocal meta-device for augmented reality display” 第一作者:宋昱舟,袁家琪,陳欽杪,刘小源 ,周寅,程家洛,肖淑敏*,陈沐…...

[ Qt ] | 与系统相关的操作(三):QFile介绍和使用
目录 之前的操作文件的方式 Qt中的文件操作简介 QFile 打开 读 写 关闭 一个例子来说明 QFileInfo 之前的操作文件的方式 C语言中,fopen 打开文件,fread fwrite 读写文件,fclose 关闭文件。 C中,fstream 打开文件&…...
RetroMAE 预训练任务
RetroMAE 预训练任务的具体步骤,围绕 编码(Encoding)、解码(Decoding)、增强解码(Enhanced decoding) 三个核心阶段展开,以下结合图中流程拆解: 一、阶段 A:…...

软件工程:如何做好软件产品
1、什么是产品 从项目到产品 产品:满足行业共性需求的标准产品。即要能够做到配置化的开发,用同一款产品最大限度地满足不同客户的需求,同时让产品具有可以快速响应客户需求变化的能力。 好的产品一定吸收了多个项目的共性,一定是…...

蓝桥杯 省赛 2025python(B组)题目(分析)
目录 第一题 为什么答案是103而不是104? 第二题 为什么必须按长度排序? 第三题 易错点总结 第四题 逻辑问题: 可能超过时间复杂度的代码示例 1. 暴力枚举所有可能的子串 2. 递归回溯 第五题 1. 暴力枚举法 2. 优化枚举 3.数…...

React - 组件通信
组件通信 概念:组件通信就是组件之间数据传递,根据组件嵌套关系不同,有不同的通信方法 父传子 —— 基础实现 实现步骤 父组件传递数据 - 在子组件标签上绑定属性子组件接收数据 - 子组件通过props参数接收数据 声明子组件并使用 //声明子…...
《前端面试题:CSS的display属性》
CSS display属性完全指南:深入理解布局核心属性 掌握display属性是CSS布局的基石,也是前端面试必考知识点 一、display属性概述:布局的核心控制 display属性是CSS中最重要、最基础的属性之一,它决定了元素在页面上的渲染方式和布…...

飞牛使用Docker部署Tailscale 内网穿透教程
之前发过使用docker部署Tailscale的教程,不过是一年前的事情了,今天再重新发表一遍,这次使用compose部署更加方便,教程也会更加详细一点,希望对有需要的朋友有所帮助! 对于大部分用户来说,白嫖 …...

《数据挖掘》- 房价数据分析
这里写目录标题 采用的技术1. Python编程语言2. 网络爬虫库技术点对比与区别项目技术栈的协同工作流程 代码解析1. 导入头文件2. 读取原始数据3. 清洗数据4. 数据分割4.1 统计房屋信息的分段数量4.2 将房屋信息拆分为独立列4.3 处理面积字段4.4 删除原始房屋信息列 5. 可视化分…...
centos中的ulimit命令
centos中的ulimit命令 ulimit的作用CENTOS系统文件配置配置文件地址配置格式 配置方法 ulimit的作用 ulimit用于限制shell启动进程所占用的资源,支持以下各种类型的限制:所创建的内核文件的大小、进程数据块的大小、Shell进程创建文件的大小、内存锁住的…...
git提交代码和解决冲突修复bug
提交到分支的步骤如下: 确保你当前在开发分支上,可以使用命令 git branch 来查看当前所在分支,并使用 git checkout 命令切换到开发分支。使用 git add 命令将修改的文件添加到暂存区。使用 git commit 命令提交代码到本地仓库。 解决合并冲…...
华为仓颉语言初识:并发编程之同步机制(上)
前言 线程同步机制是多线程下解决线程对共享资源竞争的主要方式,华为仓颉语言提供了三种常见的同步机制用来保证线程同步安全,分别是原子操作,互斥锁和条件变量。本篇文章详细介绍主要仓颉语言解决同步机制的方法,建议点赞收藏&a…...
php中实现邮件发送功能
要在php项目中实现邮件发送功能,推荐使用phpmailer库通过smtp协议配置。首先安装phpmailer扩展,可通过composer命令composer require phpmailer/phpmailer安装;若未使用composer则手动引入源码。接着配置smtp信息,包括服务器地址&…...

C++之动态数组vector
Vector 一、什么是 std::vector?二、std::vector 的基本特性(一)动态扩展(二)随机访问(三)内存管理 三、std::vector 的基本操作(一)定义和初始化(二…...
arc3.2语言sort的时候报错:(sort < `(2 9 3 7 5 1)) 需要写成这种:(sort > (pair (list 3 2)))
arc语言sort的时候报错:(sort < (2 9 3 7 5 1)) arc> (sort < (2 9 3 7 5 1)) Error: "set-car!: expected argument of type <pair>; given: 9609216" arc> (sort < (2 9 3 )) Error: "Function call on inappropriate object…...
Android动态广播注册收发原理
一、动态广播的注册流程 1. 注册方式 动态广播通过代码调用 Context.registerReceiver() 方法实现,需显式指定 IntentFilter 和接收器实例: // 示例:在 Activity 中注册监听网络变化的广播 IntentFilter filter new IntentFilter…...
Ubuntu 系统通过防火墙管控 Docker 容器
Ubuntu 系统通过防火墙管控 Docker 容器指南 一、基础防火墙配置 # 启用防火墙 sudo ufw enable# 允许 SSH 连接(防止配置过程中断联) sudo ufw allow 22/tcp二、Docker 配置调整 # 编辑 Docker 配置文件 sudo vim /etc/docker/daemon.json配置文件内…...
AI 模型分类全解:特性与选择指南
人工智能(AI)技术正以前所未有的速度改变着我们的生活和工作方式。AI 模型作为实现人工智能的核心组件,种类繁多,功能各异。从简单的线性回归模型到复杂的深度学习网络,从文本生成到图像识别,AI 模型的应用…...

【Zephyr 系列 11】使用 NVS 实现 BLE 参数持久化:掉电不丢配置,开机自动加载
🧠关键词:Zephyr、NVS、非易失存储、掉电保持、Flash、AT命令保存、配置管理 📌目标读者:希望在 BLE 模块中实现掉电不丢配置、支持产测参数注入与自动加载功能的开发者 📊文章长度:约 5200 字 🔍 为什么要使用 NVS? 在实际产品中,我们经常面临以下场景: 用户或…...

【Android】Android Studio项目代码异常错乱问题处理(2020.3版本)
问题 项目打开之后,发现项目文件直接乱码, 这样子的 这本来是个Java文件,结果一打开变成了这种情况,跟见鬼一样,而且还不是这一个文件这样,基本上一个项目里面一大半都是这样的问题。 处理方法 此时遇到…...
n皇后问题的 C++ 回溯算法教学攻略
一、问题描述 n皇后问题是经典的回溯算法问题。给定一个 nn 的棋盘,要求在棋盘上放置 n 个皇后,使得任何两个皇后之间不能互相攻击。皇后可以攻击同一行、同一列以及同一对角线上的棋子。我们需要找出所有的合法放置方案并输出方案数。 二、输入输出形…...

一些免费的大A数据接口库
文章目录 一、Python开源库(适合开发者)1. AkShare2. Tushare3. Baostock 二、公开API接口(适合快速调用)1. 新浪财经API2. 腾讯证券接口3. 雅虎财经API 三、第三方数据平台(含免费额度)1. 必盈数据2. 聚合…...
DeepSeek本地部署及WebUI可视化教程
前言 DeepSeek是近年来备受关注的大模型之一,支持多种推理和微调场景。很多开发者希望在本地部署DeepSeek模型,并通过WebUI进行可视化交互。本文将详细介绍如何在本地环境下部署DeepSeek,并实现WebUI可视化,包括Ollama和CherryStudio的使用方法。 一、环境准备 1. 硬件要…...