关于springcloud:SpringCloud和SpringBoot的版本依赖该怎么选择

February 27, 2024 · 0 min · jiezi

关于spring-cloud:开源微服务如何选型Spring-CloudDubbogRPCIstio-详细对比

不管您是一名开发者、架构师、CTO, 如果您曾深度参加在微服务开发中,那么置信您肯定有过开源微服务框架或体系选型的疑难:Apache Dubbo、Spring Cloud、gRPC 以及 Service Mesh 体系产品如 Istio,到底应该选型哪一个?这篇文章对这几个框架进行了具体的阐明,并在选型方面给了肯定的领导意见,置信能给微服务开发者带来肯定的帮忙。 须要留神的是,这篇文章的作者有深度 Apache Dubbo 社区参加教训,因而整篇文章是以 Dubbo 为根底开展的,通过将 Dubbo 与其余组件之间的分割与差别主观、通明的展示进去,来向读者出现几款开源产品的劣势和实用场景。整篇文章中有局部内容突出了 Apache Dubbo 我的项目的劣势,请大家在浏览过程中放弃对这点的意识,但它总体上并不影响咱们从总体上理解每个产品并取得具备价值的选型领导。 Dubbo 与 Spring Cloud 从上图咱们能够看出,Dubbo 和 Spring Cloud 有很多相似之处,它们都在整个架构图的雷同地位并提供一些类似的性能。 Dubbo 和 Spring Cloud 都偏重在对分布式系统中常见问题模式的形象(如服务发现、负载平衡、动静配置等),同时对每一个问题都提供了配套组件实现,造成了一套微服务整体解决方案,让应用 Dubbo 及 Spring Cloud 的用户在开发微服务利用时能够专一在业务逻辑开发上。Dubbo 和 Spring Cloud 都齐全兼容 Spring 体系的利用开发模式,Dubbo 对 Spring 利用开发框架、Spring Boot 微服务框架都做了很好的适配,因为 Spring Cloud 出自 Spring 体系,在这一点上天然更不用多说。尽管两者有很多相似之处,但因为它们在诞生背景与架构设计上的微小差别,两者在性能、实用的微服务集群规模、生产稳定性保障、服务治理等方面都有很大差别。 Spring Cloud 的劣势在于: 同样都反对 Spring 开发体系的状况下,Spring Cloud 失去更多的原生反对。对一些罕用的微服务模式做了形象如服务发现、动静配置、异步音讯等,同时包含一些批处理工作、定时工作、长久化数据拜访等畛域也有涉猎。基于 HTTP+JSON 的通信模式,对于开发、测试、上下游体系接入等更敌对,老本更低。Spring Cloud 官网具备绝对欠缺的入门文档和演示 demo 和 starters,包含书籍材料等,让开发者上更易于上手。Spring Cloud 的问题有: ...

August 28, 2023 · 2 min · jiezi

关于spring-cloud:Spring-Cloud-如何引入云原生网关创新微服务架构

在传统的微服务体系中,Spring Cloud Alibaba 和 Zuul 常被用作配合 Spring Cloud 应用的微服务网关。然而,这些传统的 Java 网关在面对大规模流量的场景下仍存在种种问题。例如 Zuul 因为采纳了非异步 IO 的架构,导致了其在面对高流量的状况下容易呈现阻塞的景象,Spring Cloud Gateway 也会在流量很大的状况下产生 Full GC 的状况,导致申请 RT 变长,影响用户体验和业务稳定性。因而咱们须要寻找一个新的选项,来代替这些传统的微服务网关。 Higress: Spring Cloud生态下微服务网关的新抉择Higress 是阿里巴巴开源的一款下一代云原生微服务网关。Higress 能够对接多种注册核心,包含Nacos/Zookeeper/Eureka 等,可能无缝集成 Spring Cloud 利用,对 Dubbo/Sentinel/OpenSergo 等微服务生态也有着深度的集成。与此同时,Higress 采纳 C++内核,相比于传统的 Java 网关来说性能更高,更稳固,比照Spring Cloud Gateway 和 Zuul 来说,性能能够晋升至2-4倍。另外,Higress 还人造兼容 K8s 的Ingress/Gateway API 规范,是一款更合乎云原生时代规范的微服务网关。 更多性能压测试验,请参考:https://mp.weixin.qq.com/s/45ZAc5CGfND46Ao3lbHefQHigress无缝对接Spring Cloud利用公布实战在古代软件架构逐步走向微服务化、云原生化的过程中,利用的更新和迭代的频率变得越来越快,如何在尽可能保障用户体验不受影响的状况下实现利用的迭代公布就显得至关重要。目前业界广泛采纳的几种典型的利用公布策略包含蓝绿公布、金丝雀公布、A/B Testing公布等。接下来本文将介绍如何应用Higress来实现Spring Cloud Alibaba利用公布的最佳实际。 前提条件装置Higress,并装置Istio CRD,参考Higress装置部署文档。装置Naocs,参考Nacos装置部署文档。Higress反对将Nacos,Spring Cloud利用部署于K8s集群内,或者独立于K8s进行部署。为了演示不便,本文将Higress,Nacos,Spring Cloud利用都部署在本地K8s集群。 1.通过Higress实现Spring Cloud利用的服务发现和路由1.1. 部署SpringCloudAlibaba利用apiVersion: apps/v1kind: Deploymentmetadata: name: spring-cloud-demo-v1spec: replicas: 1 selector: matchLabels: app: spring-cloud-demo template: metadata: labels: app: spring-cloud-demo spec: containers: - name: server image: higress-registry.cn-hangzhou.cr.aliyuncs.com/samples/spring-cloud-demo:v1 imagePullPolicy: IfNotPresent env: # 注册到的nacos的地址 - name: NACOS_REGISTRY_ADDRESS value: nacos-server.default.svc.cluster.local # 注册时携带的version元信息 - name: SPRING_CLOUD_NACOS_DEMO_VERSION value: v1咱们在k8s集群中部署如上Deployment,其中通过NACOS_REGISTRY_ADDRESS和SPRING_CLOUD_NACOS_DEMO_VERSION两个环境变量指定了Nacos的地址以及注册时携带的version元信息。SpringCloud利用的application.properties配置会读取这两个环境变量,如下所示: ...

July 4, 2023 · 2 min · jiezi

关于spring-cloud:openfeign集成spring-cloud-loadbalancer实现负载均衡流程

当咱们在我的项目中调用本人实现的Feignclient负载平衡中如何起作用?请看下图: 图一 在图一中咱们能够发现,在ConsumerController中调用自定义的DemoFeignClient办法时,通过spring容器中对DemoFeignclient的代理类的调用最终通过feign.SynchronousMethodHandler.invoke()->openfeign.loadbalancer.execute()->org.springframework.cloud.loadbalancer.blocking.client.FeignBlockingLoadBalancerClient.choose()->org.springframework.cloud.loadbalancer.core.RoundRobinLoadBalancer.choose()这样的调用链,最终执行spring cloud loadbalaner中的轮询负载均横策略! 然而,上图中的这些要害类是如何组合起来发挥作用呢?请咱们一起持续剖析!spring cloud我的项目启动后,spring容器解析并加载LoadBalancerClientConfiguration.java配置文件(如下图所示)图二 而后将"reactorServiceInstanceLoadBalancer"注册到beanDefinitionMap中。而后会扫描咱们申明的controller,因为conroller中注入了DemoFeignClient,因而spring容器会递归创立DemoFeignClient,创立DemoFiegnClient过程中会通过AbstractAutowireCapableBeanFactory.obtainFromSupplier()注入instanceSupplier实例,也就是FeignClientFactoryBean实例! 上面是org.springframework.cloud.openfeign.FeignClientsRegistrar.registerFeignClient()办法次要逻辑: private void registerFeignClient(BeanDefinitionRegistry registry, AnnotationMetadata annotationMetadata, Map<String, Object> attributes) { //疏忽非核心代码片段 BeanDefinitionBuilder definition = BeanDefinitionBuilder.genericBeanDefinition(clazz, () -> { //设置url factoryBean.setUrl(getUrl(beanFactory, attributes)); //设置门路 factoryBean.setPath(getPath(beanFactory, attributes)); //decode404 布尔值 factoryBean.setDecode404(Boolean.parseBoolean(String.valueOf(attributes.get("decode404")))); Object fallback = attributes.get("fallback"); //设置fallback if (fallback != null) { factoryBean.setFallback(fallback instanceof Class ? (Class<?>) fallback : ClassUtils.resolveClassName(fallback.toString(), null)); } //设置fallback工厂类 Object fallbackFactory = attributes.get("fallbackFactory"); if (fallbackFactory != null) { factoryBean.setFallbackFactory(fallbackFactory instanceof Class ? (Class<?>) fallbackFactory : ClassUtils.resolveClassName(fallbackFactory.toString(), null)); } //实例化咱们申明的DemoClient return factoryBean.getObject(); });}这还没有完,org.springframework.cloud.openfeign.FeignClientFactoryBean.getObject()中最终执行loadBalance();在loadBalance()中实例化FeignInvocationHandler; ...

July 4, 2023 · 1 min · jiezi

关于spring-cloud:Spring依赖可视化分析与微服务模块划分

前言19年的时候,次要负责微服务治理平台BOMS交付工作,期间客户提到在微服务模块拆分方面须要征询。 过后我还只是技术负责人,没有深刻理解这方面的需要,只是网上找了点材料发给客户,再联合资料简略讲一下“正交合成”等准则。 起初据说客户找到埃森哲做培训,每天的培训费用大略是好几千,前面领导打算让我当架构师,惋惜我回绝了,当初想想十分惋惜,但我并不是想做培训老师, 而是想能不能制作一款可视化的剖析工具,给微服务模块拆分提供可量化的拆分根据,以及评估拆分前后的性能指标变动。 Spring依赖剖析我首先想到基于代码扫描的动态剖析,得益于 Spring 的架构劣势,做起来并不难,只须要把 Spring IoC 容器保留的 Bean 信息导出来即可,而正好 Spring Boot Actuator 模块刚好提供 /beans 接口用于导出Bean信息,Bean信息结构大略如下: {    "contexts": {        "school-service": {            "beans": {                "spring.jpa-org.springframework.boot.autoconfigure.orm.jpa.JpaProperties": {                    "aliases": [],                    "scope": "singleton",                    "type": "org.springframework.boot.autoconfigure.orm.jpa.JpaProperties",                    "resource": null,                    "dependencies": []                } } } }}对于没有应用 Spring Boot 的老旧我的项目,以下就是参考 Actuator 源码实现的代替实现: ...

June 8, 2023 · 4 min · jiezi

关于spring-cloud:2022升级版Spring-Cloud-进阶-Alibaba-微服务体系自媒体实战

download:2022升级版Spring Cloud 进阶 Alibaba 微服务体系自媒体实战Spring Cloud 进阶 Alibaba:微服务架构下的可靠性、性能与平安作为以后风行的微服务框架之一,Spring Cloud 在构建分布式系统方面施展着重要作用。随着企业数字化转型以及云计算技术的一直遍及,越来越多的企业开始关注微服务架构在实现业务翻新、进步 IT 效率、保障数据安全等方面带来的劣势。 而在泛滥的微服务解决方案中,基于阿里巴巴开源技术的 Spring Cloud Alibaba 也越来越受到企业的关注和青眼。本文将介绍 Spring Cloud Alibaba 的特点和劣势,并从可靠性、性能和平安三个方面论述如何进一步晋升 Spring Cloud 在微服务架构下的价值。 一、Spring Cloud Alibaba 简介Spring Cloud Alibaba 是由 Spring Cloud 和阿里巴巴联合推出的微服务整体解决方案。它利用 Spring Cloud 生态圈中最罕用的组件和利用程序库,联合阿里巴巴的优良开源产品,帮忙企业疾速搭建分布式应用程序。 Spring Cloud Alibaba 包含了 Spring Cloud Alibaba 微服务框架和 Spring Cloud Alibaba 生态系列产品两局部。其中微服务框架包含 Spring Cloud Alibaba 的外围组件,例如 Nacos 注册核心、Sentinel 服务降级与熔断、Seata 分布式事务等;而生态系列产品则包含 Alibaba Cloud SDK、Logistics 算法库等。 相较于其余微服务框架,Spring Cloud Alibaba 具备以下劣势: 兼容 Spring 生态圈: Spring Cloud Alibaba 基于 Spring Cloud 实现,兼容 Spring Boot 和 Spring Cloud 的所有性能和个性。集成开箱即用: Spring Cloud Alibaba 整合了多个阿里巴巴自主研发的优良产品,如 Nacos、Sentinel、RocketMQ 等,提供了高效便捷的解决方案。轻量级高性能: Spring Cloud Alibaba 各个组件都是基于轻量化的应用程序构建,同时具备杰出的性能和可靠性。二、可靠性晋升在大型分布式系统中,各个服务之间会存在许多不可避免的故障和问题。因而,在微服务架构下实现高可靠性是十分必要的。Spring Cloud Alibaba 提供了多种工具和机制,帮忙企业实现微服务架构下的可靠性。 ...

June 2, 2023 · 1 min · jiezi

关于springcloud:SpringCloud整合Dubbo3实战高并发下的微服务架构设计到乡翻似烂柯人

download:SpringCloud整合Dubbo3实战高并发下的微服务架构设计Spring Cloud整合 Part 1: 服务注册与发现Spring Cloud提供了一套残缺的微服务解决方案,其中包含服务注册与发现、负载平衡、断路器等。本文将介绍如何应用Spring Cloud进行服务注册与发现。 服务注册在应用Spring Cloud进行服务注册之前,咱们须要首先定义一个简略的服务。以下是一个示例: java@RestController@RequestMapping("/hello")public class HelloController { @GetMapping("/{name}")public String hello(@PathVariable String name) { return "Hello, " + name;}}上述代码定义了一个名为“hello”的REST服务,并承受一个名为“name”的门路参数。这个服务返回一个字符串,蕴含了“Hello, ”和门路参数的值。 为了将这个服务注册到Spring Cloud中,咱们须要在服务的pom.xml文件中增加以下依赖项: xml<dependency> <groupId>org.springframework.cloud</groupId><artifactId>spring-cloud-starter-netflix-eureka-client</artifactId></dependency>接下来,在应用程序的application.properties或application.yml文件中,咱们须要配置Eureka服务器的地位: eureka.client.service-url.default-zone=http://localhost:8761/eureka/最初,在服务类上增加@EnableDiscoveryClient正文,以启用服务注册性能: java@SpringBootApplication@EnableDiscoveryClientpublic class HelloServiceApplication { public static void main(String[] args) { SpringApplication.run(HelloServiceApplication.class, args);}}服务发现在服务注册实现后,咱们能够应用Spring Cloud的服务发现性能来查找可用的服务。以下是一个示例: java@RestController@RequestMapping("/client")public class ClientController { @Autowiredprivate RestTemplate restTemplate;@GetMapping("/{name}")public String hello(@PathVariable String name) { String serviceUrl = "http://hello-service/hello/" + name; return restTemplate.getForObject(serviceUrl, String.class);}}上述代码定义了一个名为“client”的REST服务,并承受一个名为“name”的门路参数。这个服务应用RestTemplate类来调用名为“hello”的服务。 在应用程序的application.properties或application.yml文件中,咱们须要配置RestTemplate类: spring.cloud.loadbalancer.ribbon.enabled=false最初,在主类上增加@LoadBalanced正文,以启用客户端负载平衡: java@SpringBootApplication@EnableDiscoveryClientpublic class ClientServiceApplication { @Bean@LoadBalancedpublic RestTemplate restTemplate() { return new RestTemplate();}public static void main(String[] args) { SpringApplication.run(ClientServiceApplication.class, args);}}总结Spring Cloud提供了一套残缺的微服务解决方案,其中包含服务注册与发现、负载平衡、断路器等。通过本文的介绍,你曾经学会了如何应用Spring Cloud进行服务注册与发现。 ...

May 28, 2023 · 1 min · jiezi

关于springcloud:SpringCloudalibabaVue开发仿社交小程序完结春风送暖入屠苏

SpringCloudalibaba+Vue开发仿社交小程序download:3w zxit666 com应用Vue开发仿社交小程序在当今的互联网时代,社交网络变得越来越遍及。人们应用社交媒体与别人分享信息、交换、建立联系等。为此,许多公司和集体都在开发社交应用程序,以满足用户的需要。 本文将介绍如何应用Vue框架来开发仿社交小程序。Vue是一个风行的JavaScript框架,它提供了一套简略易用的工具来开发Web应用程序。咱们将应用Vue来搭建前端界面,并应用云开发平台来实现后端服务。 步骤1:设置开发环境首先,您须要装置Node.js和Vue CLI。这两个工具是应用Vue进行开发的必需品。您能够通过以下命令来查看您是否曾经装置了Node.js: node -v如果您曾经装置了Node.js,您应该会看到相似于"v10.15.0"的版本号。接下来,您须要装置Vue CLI。您能够通过以下命令来装置Vue CLI: npm install -g @vue/cli步骤2:创立Vue我的项目一旦您实现了设置开发环境的步骤,接下来就是创立Vue我的项目。您能够应用Vue CLI来创立我的项目。执行以下命令: vue create my-project这将启动一个交互式命令行提醒。您能够按Enter键承受默认选项,或依据须要进行自定义设置。 步骤3:应用微信小程序开发者工具创立小程序在Vue我的项目创立实现后,您须要应用微信小程序开发者工具来创立小程序。在开发者工具中,抉择“新建小程序”,并填写相应的信息,例如小程序名称、AppID等。 步骤4:创立小程序页面一旦您创立了小程序,接下来就是创立小程序页面。在Vue我的项目的src文件夹中,创立一个名为“pages”的文件夹,并在该文件夹中创立您的小程序页面。 例如,假如您想创立一个名为“index”的页面。您能够在“pages”文件夹中创立一个名为“index.vue”的文件,并将以下代码增加到该文件中: html<template> <div> <h1>{{ title }}</h1><p>{{ message }}</p></div></template> <script>export default { data() { return { title: 'Welcome to my social app!', message: 'This is my first Vue.js social app.'}}}</script>步骤5:将Vue组件转换成小程序组件一旦您创立了小程序页面,接下来就是将Vue组件转换成小程序组件。您能够应用“mpvue-loader”插件来实现这一点。执行以下命令来装置该插件: npm install mpvue-loader --save-dev接下来,在Vue我的项目的build文件夹中创立一个名为“webpack.base.conf.js”的文件,并将以下代码增加到该文件中: javascriptconst MpvueLoaderPlugin = require('mpvue-loader/lib/plugin') module.exports = { // ... plugins: [ new MpvueLoaderPlugin()]}步骤6:构建小程序一旦您实现了以上步骤,接下来就是构建小程序。应用以下命令来构建小程序: npm run build:mp-weixin这将在dist目录中生成小程序代码。而后,您能够应用微信小程序开发者工具关上该目录并预览小程序。 至此,您曾经胜利地应用Vue框架开发了一个仿社交小程序。祝您开发欢快!

May 27, 2023 · 1 min · jiezi

关于spring-cloud:SpringCloudalibabaVue开发仿社交小程序谪居卧病浔阳城

download:SpringCloudalibaba+Vue开发仿社交小程序莫辞更坐弹一曲音乐,古琴,传统文化莫辞更是中国现代文人雅士中的代表人物之一,他是一位喜好古琴的文艺青年。据史料记录,莫辞更经常在宴会上弹奏古琴,给人们带来美好的音乐享受。其中最有名的就要数他“更坐弹一曲”的故事了。 相传有一次,莫辞更加入了一个宴会,过后的氛围非常热烈,人们喝着酒、谈着天。突然间,有人向莫辞更提出了一个挑战:“你能一边弹古琴,一边吟诗吗?”莫辞更并不慌乱,他微笑着承受了这个挑战,而后开始演奏起古琴来。他的指尖轻捷地拨动着琴弦,音乐随之流淌而出,像一朵绽开的花,漂亮而动人。同时,他还口吟着本人创作的诗歌,将音乐与诗意完满联合在一起。 这一幕场景,让在场的众人为之倾倒。他们惊叹于莫辞更的琴艺、诗才和气派,也由衷地感触到了中国传统文化的博大精深。 莫辞更“更坐弹一曲”的故事,至今仍被前人传颂不衰。这个故事通知咱们,艺术能够逾越时空的界线,它是人类智慧和理性的结晶。古琴作为中国传统音乐的代表,有着博大精深的历史渊源和独特的韵味,而莫辞更则将其演奏得酣畅淋漓,彰显出了中国文化的魅力与底蕴。 在当今社会,咱们应该更加关注和弘扬传统文化,让这些古老而神秘的艺术模式在古代焕发新的光辉。同时,咱们也要向莫辞更这样的前辈学习,用本人的才华和致力去发明属于本人的经典,为传统文化的倒退奉献本人的力量。

May 14, 2023 · 1 min · jiezi

关于spring-cloud:2022升级版Spring-Cloud-进阶-Alibaba-微服务体系自媒体实战风月即勋名

download:2022升级版Spring Cloud 进阶 Alibaba 微服务体系自媒体实战WEB前端技术:从HTML、CSS到JavaScript的全面介绍随着互联网的遍及和倒退,WEB前端技术也变得越来越重要。本文将全面介绍WEB前端技术,包含HTML、CSS和JavaScript三方面的内容。 HTMLHTML(Hypertext Markup Language)是一种用于创立网页的标记语言。它通过各种标签和属性来形容网页上的内容和构造。HTML标签通常由尖括号突围,例如<html>、<head>、<body>等。HTML还反对链接、图片、表格、表单等性能,这些都是通过不同的标签和属性实现的。 CSSCSS(Cascading Style Sheets)是一种用于管制网页外观的样式表语言。它能够扭转文本的色彩、字体、大小,设置页面布局和款式等。CSS通过层叠规定来确定利用哪个款式,同时也反对选择器来抉择元素并为其利用款式。CSS还反对动画和转换等高级成果,能够让网页更加丰富多彩。 JavaScriptJavaScript是一种广泛应用于WEB前端开发的编程语言,它能够在网页中增加动态效果、交互行为、数据验证和操作等。JavaScript能够通过DOM(Document Object Model)和BOM(Browser Object Model)来拜访和管制网页元素。它还能够通过AJAX(Asynchronous JavaScript and XML)技术实现异步数据交互,使网页更加晦涩和疾速。 总之,WEB前端技术是创立网页和应用程序的关键所在。HTML、CSS和JavaScript三者相辅相成,独特构建了一个残缺的网页。通过学习WEB前端技术,开发者能够创立出高质量、高性能的网站和应用程序。

May 11, 2023 · 1 min · jiezi

关于springcloud:SpringCloud整合Dubbo3实战高并发下的微服务架构设计品画先神韵论诗重性情

download:SpringCloud整合Dubbo3实战高并发下的微服务架构设计Go是一种由Google开发的开源编程语言,它重视简洁、高效、并发和安全性。在本文中,咱们将深入探讨Go语言的一些基本知识和利用。 1.根本语法 Go语言的根本语法相似于C语言,具备一些非凡的关键字和语法结构。例如,以下是一个简略的Go程序: goCopy codepackage main import "fmt" func main() { fmt.Println("Hello, World!") }在这个例子中,package关键字指定程序所属的包,import关键字用于导入其余包中的代码。main函数是程序的入口点,fmt.Println用于将一条音讯输入到规范输入。 2.并发编程 Go语言在语言级别提供了并发编程的反对,它的并发模型基于轻量级的线程(goroutine)和通道(channel)。例如,以下是一个简略的并发程序: goCopy codepackage main import ( "fmt" "time" ) func worker(done chan bool) { fmt.Print("working...") time.Sleep(time.Second) fmt.Println("done") done <- true } func main() { done := make(chan bool, 1) go worker(done) <-done }在这个例子中,worker函数是一个在goroutine中运行的并发工作单元,它会期待一秒钟后实现工作并将一个布尔值发送到通道中。main函数启动了一个goroutine来运行worker函数,并期待通道中的布尔值。 3.内存治理 Go语言在内存治理方面具备主动垃圾回收的性能,能够帮忙开发人员防止常见的内存透露和野指针问题。例如,以下是一个简略的应用切片的程序: goCopy codepackage main import "fmt" func main() { s := make([]int, 0) for i := 0; i < 10; i++ { s = append(s, i) } fmt.Println(s) }在这个例子中,make函数用于创立一个长度为0的整数切片。append函数用于向切片中增加元素,它会主动调整切片的大小和容量。 ...

April 10, 2023 · 1 min · jiezi

关于springcloud:SpringCloud整合Dubbo3实战高并发下的微服务架构设计汀上白沙看不见

download:SpringCloud整合Dubbo3实战高并发下的微服务架构设计首先必定前后端采纳MQTT进行通信,别问我为什么,因为他简略,不需要做太多的处理。既然是简略的ERP,练手用的,就不讲究那么多的技术打算了。 1、如果有人员治理模块,那么避免不了需要上传图片。那么图片如何保存呢? 原本想在数据库中保存图片路径,而后通过MQTT上传图片文件。那么客户端浮现咱们办,总不能下载到本地在浮现吧。。。 其实有解决办法,就是走流模式,那么有要走socket通信。 麻烦。。。 解决打算仍旧采纳MQTT协定: 1)先将图片转为 Byte[]数组 2)诚然MQTT传输时使用的也是 Byte数据,然而图片间接转换的Byte数组无奈间接使用;需要转换一下。 3)将图片的Byte数组转为 Base64的字符串,再将字符串转为转为utf8 的byte数组才可能使用。

April 7, 2023 · 1 min · jiezi

关于spring-cloud:Spring-Cloud-Alibaba-应用如何平滑迁移至-IPv6

背景IPv4 协定(后文简称 IPv4)为互联网的倒退与遍及做出了重要奉献,但近年来,随着应用程序、数据和 IT 服务的爆炸式增长。当初协定设计过程中用来形容 IP 地址所采纳的 32 位二进制数格局的 IPv4 地址曾经于 2011 年[1]被申请耗尽,从那时起,全世界都曾经处于无新地址可用的场面。 IPv6 协定(后文简称 IPv6)作为 IPv4 之后被采纳的下一代互联网协议,相比 IPv4 协定中采纳 32 位来示意 IP 地址,其地址示意位数裁减到了 128 位,地址数量是 IPv4 所能提供的 2 的 96 次方倍。简略看数字可能显得不太直观,换成一句形容 IPv6 地址之多更直观和经典的话:“采纳 128 位示意地址的 IPv6 能够为地球上的每一粒沙子都调配一个 IP 地址”!此外,IPv6 协定其不仅能够解决 IPv4 协定中的地址短缺问题,同时也能为互联网提供更高效、更平安的网络通信。IPv6 协定在网络通信中提供了许多新的性能和劣势。例如,在数据传输和路由方面,其通过新的设计进步了效率和可靠性,缩小了网络拥挤和数据包失落的状况。此外,在平安畛域,其内置对 IPSec 的反对,能够更好地爱护网络中的数据传输平安,避免黑客攻击和窃取数据。 作为下一代互联网协议,向 IPv6 迁徙是将来的大势所趋。在我国,从 2014 年开始相干机构曾经逐渐进行向新用户和利用调配 IPv4 地址,开始全面商用 IPv6 协定[2]。在政府疏导测,近年来,陆续也出台了一系列相干领导文件例如:2017 年国务院公布的《推动互联网协议第六版(IPv6)规模部署行动计划》[3]、2021 年工业与信息化部公布的《IPv6 流量晋升三年专项行动计划(2021-2023 年)》[4]、2021 年网信办公布的《对于推动 IPv6 规模部署的领导意见》[5]等一直地在疏导企业从 IPv4 协定向 IPv6 协定迁徙。 但因为以后互联网中 IPv4 协定的利用规模十分大,对于用户来说,没方法通过规定一个工夫日期,从那一刻开始,所有互联网上的设施全副应用 IPv6,这是不事实的。一次性迁徙不仅在基础设施层面不可行,对企业用户来说,就算基础设施都能筹备结束,让其将少则上百,多则成千上万的利用实例在一段时间内一次性停机进行协定栈迁徙,无论是在危险上,还是老本上,对企业用户来说都是难以承受的!既然无奈一步到位,渐进式的 IP 地址迁徙成为以后的支流抉择。接下来本文将介绍一些支流渐进式的 IP 地址迁徙办法。 ...

March 27, 2023 · 2 min · jiezi

关于springcloud:三天吃透Spring-Cloud面试八股文

本文曾经收录到Github仓库,该仓库蕴含计算机根底、Java根底、多线程、JVM、数据库、Redis、Spring、Mybatis、SpringMVC、SpringBoot、分布式、微服务、设计模式、架构、校招社招分享等外围知识点,欢送star~ Github地址:https://github.com/Tyson0314/Java-learning 1、什么是Spring Cloud ?Spring cloud 流应用程序启动器是基于 Spring Boot 的 Spring 集成应用程序,提供与内部零碎的集成。Spring cloud Task,一个生命周期短暂的微服务框架,用于疾速构建执行无限数据处理的应用程序。 2、什么是微服务?微服务架构是一种架构模式或者说是一种架构格调,它提倡将繁多应用程序划分为一组小的服务,每个服务运行在其独立的本人的过程中,服务之间互相协调、互相配合,为用户提供最终价值。服务之间采纳轻量级的通信机制相互沟通(通常是基于HTTP的RESTful API),每个服务都围绕着具体的业务进行构建,并且可能被独立的构建在生产环境、类生产环境等。另外,应防止对立的、集中式的服务管理机制,对具体的一个服务而言,应依据业务上下文,抉择适合的语言、工具对其进行构建,能够有一个十分轻量级的集中式治理来协调这些服务,能够应用不同的语言来编写服务,也能够应用不同的数据存储。 艰深地来讲: 微服务就是一个独立的职责繁多的服务应用程序。在 intellij idea 工具外面就是用maven开发的一个个独立的module,具体就是应用springboot 开发的一个小的模块,解决繁多业余的业务逻辑,一个模块只做一个事件。 微服务强调的是服务大小,关注的是某一个点,具体解决某一个问题/落地对应的一个服务利用,能够看做是idea 外面一个 module。 3、Spring Cloud有什么劣势应用 Spring Boot 开发散布式微服务时,咱们面临以下问题 与分布式系统相干的复杂性-这种开销包含网络问题,提早开销,带宽问题,平安问题。服务发现-服务发现工具治理群集中的流程和服务如何查找和相互交谈。它波及一个服务目录,在该目录中注册服务,而后可能查找并连贯到该目录中的服务。冗余-分布式系统中的冗余问题。负载平衡 --负载平衡改善跨多个计算资源的工作负荷,诸如计算机,计算机集群,网络链路,地方处理单元,或磁盘驱动器的散布。性能-问题 因为各种经营开销导致的性能问题。部署复杂性-Devops 技能的要求。4、微服务之间如何独立通信的?同步通信:dobbo通过 RPC 近程过程调用、springcloud通过 REST 接口json调用等。 异步:音讯队列,如:RabbitMq、ActiveM、Kafka等音讯队列。 5、 什么是服务熔断?什么是服务降级?熔断机制是应答雪崩效应的一种微服务链路爱护机制。当某个微服务不可用或者响应工夫太长时,会进行服务降级,进而熔断该节点微服务的调用,疾速返回“谬误”的响应信息。当检测到该节点微服务调用响应失常后复原调用链路。在Spring Cloud框架里熔断机制通过Hystrix实现,Hystrix会监控微服务间调用的情况,当失败的调用到肯定阈值,缺省是5秒内调用20次,如果失败,就会启动熔断机制。 服务降级,个别是从整体负荷思考。就是当某个服务熔断之后,服务器将不再被调用,此时客户端能够本人筹备一个本地的fallback回调,返回一个缺省值。这样做,尽管程度降落,但好歹可用,比间接挂掉强。 Hystrix相干注解@EnableHystrix:开启熔断 @HystrixCommand(fallbackMethod=”XXX”),申明一个失败回滚处理函数XXX,当被注解的办法执行超时(默认是1000毫秒),就会执行fallback函数,返回谬误提醒。 6、 请说说Eureka和zookeeper 的区别?Zookeeper保障了CP,Eureka保障了AP。 A:高可用 C:一致性 P:分区容错性 1.当向注册核心查问服务列表时,咱们能够容忍注册核心返回的是几分钟以前的信息,但不能容忍间接down掉不可用。也就是说,服务注册性能对高可用性要求比拟高,但zk会呈现这样一种状况,当master节点因为网络故障与其余节点失去分割时,残余节点会从新选leader。问题在于,选取leader工夫过长,30 ~ 120s,且选取期间zk集群都不可用,这样就会导致选取期间注册服务瘫痪。在云部署的环境下,因网络问题使得zk集群失去master节点是较大概率会产生的事,尽管服务可能复原,然而漫长的选取工夫导致的注册长期不可用是不能容忍的。 2.Eureka保障了可用性,Eureka各个节点是平等的,几个节点挂掉不会影响失常节点的工作,残余的节点依然能够提供注册和查问服务。而Eureka的客户端向某个Eureka注册或发现时产生连贯失败,则会主动切换到其余节点,只有有一台Eureka还在,就能保障注册服务可用,只是查到的信息可能不是最新的。除此之外,Eureka还有自我爱护机制,如果在15分钟内超过85%的节点没有失常的心跳,那么Eureka就认为客户端与注册核心产生了网络故障,此时会呈现以下几种状况: ①、Eureka不在从注册列表中移除因为长时间没有收到心跳而应该过期的服务。 ②、Eureka依然可能承受新服务的注册和查问申请,然而不会被同步到其余节点上(即保障以后节点依然可用) ③、当网络稳固时,以后实例新的注册信息会被同步到其余节点。 因而,Eureka能够很好地应答因网络故障导致局部节点失去分割的状况,而不会像Zookeeper那样使整个微服务瘫痪 7、SpringBoot和SpringCloud的区别?SpringBoot专一于疾速不便得开发单个个体微服务。 SpringCloud是关注全局的微服务协调整顿治理框架,它将SpringBoot开发的一个个单体微服务整合并治理起来, 为各个微服务之间提供,配置管理、服务发现、断路器、路由、微代理、事件总线、全局锁、决策竞选、分布式会话等等集成服务 SpringBoot能够来到SpringCloud独立应用开发我的项目, 然而SpringCloud离不开SpringBoot ,属于依赖的关系. SpringBoot专一于疾速、不便得开发单个微服务个体,SpringCloud关注全局的服务治理框架。 8、负载平衡的意义什么?在计算中,负载平衡能够改善跨计算机,计算机集群,网络链接,地方处理单元或磁盘驱动器等多种计算资源的工作负载散布。负载平衡旨在优化资源应用,最大化吞吐量,最小化响应工夫并防止任何繁多资源 的过载。应用多个组件进行负载平衡而不是单个组件可能会通过冗余来进步可靠性和可用性。负载平衡通常波及专用软件或硬件,例如多层交换机或域名零碎服务器过程。 9、什么是Hystrix?它如何实现容错?Hystrix是一个提早和容错库,旨在隔离近程零碎,服务和第三方库的拜访点,当呈现故障是不可避免的故障时,进行级联故障并在简单的分布式系统中实现弹性。 ...

March 18, 2023 · 1 min · jiezi

关于springcloud:Gateway集成Netty服务

Gateway和Netty都有盲区的感觉;一、Netty简介Netty是一个异步的,事件驱动的网络应用框架,用以疾速开发高牢靠、高性能的网络应用程序。 传输服务:提供网络传输能力的治理; 协定反对:反对常见的数据传输协定; 外围模块:包含可扩大事件模型、通用的通信API、零拷贝字节缓冲; 二、Netty入门案例1、服务端启动配置Netty服务器端程序,疏导相干外围组件的加载; public class NettyServer { public static void main(String[] args) { // EventLoop组,处理事件和IO EventLoopGroup parentGroup = new NioEventLoopGroup(); EventLoopGroup childGroup = new NioEventLoopGroup(); try { // 服务端启动疏导类 ServerBootstrap serverBootstrap = new ServerBootstrap(); serverBootstrap.group(parentGroup, childGroup) .channel(NioServerSocketChannel.class).childHandler(new ChannelInit()); // 异步IO的后果 ChannelFuture channelFuture = serverBootstrap.bind(8082).sync(); channelFuture.channel().closeFuture().sync(); } catch (Exception e){ e.printStackTrace(); } finally { parentGroup.shutdownGracefully(); childGroup.shutdownGracefully(); } }}2、通道初始化ChannelInitializer非凡的通道处理器,提供一种简略的办法,对注册到EventLoop的通道进行初始化;比方此处设置的编码解码器,自定义处理器; public class ChannelInit extends ChannelInitializer<SocketChannel> { @Override protected void initChannel(SocketChannel socketChannel) { // 获取管道 ChannelPipeline pipeline = socketChannel.pipeline(); // Http编码、解码器 pipeline.addLast("DefHttpServerCodec",new HttpServerCodec()); // 增加自定义的handler pipeline.addLast("DefHttpHandler", new DefHandler()); }}3、自定义处理器解决对服务器端发动的拜访,通常包含申请解析,具体的逻辑执行,申请响应等过程; ...

February 28, 2023 · 3 min · jiezi

关于spring-cloud:Spring-Cloud-Alibaba-在-Proxyless-Mesh-上的探索

站在 2023 年的明天,Service Mesh 早已不是一个新兴的概念, 回顾过去 6 年多的倒退历程,Service Mesh 从一经推出就受到来自全世界的支流技术公司关注和追捧。 2016 年作为 Service Mesh 的元年,Buoyant 公司 CEO William Morgan 率先公布 Linkerd[1] ,成为业界首个 Service Mesh 我的项目,同年 Lyft 公布Envoy[2] ,成为第二个 Service Mesh 我的项目。2017年,Google、IBM、Lyft 联手公布了 Istio[3],它与 Linkerd / Envoy 等我的项目相比,它首次给大家减少了管制立体的概念,提供了弱小的流量控制能力。通过多年的倒退 Istio,曾经逐渐成为服务网格畛域管制立体的事实标准。2018年7月,Istio 1.0版本公布[4],标记着其进入了能够生产可用的时代,逐步也有越来越多的企业开始思考和尝试将服务网格利用于生产中。Istio 作为以后最风行的开源服务网格技术,它由管制立体和数据立体两局部形成。 在 Istio Mesh 架构中,其管制立体是一个名为 Istiod 的过程,网络代理是 Envoy 。Istiod 作为管制面的对立组件,负责对接服务注册发现、路由规定治理、证书治理等能力,Envoy 则是作为数据面通过 Sidecar 形式代理业务流量,Istio 和 Envoy 之间通过 xDS 协定接口实现服务发现、路由规定等数据的传递。Istiod 通过监听 K8s 资源例如 Service、Endpoint 等,获取服务信息,并将这些资源对立通过 xDS 协定下发给位于数据立体的网络代理。Envoy 则是独立于利用之外的一个过程,以 Sidecar 的形式(个别是以 Container 形式)随同业务利用 Pod 运行,它与利用过程共用同一个主机网络,通过批改路由表的形式劫持业务利用的网络流量从而达到为利用无侵入地提供如服务鉴权、标签路由等能力。 Proxyless MeshProxyless Mesh 全称是 Proxyless Service Mesh,其是近几年在 Service Mesh 根底上倒退而来的一种新型软件架构。Service Mesh 现实很饱满,但事实很骨感!通过一层代理尽管做到了对利用无侵入,但减少的网络代理开销对很多性能要求很高的互联网业务落地造成不少挑战。因而 Proxyless Mesh 作为一种在传统侵入式微服务框架与 Service Mesh 之间的折中计划,通过取众家之所长,为大量的非 Service Mesh 利用在云原生时代,拥抱云原生基础设施,解决流量治理等痛点提供了一种无效的解决方案。Service Mesh 和 Proxyless Mesh 架构区别如下图所示: ...

February 7, 2023 · 5 min · jiezi

关于springcloud:为什么我们的微服务中需要网关

玩过微服务的小伙伴对 Spring Cloud 中的的 Spring Cloud Gateway 多多少少都有一些理解,松哥之前既写过相干的文章,也录过相干的视频跟小伙伴们介绍 Spring Cloud Gateway,不过在之前的介绍中,我可能更加侧重于跟小伙伴们介绍 Spring Cloud Gateway 的用法,对于咱们在微服务中为什么要应用 Spring Cloud Gateway 可能没有和大家仔细分析过,最近年前无暇,咱们来一起探讨一下这个话题。 说起 Spring Cloud Gateway 的应用场景,我置信很多小伙伴都可能脱口而出认证二字,的确,在网关中实现认证操作,的确是 Gateway 的重要应用场景之一,然而并不是惟一的应用场景。在微服务中应用网关的益处可太多了,明天咱们就来逐个剖析一下。 1. 申请路由首先,Gateway 的第一个重要特点就是对申请进行路由,依据不同的申请头、申请参数、申请门路等,将申请路由到不同的服务上。 从这个角度来说,Spring Cloud Gateway 所表演的角色与 Nginx 这一类的反向代理服务器相似,之前就有小伙伴问我,Spring Cloud Gateway 和 Nginx 有啥区别?能不能用 Nginx 代替 Spring Cloud Gateway?其实,你要是单纯的只看申请路由这一个性能,那么的确能够用 Nginx 代替 Spring Cloud Gateway,然而在理论开发中,咱们 Spring Cloud Gateway 所承当的责任可不仅仅是申请路由转发,还有其余方面的性能(后文有介绍),其余的性能用 Nginx 做起来就有一些吃力了。 如果用 Spring Cloud Gateway 做申请路由转发,咱们能够画一张简略的架构图,如下: 2. API 组合网关的另一个作用就是能够实现 API 的组合。当然这个一般来说须要一些代码开发,单纯的配置一般来说是无奈实现需求的。 先来说说没有网关的时候咱们可能会存在什么状况。 以松哥最近在录的 TienChin 我的项目视频为例,我有一个流动治理服务,也就是健身房定期会做一些促销流动,促销流动往往又分为线上或者线下,线上线下又持续细分为不同的渠道,如小红书推广、抖音推广、公众号推广、线下地推等等,所以,假如我当初要做一个批改流动的性能,那么当我选中一条记录,点击批改按钮,此时,客户端至多要发送两条申请: ...

January 12, 2023 · 1 min · jiezi

关于spring-cloud:关于SpringCloudSpringBoot

一、对于SpringCloud、SpringBoot什么是Spring Boot用我的话来了解,Spring Boot就是整合了框架的框架,它让所有依赖都变得有序简略,你不必操心A.jar是什么版本,又依赖哪些版本的jar,它默认配置了很多框架的应用形式,就像 maven整合了所有的jar包,Spring Boot整合了所有的框架,第三方库的性能你拿着就能用。 Spring Boot的核心思想就是约定大于配置,所有由内定的束缚来主动实现。采纳 Spring Boot能够大大的简化你的开发模式,节俭大部分照搬照抄的老本,通过大量的代码就能创立一个独立的,它都有对应的组件反对。 它是由 Pivotal团队提供的全新框架,其设计目标是用来简化新 Spring利用的初始搭建以及开发过程。该框架应用了特定的形式来进行配置,从而使开发人员不再须要定义样板化的配置。 Spring Boot提供了很多”开箱即用“的依赖模块,都是以spring-boot-starter-xx作为命名的。上面列举一些罕用的模块。 spring-boot-starter-logging :应用 Spring Boot 默认的日志框架 Logback。spring-boot-starter-log4j :增加 Log4j 的反对。spring-boot-starter-web :反对 Web 利用开发,蕴含 Tomcat 和 spring-mvc。spring-boot-starter-tomcat :应用 Spring Boot 默认的 Tomcat 作为应用服务器。spring-boot-starter-jetty :应用 Jetty 而不是默认的 Tomcat 作为应用服务器。spring-boot-starter-test :蕴含罕用的测试所需的依赖,如 JUnit、Hamcrest、Mockito 和 spring-test 等。spring-boot-starter-aop :蕴含 spring-aop 和 AspectJ 来反对面向切面编程(AOP)。spring-boot-starter-security :蕴含 spring-security。spring-boot-starter-jdbc :反对应用 JDBC 拜访数据库。spring-boot-starter-redis :反对应用 Redis。spring-boot-starter-data-mongodb :蕴含 spring-data-mongodb 来反对 MongoDB。spring-boot-starter-data-jpa :蕴含 spring-data-jpa、spring-orm 和 Hibernate 来反对 JPA。spring-boot-starter-amqp :通过 spring-rabbit 反对 AMQP。spring-boot-starter-actuator : 增加实用于生产环境的性能,如性能指标和监测等性能。什么是Spring CloudSpring Cloud是一套分布式服务治理的框架,既然它是一套服务治理的框架,那么它自身不会提供具体功能性的操作,更专一于服务之间的通信、熔断、监控等。因而就须要很多的组件来反对一套性能。 ...

November 27, 2022 · 1 min · jiezi

关于springcloud:Spring-Cloud-OpenFeign调用流程

上一节给大家分享了Spring Cloud OpenFeign的启动流程,接下来给大家分享一下调用流程。话不多说,咱们间接开始。 视频:https://www.bilibili.com/video/BV1A84y1C7XD/ 调用流程xxxFeignClient → feign.ReflectiveFeign.FeignInvocationHandler#invoke → feign.InvocationHandlerFactory.MethodHandler#invoke → feign.SynchronousMethodHandler#invoke → feign.SynchronousMethodHandler#executeAndDecode → org.springframework.cloud.openfeign.loadbalancer.FeignBlockingLoadBalancerClient#execute → feign.Client.Default#execute → feign.AsyncResponseHandler#handleResponse 动静代理feign.ReflectiveFeign.FeignInvocationHandler#invoke public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { return dispatch.get(method).invoke(args);}这里说一下 dispatch 属性,它的类型是Map<Method, MethodHandler>意思是,能够通过办法找到对应的Handler,这样就能够进入到 SynchronousMethodHandler#invoke。 feign.SynchronousMethodHandler#executeAndDecode 从这个办法的名称也能看进去,这个是执行申请,并且实现解码的性能,这是一个外围的办法。 负载平衡org.springframework.cloud.openfeign.loadbalancer.FeignBlockingLoadBalancerClient#execute 这个是实现平衡,实现将URL中服务名转成 实在的IP。 上面咱们看看它是如何被主动注入的。 首先在 spring.factories 文件中,做了配置 org.springframework.boot.autoconfigure.EnableAutoConfiguration=\org.springframework.cloud.openfeign.loadbalancer.FeignLoadBalancerAutoConfigurationFeignLoadBalancerAutoConfiguration 中引入 DefaultFeignLoadBalancerConfiguration @ConditionalOnClass(Feign.class)@ConditionalOnBean({ LoadBalancerClient.class, LoadBalancerClientFactory.class })@AutoConfigureBefore(FeignAutoConfiguration.class)@AutoConfigureAfter({ BlockingLoadBalancerClientAutoConfiguration.class, LoadBalancerAutoConfiguration.class })@EnableConfigurationProperties(FeignHttpClientProperties.class)@Configuration(proxyBeanMethods = false)// Order is important here, last should be the default, first should be optional// see// https://github.com/spring-cloud/spring-cloud-netflix/issues/2086#issuecomment-316281653@Import({ HttpClientFeignLoadBalancerConfiguration.class, OkHttpFeignLoadBalancerConfiguration.class, HttpClient5FeignLoadBalancerConfiguration.class, DefaultFeignLoadBalancerConfiguration.class })public class FeignLoadBalancerAutoConfiguration {}new FeignBlockingLoadBalancerClient,并且注入到 Spring Bean 中 ...

November 21, 2022 · 2 min · jiezi

关于springcloud:Spring-Cloud-Alibaba-从入门到精通2023

Alibaba Cloud 简介Spring Cloud Alibaba 即 Alibaba Cloud ,基于 Spring Cloud 构建,同时封装了阿里巴巴的 Nacos、Sentinel 等组件。因为 Netflix 晚期提供的 Eureka、Zuul、Hystrix 等组件早已进行保护,所以倡议间接学习 Alibaba Cloud 全家桶。 学习指标本系列文章波及微服务实战我的项目中所有用到的技术点,学习实现可零碎把握微服务架构设计、微服务体系组件及支流中间件整合等。如下: 把握Alibaba Cloud全家桶服务注册与发现 :ServiceRegistry、DiscoveryClient,Nacos 实现服务注册核心、配置核心负载平衡服务调用 :RestTemplate、OpenFeignGetway :微服务网关,实现路由转发Sentinel :限流、熔断、监控音讯队列 :RocketMQ、RabbitMQ、Kafka(异步音讯订阅、生产,提早音讯)分布式链路追踪 :Zipkin+Sleuth分布式事务 :Seata分布式缓存 :redis 高可用分布式搜索引擎 :ElasticSearch分库分表 :Sharding-JDBC平安认证 :Spring Security + JWT、Oauth 2.0..........次要工具及版本JDK:11数据库:Mysql 8.0.31Spring Cloud Alibaba:2021.0.4.0(更新日期2022年9月)Spring Boot:2.6.11开发工具:idea关注微信公众号:【技术治理修行】分享日常技术干货、技术/治理教训分享,项目经理/产品经理/技术总监 职业规划:

November 7, 2022 · 1 min · jiezi

关于spring-cloud:如何阅读-Spring-Cloud-OpenFein-源码

背景始终以来,应用 Spring Cloud OpenFeign 都是浏览官网文档,尽管也大略晓得其实现原理,但究竟是没有"证据"的。对于 Spring 的源码浏览,自认为是一件非常令人头疼的事件。最近,在学习 Feign 的原生 API,乘此机会,也就浏览一下 Spring Cloud OpenFeign 的源码,并将分享进去,心愿能帮到有须要的人吧。 概述对于 Spring Cloud OpenFeign 源码的博客有很多,然而,不晓得为什么,照着博客,一边读博客,一边读源码,还一边 debug,总是认为还有很多不分明的中央。究其原因,我认为,博客都是依照源码的流程解说,尽管附上了大段代码,可能还是无奈清晰的了解。不晓得你们是不是,反正我是这样的。 指标首先,咱们明确一下明天探索的问题: 咱们晓得,当咱们应用 @FeignClient,是应用了JDK动静代理,那么是如何实现的,那一步创立的代理类。当咱们晓得第一个问题后,咱们就根本分明整个流程了,那么,咱们就能够手写一个繁难的入门测试了。源码启动流程org.springframework.cloud.openfeign.EnableFeignClientsorg.springframework.cloud.openfeign.FeignAutoConfigurationorg.springframework.cloud.openfeign.FeignClientsRegistrarorg.springframework.cloud.openfeign.FeignClientsRegistrar#registerBeanDefinitionsorg.springframework.cloud.openfeign.FeignClientsRegistrar#registerFeignClientorg.springframework.cloud.openfeign.FeignClientFactoryBean#getObjectorg.springframework.cloud.openfeign.Targeterfeign.Feign.Builder#buildfeign.SynchronousMethodHandler.Factoryfeign.ReflectiveFeign.ParseHandlersByNamefeign.ReflectiveFeign#ReflectiveFeignfeign.Feign#newInstancefeign.ReflectiveFeign#newInstancefeign.InvocationHandlerFactory#createfeign.InvocationHandlerFactory.Default#createfeign.ReflectiveFeign.FeignInvocationHandler#FeignInvocationHandler贴上图吧,看看完整版的 注册流程: 主动配置: 调用流程feign.ReflectiveFeign.FeignInvocationHandler#invokefeign.InvocationHandlerFactory.MethodHandler#invokefeign.SynchronousMethodHandler#invoke MyRpc通过下面的流程,咱们手写一个 RPC。 上面给出次要代码。 @Retention(RetentionPolicy.RUNTIME)@Target(ElementType.TYPE)@Documented@Import({MyRpcRegister.class, MyRpcAutoConfig.class})public @interface EnableMyRpc {}getObject() @Datapublic class MyRpcFactoryBean implements FactoryBean<Object> { private String url; private String contextPath; private String name; private Class<?> type; private BeanFactory beanFactory; private MyClient myClient; @Override public Object getObject() { Map<Method, RpcBean> map = new HashMap<>(); Method[] methods = type.getMethods(); myClient = beanFactory.getBean(MyClient.class); for (Method method : methods) { Annotation[] annotations = method.getAnnotations(); String httpMethod = ""; String path = ""; for (Annotation annotation : annotations) { if (annotation.annotationType() == PostMapping.class) { httpMethod = "POST"; path = ((PostMapping) annotation).value()[0]; break; } else if (annotation.annotationType() == GetMapping.class) { httpMethod = "GET"; path = ((GetMapping) annotation).value()[0]; break; } else if (annotation.annotationType() == RequestMapping.class) { RequestMapping requestMapping = ((RequestMapping) annotation); httpMethod = requestMapping.method()[0].name(); path = requestMapping.value()[0]; break; } } RpcBean rpcBean = new RpcBean() .setUrl(url + contextPath) .setPath(path) .setHttpMethod(httpMethod) .setMyClient(myClient) ; map.put(method, rpcBean); } ClassLoader loader = type.getClassLoader(); return Proxy.newProxyInstance(loader, new Class<?>[] {type}, new MyRpcInvocationHandler(map)); } @Override public Class<?> getObjectType() { return type; }}handler ...

October 22, 2022 · 2 min · jiezi

关于springcloud:SpringCloud整合Dubbo3实战高并发下的微服务架构设计网潘货区

download:SpringCloud整合Dubbo3实战高并发下的微服务架构设计网潘货区StampedLock读写锁“StampedLock简介”StampedLock的状态由版本和模式组成。get lock办法返回一个示意和管制对锁状态的拜访的戳。StampedLock提供三种模式来管制拜访锁: 写入模式 获取写锁,这是独占的。当锁处于写模式时,您无奈取得读锁,并且所有乐观读验证都将失败。 writeLock():阻塞期待锁的独占获取,并返回一个戳。如果为0,则采集失败。TryWriteLock():`尝试获取一个写锁并返回一个工夫戳。如果为0,则采集失败。Long trywritelock (长时间,工夫单位单位):当试图获取一个独占写锁时,能够期待一个事件并返回一个stamp。如果为0,则采集失败。 long writelockinterrupt():尝试获取一个独占的写锁,它能够被中断并返回一个工夫戳。如果为0,则采集失败。UnlockWrite(long stamp):`开释独占写锁,并传入以前获取的stamp。 tryUnlockWrite():如果持有写锁,则该锁将在没有标记值的状况下被开释。这种办法对于出错后的复原可能很有用。 long stamp = lock . write lock();尝试{....}最初{lock.unlockWrite(戳);}复制代码 读取模式 独占读锁之后的乐观之路。 readLock():阻塞期待获取非独占读锁,并返回一个stamp。如果为0,则采集失败。TryReadLock():`尝试获取一个读锁并返回一个工夫戳。如果为0,则采集失败。长读锁(long time,工夫单位单位):当试图获取读锁时,能够期待一个事件并返回一个工夫戳。如果为0,则采集失败。Readlockinterrupt():期待获取非独占读锁的块,它能够被中断并返回一个stamp。如果为0,则采集失败。UnlockRead(long stamp):开释非独占读锁,并传入之前获取的stamp。 tryUnlockRead():如果持有读锁,开释持有一次,不须要stamp值。这种办法对于出错后的复原可能很有用。 长戳= lock . read lock();尝试{....}最初{lock . unlock read(stamp);}复制代码 乐观浏览模式 乐观是指如果读操作多,写操作少,能够乐观地认为写和读同时产生的概率很小,能够应用齐全读锁,不乐观。在读取数据后,程序能够通过写入来查看它是否被更改,而后采取后续措施(从新读取更改的信息或抛出异样)。这个小小的改良能够大大提高程序的吞吐量。StampedLock反对tryOptimisticRead()办法。浏览后,进行盖章查看。如果查看通过,则意味着在此期间没有其余线程写入,数据能够平安应用。如果查看失败,须要从新获取读锁以确保数据一致性。 TryOptimisticRead():`返回一个能够在当前验证的戳,如果以独占形式锁定,则返回零。 boolean validate(long stamp):如果自给定的stamp收回后锁尚未被独占获取,则返回true。 long stamp = lock . trypositicread();//查看戳记如果(!lock.validate(stamp)){//锁定降级}复制代码此外,StampedLock提供api来实现上述三种转换形式: `长tryConvertToWriteLock(长戳)' 如果锁定状态与给定的标记匹配,请执行下列操作之一。如果该标记批示持有写锁,则返回该标记。或者,如果是读锁,并且写锁可用,则开释读锁并返回写戳。或者,在乐观读取的状况下,写戳只有在立刻可用时才返回。在所有其余状况下,该办法返回零。 ` long tryConvertToReadLock(长戳)' 如果锁定状态与给定的标记匹配,请执行下列操作之一。如果标记批示持有写锁,则开释它并取得读锁。或者,如果是读锁,则返回它。或者,在乐观读取的状况下,只有当读取标记立刻可用时,才会取得读取锁并返回读取标记。在所有其余状况下,该办法返回零。 长tryConvertToOptimisticRead(长戳)如果锁的状态与给定的标记相匹配,那么如果标记批示锁被持有,则开释锁并返回察看标记。或者,如果是乐观浏览,验证后返回。在所有其余状况下,该办法都返回0,因而它作为“tryUnlock”的一种模式可能很有用。演示示例用上面的例子来演示StampedLock的用法。这个例子来自jdk中的javadoc。 @Slf4j@数据公共类点{公有双x,y;private final StampedLock sl = new StampedLock();void move(double deltaX,double deltaY)抛出中断异样{//波及共享资源的批改,应用写锁排他操作。long stamp = sl . write lock();log.info("writeLock锁胜利");thread . sleep(500);尝试{x+= deltaX;y+= deltaY;}最初{sl.unlockWrite(盖章);log.info("解锁写锁胜利");}}/***应用乐观读锁访问共享资源。*留神:乐观读锁须要将一个要操作的变量复制到办法栈中,以保证数据的一致性,其余写者在操作数据时可能曾经批改了数据。*而咱们操作的是办法栈中的数据,也就是快照,所以返回最多的数据不是最新的数据,然而一致性还是有保障的。** @返回*/double distanceFromOrigin()抛出InterruptedException {long stamp = sl . trypositicread();//应用乐观读锁log . info(" trypositicread锁胜利");//睡一秒钟thread . sleep(1000);double currentX = x,currentY = y;//将共享资源复制到本地办法堆栈中。如果(!Sl.validate(stamp)) {//如果写锁被占用,可能会导致数据不统一,所以切换到失常的读锁模式。log.info("验证戳记谬误");stamp = sl . read lock();log.info("readLock胜利");尝试{currentX = x;currentY = y;}最初{sl.unlockRead(盖章);log.info("解锁读取胜利");}}return math . sqrt(currentX * currentX+currentY * currentY);}void moveIfAtOrigin(double newX,double newY) { //降级//能够从乐观模式而不是读取模式开始长戳= sl . read lock();尝试{while (x == 0.0 && y == 0.0) {long ws = sl . tryconverttowritelock(stamp);//读锁转换为写锁如果(ws!= 0L) {stamp = wsx = newXy = newY突破;}否则{sl.unlockRead(盖章);stamp = sl . write lock();}}}最初{sl.unlock(盖章);}}}复制代码 ...

October 19, 2022 · 2 min · jiezi

关于springcloud:SpringCloud整合Dubbo3实战高并发下的微服务架构设计内附ppt上山的阿科姿

download:SpringCloud整合Dubbo3实战高并发下的微服务架构设计内附ppt上山的阿科姿国际化示例程序如果您查看国际化的源代码,您会留神到硬编码的英文音讯已被删除。因为音讯不再是硬编码的,而且语言代码是在运行时指定的,所以同一个可执行文件能够在世界范畴内散发。本地化不须要从新编译。这个打算曾经国际化了。 您可能想晓得音讯文本产生了什么变动,或者语言和国家代码的含意。别放心,在示例程序一步步国际化的过程中,你会学到这些概念。 1。创立属性文件属性存储无关程序或环境特色的信息。该文件是纯文本格式的。您简直能够应用任何文本编辑器来创立文件。 在示例中,属性文件存储了要显示的音讯的可翻译文本。在程序国际化之前,该文本的英文版本是硬编码的,并在System.out.println中申明。默认属性文件名为MessagesBundle.properties,蕴含以下行: 问候=你好辞别=再见询问=你好吗?当初,音讯位于属性文件中,它们能够被翻译成各种语言。不须要批改源代码。法语翻译人员创立了一个名为Messages Bundle fr fr . properties的名称,其中蕴含以下几行: 问候=你好。再见。询问=评论allez-vous?请留神,等号左边的值已被转换,但右边的键没有扭转。这些键不能被扭转,因为当程序取得翻译的文本时它们将被援用。 属性的名称很重要。例如,音讯bundle fr fr.properties文件蕴含FR语言代码和FR国家代码。创立广告代码时也会用到这些代码区域设置对象。 2。定义区域的Locale对象标识特定的语言和国家。以下语句定义了语言为英语、国家为美国的区域设置: aLocale =新的区域设置(" en "," US ");下一个示例创立一个对象,其中区域设置在加拿大和法国应用法语: caLocale =新的区域设置(" fr "," CA ");frLocale =新的区域设置(" fr "," FR ");该打算是灵便的。该程序不应用硬编码的语言和国家代码,而是在运行时从命令行获取它们: String language = new String(args[0]);String country = new String(args[1]);currentLocale =新的区域设置(语言,国家);Locale对象只是一个标识符。定义一个区域设置,而后将其传递给执行有用工作的其余对象,例如格式化日期和数字。这些对象是区域敏感的,因为它们的行为是基于区域的。ResourceBundle是区域敏感对象的一个例子。 3。创立ResourceBundleResourceBundle对象蕴含特定于区域设置的对象。您应用ResourceBundle对象来隔离敏感数据,例如可翻译的文本。在示例程序中,ResourceBundle由蕴含咱们想要显示的音讯文本的属性文件反对。 的ResourceBundle创立如下: messages = resource bundle . get bundle(" messages bundle ",current locale);参数被传递给getBundle办法,以确定将拜访哪个属性文件。第一个参数MessagesBundle指的是这组属性文件: MessagesBundle_en_US .属性音讯绑定_fr_FR.propertiesMessagesBundle_de_DE .属性的区域设置是getBundle,它指定抉择了哪个MessagesBundle文件。什么时候。。。创立的区域设置时,语言代码和国家代码已传递给其构造函数。请留神,随后的语言和国家代码音讯是在属性文件的名称中。 当初你要做的就是从ResourceBundle开始。 4。从ResourceBundle获取文本该文件蕴含键值对。包含程序将显示的翻译文本。能够从ResourceBundle和getString办法开始。例如,要检索由greetings键标识的音讯,能够如下调用getString: string msg 1 = messages . getstring(" greetings ");示例程序应用关键字greetings,因为它反映了音讯的内容,但它可能曾经应用了另一个字符串,如s1或msg1。请记住,这个键是硬编码在程序中的,它必须存在于属性文件中。如果您的翻译器不小心批改了属性文件中的键,getString将找不到该音讯。 ...

October 15, 2022 · 1 min · jiezi

关于springcloud:SpringCloud整合Dubbo3实战高并发下的微服务架构设计

download:SpringCloud整合Dubbo3实战高并发下的微服务架构设计Android利用自适应多分辨率解决方案1.第一步是创立多个布局文件夹(drawable也是如此)。 在在res目录下创立多个布局文件夹,文件夹名称为layout-800x480等。写下任何你须要的货色来适应这个决定。留神:A.大的数字应该写在后面:比方layout-854x480而不是layout-480x854。B.这两个数字后面是小写字母X,而不是乘法符号。2.在不可用的布局下调整布局的宽度、长度等设置。以适应不同的分辨率。3最初,你须要在AndroidManifest.xml中增加上面这段话,没有这段话,自适应就无奈实现: android:largeScreens="true "android:normalScreens="true "android:anyDensity = "true"/>在标记之间增加下面的代码。你能够。 Android适应不同分辨率或不同屏幕尺寸的布局布局(横向|纵向)一:布局不同 安卓手机有不同的屏幕尺寸,包含480x320,640x360,800x480。怎样才能让App主动适应不同的屏幕?其实很简略。你只须要在res目录下创立不同的布局文件夹,比方layout-640x360和layout-800x480。所有布局文件在编译后都会写入R.java,零碎会依据屏幕大小抉择适合的布局应用。 二:hdpi,mdpi,ldpi 之前版本只有一个drawable,而2.1版本有三个drawable-mdpi,drawable-ldpi,drawable-hdpi,次要是为了反对多分辨率。 drawable- hdpi、drawable- mdpi和drawable-ldpi之间的区别: (1)drawable-hdpi存储高分辨率图片,如wvga (480x800)、fwvga (480x854)。 (2)drawable-mdpi存储中等分辨率的图片,如HVGA (320x480) (3)drawable-ldpi存储低分辨率图片,如QVGA (240x320) 零碎会依据机器的分辨率在这些文件夹中寻找对应的图片。 更正:应该是不同密度对应的图片。 开发程序时为了兼容不同的平台和屏幕,倡议每个文件夹依据需要寄存不同版本的图片。 [i]备注:三者的分辨率不同,就如同你把电脑的分辨率调低,画面会变大,反之分辨率高,画面会变小。[/i]屏幕方向: 屏幕肖像屏幕主动切换: 能够在res目录下建设layout-port-800x600和layout-land两个目录,别离搁置竖屏和横屏两个布局文件,这样当手机屏幕方位发生变化时,零碎会主动调用相应的布局文件,防止了一个布局文件无奈满足两个屏幕显示的问题。 在不同分辨率的程度和垂直屏幕之间主动切换: 以800x600为例。您能够在res目录中创立layout-port-800x600和layout-land-800x600目录。 不要切换: 以下步骤网上流传,但我以前是通过图形界面实现这种配置的,认为是必由之路。有工夫我会把图片贴上来。 还要留神的是,每个流动都有这个属性screenOrientation,每个流动都须要设置,能够设置为人像或者无重力nosensor。 使程序界面放弃一个方向,不随手机方向变动: 在AndroidManifest.xml中配置就行了增加这行Android:screen orientation = " landscape "。例如(横向是程度的,纵向是垂直的): Java代码: package="com.ray.linkit "android:versionCode="1 "android:versionName="1.0 " > Android:label = " @ string/app _ name "Android:screen orientation = " portrait " > Android:screen orientation = " portrait " > Android:screen orientation = " portrait " > ...

October 6, 2022 · 1 min · jiezi

关于spring-cloud:sofa模块化隔离

传统我的项目传统我的项目中有时会Klass service层间接调用Student service层的Bean去实现某些逻辑,当我的项目变得越来越大时,这种层与层之间的依赖关系变得十分复杂,不利于开发。多个团队同时开发时,本团队只心愿关怀本人负责的模块。这种状况下,就须要将模块于模块之间互相独立,也就是对模块做隔离,export能够提供的Bean,import须要的bean,这样也能让开发者分明每个模块依赖的货色。当我的项目收缩到须要去做服务化的时候,这样,拆分起来就非常简单了。 sofaSOFABoot 是蚂蚁金服开源的基于 Spring Boot 的研发框架。提供了很多性能,如扩大 Spring Boot 健康检查的能力,提供模块化开发的能力,减少模块并行加载和 Spring Bean 异步初始化能力,减少日志空间隔离的能力,减少类隔离的能力,减少中间件集成治理的能力,其中就有模块化隔离性能。 模块化隔离原理原理:基于 Spring 上下文隔离的模块化,用 Spring 上下文来做不同功能模块的隔离,在开发期和编译期,代码和配置也会分在不同 Java 工程中,但在运行期,不同模块间的 Spring Bean 互相不可见,然而所有的 Java 类还是在同一个 ClassLoader 下。 https://www.sofastack.tech/pr... sofa模块首先咱们须要创立一个基于sofa的模块,一个sofa模块与一般我的项目类似,多一个配置文件,使之可能被辨认成一个sofa模块。同时多个sofa模块又都在同一个Spring Boot 我的项目文件夹下。 .├── README.md├── build.gradle├── gradle│   └── wrapper├── gradle.properties├── gradlew├── gradlew.bat├── logs│   ├── health-check│   ├── infra│   ├── sofa-runtime│   └── spring.log├── pom.xml├── service-consumer│   ├── build│   ├── build.gradle│   ├── pom.xml│   └── src├── service-facade│   ├── build│   ├── build.gradle│   ├── pom.xml│   └── src├── service-provider│   ├── build│   ├── build.gradle│   ├── pom.xml│   └── src├── settings.gradle└── sofa-boot-run ├── build ├── build.gradle ├── pom.xml └── src对于每一个sofa模块,多一个sofa-module.properties 文件(src/main/resources 目录下) ...

October 5, 2022 · 1 min · jiezi

关于spring-cloud:2022升级版Spring-Cloud-进阶-Alibaba-微服务体系自媒体实战完结无密王盘分xiang

网潘货区:2022升级版Spring Cloud 进阶 Alibaba 微服务体系自媒体实战完结无密王盘分xiang网站SEO关键词优化的5个技巧对于企业来说,网站很重要。通过网站能够展现企业的产品和服务,与客户进行交换。然而,一个企业只有网站是不够的。还要做好SEO优化,让网站有一个好的排名。那么企业如何做好网站SEO优化呢?上面分享一下SEO网站优化办法和网站SEO关键词优化的五个小技巧。网站SEO优化的办法 1.设置网站的TDK(题目、形容和关键字)。 网站的题目和形容是关键词布局的重要组成部分,设置网站的题目和形容是十分重要的一步。个别题目蕴含3~5个关键词。倡议应用“_”、“|”等作为连接符,重要的关键词要放在后面的地位。个别通顺的句子蕴含3~5个关键词,句子不要超过80个汉字,160个英文字符。 2.公布与主题相干的优质内容。 网站要有明确的主题,每个版块的内容都要解释和撑持这个主题,版块之间要有清晰的逻辑关系和层次感。每一节的内容不要混同,不要与主题无关。更加重视为用户提供主题相干、品质更高的原创内容。 3.向网站图片增加文本形容。 网站展现的图片要加上图片的形容,能够帮忙搜索引擎索引网站的图片,从而进步网站相干主题的排名。 4.关上HTTPS性能 有很大的反对百度HTTPS网站。Https能够减少网站的信任度,爱护数据,防止龚攻打,同时进步网站的SEO排名。该性能在在线建站后盾的“设置-域名”中一键开启,无需放心细节问题。 5.建设友情链接并推广。 一部分搜寻后果来自内部链接和流量,这意味着越多高质量的网站链接到咱们的网站,咱们的网站排名就会越高。所以你能够去各大博客、论坛或者社交网站分享咱们的网站,减少曝光率。 6.留神网站收录。通过SEO综合查问工具,每天查看网站的收录和关键词排名。咱们能够通过md5.com.cn枫叶SEO网查问网站。关上网站后,在首页的输入框中输出要查问的网站,点击查问。稍等一下,能够看到网站的收录和关键词排名。 网站SEO关键词优化的5个技巧 1.网站关键词权重的聚合 应该和题目形容中设置的关键词统一。每一页都应该有不同的题目和形容。切记不要和其余页面一样。题目中关键词的数量应不少于三次。 2.调配关键字等级。 把关键词分成好的等级,外围关键词要放在首页,而后下一级词放在栏目页,长尾词放在内容页。这样清晰的层次结构会给搜索引擎留下很好的印象,整个网站的构造也会更清晰,对搜索引擎优化更敌对。 3.网站的标签和关键词密度 网站的三个标签要依照前后的程序写,否则引擎会依据网站关键词呈现的次数来确定网站关键词。另外,alt标签也很重要,它能够减少关键词的密度,也有利于引擎抓取。同时须要留神的是,引擎无奈抓取网站的图片。为了不影响网站的关上速度,增加时通常须要对图片进行压缩。 4.网站关键词超链接 网站的关键词要有超链接。文章中出现的关键词能够进行网站内容的互相链接,咱们能够链接到一个与网站内容相干的网页。这也是在关键词优化技巧中突出关键词的体现。事实上,内容中某些段落的题目和文章中加粗的段落能够通过比照暂停,以显示关键词。5.定期更新文章。 放弃网站每天定期更新文章。更新的内容尽量是原创或者高质量的伪原创。其次要图文并茂,字数在800字左右。最初,如果优化后的网站竞争不强烈,也没必要天天更新。然而,别忘了引流。没有流量,天然就没有转化。 因为当初各行各业都很风行搞网站SEO,所以网站关键词排名的竞争也越来越强烈。进步网站关键词排名,要晓得网站SEO优化的办法和技巧。以上分享网站SEO优化办法和关键词优化技巧,心愿能帮忙到有须要的敌人。

September 30, 2022 · 1 min · jiezi

关于springcloud:SpringCloud整合Dubbo3实战高并发下的微服务架构设计wum的积分回

download:SpringCloud整合Dubbo3实战高并发下的微服务架构设计wum的积分回Vue 组件间的通信形式前言在Vue组件库的开发过程中,组件之间的通信一直是一个重要的课题。诚然官网的Vuex状态治理打算可能很好的解决组件之间的通信问题,然而组件库外部对Vuex的使用经常比较沉重。本文列举了几种实用的不使用Vuex的组件间通信方法,供大家参考。 组件之间通信的场景在进入咱们明天的主题之前,咱们先来总结下 Vue 组件之间通信的几种场景,一般可能分为如下几种场景: 父子组件之间的通信兄弟组件之间的通信隔代组件之间的通信父子组件之间的通信父子组件之间的通信应该是 Vue 组件通信中最简略也最常见的一种了,概括为两个部分:父组件通过 prop 向子组件传送数据,子组件通过自定义事件向父组件传送数据。 父组件通过 prop 向子组件传送数据Vue 组件的数据流向都遵循单向数据流的原则,所有的 prop 都使得其父子 prop 之间形成了一个单向上行绑定:父级 prop 的更新会向下流动到子组件中,然而反过来则不行。这样会防止从子组件意外变更父级组件的状态,从而导致你的利用的数据流向难以理解。 额定的,每次父级组件发生变更时,子组件中所有的 prop 都将会刷新为最新的值。这意味着你不应该在一个子组件外部改变 prop。如果你这样做了,Vue 会在阅读器的控制台中收回警告。 父组件 ComponentA: <component-b title="welcome">子组件 ComponentB: {{title}} 16.子组件通过自定义事件向父组件传送数据在子组件中可能通过 $emit 向父组件发生一个事件,在父组件中通过 v-on/@ 进行监听。 子组件 ComponentA: <component-b :title="title" @title-change="titleChange">子组件 ComponentB: <div @click="handleClick">{{title}}这个例子非常简略,在子组件 ComponentB 外面通过 $emit 派发一个事件 title-change,在父组件 ComponentA 通过 @title-change 绑定的 titleChange 事件进行监听,ComponentB 向 ComponentA 传送的数据在 titleChange 函数的传参中可能获取到。 兄弟组件之间的通信状态晋升写过 React 的同学应该对组件的 状态晋升 概念并不陌生,React 外面将组件按照职责的不同划分为两类:展示型组件(Presentational Component) 和 容器型组件(Container Component)。 ...

September 28, 2022 · 3 min · jiezi

关于springcloud:SpringCloud整合Dubbo3实战高并发下的微服务架构设计完整无密

download:SpringCloud整合Dubbo3实战高并发下的微服务架构设计残缺无密行为设计模型的中介模型中介模式中介模式,又称介体模式或介体模式,属于行为模式。它封装了一系列对象与两头对象的交互。中介使对象之间相互作用而不显示,从而使它们的耦合变松,独立地扭转它们的相互作用。 Mediator模式包装了一系列对象交互的形式,使得这些对象不用显著地互相交互。以便它们能够涣散耦合。当一些对象之间的交互发生变化时,不会立刻影响其余对象之间的交互。确保这些性能能够互相独立地更改。其核心思想是通过中介解耦零碎,档次对象的所有内部依赖通信都由中介转发。 中介者模式通过提供一个中介类,将零碎各级对象之间的多对多关系变为一对多关系,将简单的网络结构变为以中介者为核心的星型构造,从而升高零碎的复杂性,进步可扩展性。利用场景当多个类互相耦合造成一个网络结构时,能够思考应用mediator模式进行优化。 1.零碎中对象之间存在简单的援用关系,导致它们的依赖构造凌乱,难以重用。 2.我想通过一个两头类将行为封装在多个类中,但又不想生成太多子类。飞行员之间不会相互沟通来决定下一架要起飞的飞机。所有的通信都是通过控制塔。次要角色1.形象调停者(调停者) 定义了对立的接口,用于共事角色之间的交换。 2.特定中介(混凝土中介) 接管来自特定共事的音讯,向特定共事收回命令,并协调共事之间的合作。 3.形象的共事类(共事) 每一个共事对象都须要依附中介的作用,在与其余共事交换时,交给中介进行转发单干。 4.特定共事(混凝土共事) 负责实现本身办法和转发依赖办法。长处和毛病劣势: 1.缩小类间依赖,将多对多的依赖转化为一对多,从而缩小类间耦合; 2.每个类都有本人的性能,合乎迪米特里定律。毛病: 1.在仲裁者模式下,多个对象原来的间接依赖关系,变成了仲裁者和多个共事的依赖关系。共事多了,中介就会变得臃肿,简单,难以保护。根本用处创立一个形象的中介公共抽象类仲裁者{受爱护的混凝土;受爱护的混凝土共事b共事b; public void setColleageA(ConcreteColleagueA共事){this.colleagueA =共事;} public void setColleageB(concretecolleageb共事){this.colleagueB =共事;} //中间业务逻辑公共形象void transferA(); 公共形象void transfer b();} 创立一个具体的中介。公共类ConcreteMediator扩大了Mediator {/***由特定共事类A,向特定共事对象b发送指令*/@笼罩公共void transferA() {this . colleague b . self methodb();} /***由特定共事类b,向特定共事对象a收回指令*/@笼罩public void transferB() {this . colleague a . self methoda();}}.创立形象共事类公共抽象类共事{受爱护的调解人; 公共共事(调解人调解人){this.mediator = mediator 创立特定的共事类公共课ConcreteColleagueA扩大共事{public ConcreteColleagueA(调解员)超级(调解员);this . mediator . setcolleagea(this);} /***本人的办法*/public void selfMethodA() {system . out . println(this . getclass()。GetSimpleName ()+"收到中介合作告诉后,selfMethodA有本人的办法来执行");} /***隶属办法*/public void depMethodA() {system . out . println(this . getclass()。GetSimpleName ()+"Dep Methoda告诉中介转发单干));//中介执行转发合作。this . mediator . transfera();} ...

September 28, 2022 · 1 min · jiezi

关于spring-cloud:sentineldashboardapollo-185-发布支持-apollo-持久化的定制版

sentinel-dashboard-apollo 是从 sentinel-dashboard 官网 fork 进去的一个定制版,反对所有规定长久化到 apollo,不批改一行官网源码,不便滚动降级,继续更新。 版本定制阐明:不改一行源码,实现 sentinel-dashboard 所有配置反对 apollo 长久化 应用文档:sentinel-dashboard-apollo 应用 github:sentinel-dashboard-apollo v1.8.5 版本公布https://github.com/fengjx/Sen... #2 sentinel-dashboard-apollo 降级到 1.8.5 版本#3 docker 镜像构建

September 28, 2022 · 1 min · jiezi

关于springcloud:SpringCloud知识点汇总

SpringCloud什么是微服务架构微服务架构就是将单体的应用程序分成多个应用程序,这多个应用程序就成为微服务,每个微服务运行在本人的过程中,并应用轻量级的机制通信。这些服务围绕业务能力来划分,并通过自动化部署机制来独立部署。这些服务能够应用不同的编程语言,不同数据库,以保障最低限度的集中式管理。 为什么须要学习SpringCloud随着咱们利用业务逐步变得复杂,传统的单体式架构曾经不满足咱们的日常开发了。这个时候咱们就须要从传统的单体架构转变为微服务式的架构模式。传统的单体式架构,在业务越来越简单,代码量越来越多的时候。会导致治理越来越艰难,代码构造的越来越凌乱。同时,这也会给业务的疾速迭代带来微小挑战;开发效率变低:开发人员同时开发一套代码,很难防止代码抵触。开发过程会随同着一直解决抵触的过程,这会重大的影响开发效率;排查解决问题老本高:线上业务发现 bug,修复 bug 的过程可能很简略。然而,因为只有一套代码,须要从新编译、打包、上线,老本很高。因为单体构造的利用随着零碎复杂度的增高,会暴露出各种各样的问题。近些年来,微服务架构逐步取代了单体架构,且这种趋势将会越来越风行。Spring Cloud是目前最罕用的微服务开发框架,曾经在企业级开发中大量的利用。SpringCloud的优缺点长处产出于Spring大家族,Spring在企业级开发框架中无人能敌,来头很大,能够保障后续的更新、欠缺轻轻松松几行代码,注解或者配置就实现了熔断、负载平衡、注册核心的各种平台性能Spring Cloud 社区活跃度很高,教程很丰盛,遇到问题很容易找到解决方案服务拆分粒度更细,耦合度比拟低,有利于资源重复利用,有利于进步开发效率能够更精准的制订优化服务计划,进步零碎的可维护性加重团队的老本,能够并行开发,不必关注其他人怎么开发,先关注本人的开发微服务能够是跨平台的,能够用任何一种语言开发适于互联网时代,产品迭代周期更短 毛病微服务过多,治理老本高,不利于保护零碎分布式系统开发的老本高(容错,分布式事务等)对团队挑战大总的来说长处大过于毛病,目前看来Spring Cloud是一套十分欠缺的分布式框架,目前很多企业开始用微服务、Spring Cloud的劣势是不言而喻的。因而对于想钻研微服务架构的同学来说,学习Spring Cloud是一个不错的抉择。什么是SpringCloudSpring Cloud是一系列框架的有序汇合。它利用Spring Boot的开发便利性奇妙地简化了分布式系统基础设施的开发,如服务发现注册、配置核心、智能路由、音讯总线、负载平衡、断路器、数据监控等,都能够用Spring Boot的开发格调做到一键启动和部署。Spring Cloud并没有反复制作轮子,它只是将各家公司开发的比拟成熟、经得起理论考验的服务框架组合起来,通过Spring Boot格调进行再封装屏蔽掉了简单的配置和实现原理,最终给开发者留出了一套简略易懂、易部署和易保护的分布式系统开发工具包。 SpringBoot和SpringCloud的区别?1.SpringBoot专一于疾速不便的开发单个个体微服务。2.SpringCloud是关注全局的微服务协调整顿治理框架,它将SpringBoot开发的一个个单体微服务整合并且治理起来,为各个服务之间提供,配置管理、服务发现、断路器、路由、微代理、事件总线、全局锁、精选决策、分布式会话等集成服务。3.SpringBoot能够来到SpringCloud独立开发我的项目,然而SpringCloud离不开SpringBoot,属于依赖关系。4.SpringBoot专一于疾速、不便的开发单个微服务个体,SpringCloud关注全局的服务治理框架。 SpringCloud 和 dubbo的区别?服务调用形式: dubbo是RPC,而SpringCloud是rest api注册核心:dubbo是zookeeper,springcloud默认是eureka,当然也可能替换为zookeeper服务网关:dubbo自身没有实现服务网关,只能通过其余第三方激素整合。而springcloud又zuul路由网关,作为路由服务器,进行消费者的申请散发,springcould反对断路器,与git完满继承配置文件反对版本控制,事务总线实现配置文件的更新与服务主动拆卸等等一系列的微服务架构因素。SpringCloud由什么组成?Spring Cloud Eureka:服务注册与发现Spring Cloud Zuul:服务网关Spring Cloud Ribbon:客户端负载平衡Spring Cloud Feign:申明性的Web服务客户端Spring Cloud Hystrix:断路器Spring Cloud Config:分布式对立配置管理等等应用 Spring Boot 开发散布式微服务时,咱们面临什么问题与分布式系统相干的复杂性-这种开销包含网络问题,提早开销,带宽问题,平安问题。服务发现-服务发现工具治理群集中的流程和服务如何查找和相互交谈。它波及一个服务目录,在该目录中注册服务,而后可能查找并连贯到该目录中的服务。冗余-分布式系统中的冗余问题。负载平衡 --负载平衡改善跨多个计算资源的工作负荷,诸如计算机,计算机 集群,网络链路,地方处理单元,或磁盘驱动器的散布。性能-问题 因为各种经营开销导致的性能问题。部署复杂性-Devops 技能的要求。Spring Cloud 和dubbo区别?springcloud 不是一个开发框架,而是一整套的解决方案,而 dubbo 仅仅是一个 rpc 的框架。dubbo 采纳的是传输层 tcp 协定,是二进制传输的,占用带宽较少,序列化采纳的是 jdk 自带的序列化协定。springcloud 是应用层 http 协定,占用带宽比拟多,同时 springcloud 采纳的是 json 报文传输,耗费会比拟大。dubbo 调用应用的是长链接,适宜传输数据量小的包,而对于 springcloud 是短连贯,适宜传输大数据量的信息,比方图片、文本之类的。dubbo 开发须要依赖 jar 包,对依赖的治理比较复杂。springcloud 的接口协议比拟涣散,约束性不强。服务调用形式:dubbo是RPC springcloud Rest Api注册核心应用的不同,dubbo 默认应用的是 zk, 而 springcloud 应用的注册核心为 eureka, 前者保障的是 cp ,而后者保障的是 ap, 然而随着 springcloud alibaba 的呈现,又引入了 nacos 这样的神器,兼有注册核心和配置核心的性能。服务注册和发现是什么意思?SpringCloud如何实现?能够晓得,随着服务的越来越多,越来越杂,服务之间的调用会越来越简单,越来越难以治理。而当某个服务产生了变动,或者因为压力性能问题,多部署了几台服务,怎么让服务的消费者通晓变动,就显得很重要了。不然就会存在调用的服务其实曾经下线了,但调用者不晓得等异常情况。 ...

September 24, 2022 · 2 min · jiezi

关于springcloud:2022年Spring-Cloud-Alibaba快速上手教程

视频链接:小破站视频 代码链接:码云 [github](https://github.com/ten-ken/ken-spring-cloud-alibaba-demo)1、简略理解 SpringCloud官网地址:https://spring.io/projects/spring-cloudspring-cloud-alibaba:(基于2.2.7.RELEASE )https://spring-cloud-alibaba-group.github.io/github-pages/hoxton/zh-cn/index.html 1.1 概述:Spring Cloud 为开发者提供了工具来疾速构建分布式系统中的一些常见模式(例如配置管理、服务发现、断路器、智能路由、微代理、管制总线、一次性令牌、全局锁、领导选举、分布式会话,集群状态)。分布式系统的协调导致了样板模式,应用 Spring Cloud 开发人员能够疾速建设实现这些模式的服务和应用程序。它们在任何分布式环境中都能很好地工作,包含开发人员本人的笔记本电脑、裸机数据中心以及 Cloud Foundry 等托管平台。 1.2 特色Spring Cloud 专一于为典型用例提供良好的开箱即用体验,并提供可扩大机制以笼罩其余用例。 分布式/版本化配置服务注册和发现路由服务到服务调用负载平衡断路器全局锁leader选举和集群状态分布式消息传递如果您想要将 Spring Cloud 增加到该应用程序的现有 Spring Boot 应用程序,则第一步是确定您应该应用的 Spring Cloud 版本。您在应用程序中应用的版本取决于您应用的 Spring Boot 版本。SpringCloud 与 Spring Boot 兼容性(版本对应关系)Spring Cloud 发行版本Spring Boot 版本2021.0.x aka Jubilee2.6.x2020.0.x aka Ilford2.4.x, 2.5.x (Starting with 2020.0.3)Hoxton2.2.x, 2.3.x (Starting with SR5)Greenwich2.1.xFinchley2.0.xEdgware1.5.xDalston1.5.xSpring Cloud Dalston, Edgware, Finchley, and Greenwich 都已达到生命周期完结状态,不再受反对.spring-cloud==> >Hoxton.SR5spring-cloud-alibaba==>2.2.7.RELEASEspring-boot ==> 2.2.10.RELEASE 1.3 引入依赖1.3.1 以maven的形式<properties> <spring.cloud-version>Hoxton.SR8</spring.cloud-version></properties><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>如果咱们应用的是maven版本,咱们能够在父我的项目外面应用management 并把这个依赖放进去,这样咱们能够治理版本spring-cloud相干依赖项(重点是版本控制)1.3.2 以gradle的形式buildscript { dependencies { classpath "io.spring.gradle:dependency-management-plugin:1.0.10.RELEASE"}}ext { set('springCloudVersion', "Hoxton.SR8")}apply plugin: "io.spring.dependency-management" dependencyManagement { imports { mavenBom "org.springframework.cloud:spring-cloud-dependencies:${springCloudVersion}"}}2.对于Spring Cloud Alibaba2.1概念与个性Spring Cloud Alibaba 提供分布式应用开发的一站式解决方案。它蕴含开发分布式应用程序所需的所有组件,使您能够轻松地应用 Spring Cloud 开发应用程序。应用 Spring Cloud Alibaba,您只须要增加一些注解和大量配置,即可将 Spring Cloud 利用连贯到阿里巴巴的分布式解决方案,并通过阿里巴巴中间件构建分布式应用零碎。 ...

September 12, 2022 · 5 min · jiezi

关于springcloud:SpringCloud-三种服务调用方式你学会了吗

本文次要介绍SpringCloud中三种服务调用形式: Spring DiscoveryClient反对Ribbon的RestTemplateFeign客户端搭建服务测试环境测试中,服务发现层采纳Netflix的Eureka搭建。 次要步骤如下: 1.引入Eureka所需依赖<!--eureka服务端--> <dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-starter-eureka-server</artifactId> </dependency><!--客户端--><dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-starter-eureka</artifactId></dependency>2.批改配置文件服务端: eureka: instance: hostname: eureka9001.com #eureka服务端的实例名称 instance-id: eureka9001client: register-with-eureka: false #false示意不向注册核心注册本人 fetch-registry: false # #false 示意本人就是注册核心,职责就是保护服务实例,并不需要去检索服务 service-url: defaulteZone: http://127.0.0.1:9001客户端1: server: port: 8002spring: application: name: licensingserviceeureka: instance: instance-id: licensing-service-8002 prefer-ip-address: true client: register-with-eureka: true fetch-registry: true service-url: defaultZone: http://127.0.0.1:9001/eureka/,客户端2: server: port: 8002spring: application: name: licensingserviceeureka: instance: instance-id: licensing-service-8002 prefer-ip-address: true client: register-with-eureka: true fetch-registry: true service-url: defaultZone: http://127.0.0.1:9001/eureka/, 一组微服务的不同实例采服务名雷同,不同的实例Id辨别,别离对应,spring.application.name 和eureka.instance.instance-id。 ...

September 4, 2022 · 2 min · jiezi

关于springcloud:Spring-Cloud项目优化如何确保Redis延迟队列中数据能被正确消费

前言:无论在哪个我的项目,应用提早队列都须要很明确你应用它的意义以及音讯执行的程序,并且你还须要思考如何确保数据可能正确被解决而不会失落,在进行梳理过程中我就发现了一个破绽会造成数据失落,所以在这里我独自写一篇文章来阐明一下这个破绽及优化策略,如果你有更好的优化策略欢送私信博主。如果你想要一个能够零碎学习的网站,那么我举荐的是牛客网,个人感觉用着还是不错的,页面很整洁,而且内容也很全面,语法练习,算法题练习,面试常识汇总等等都有,论坛也很沉闷,传送门链接: 牛客刷题神器目录一:回顾梳理1.流程图实现后面的操作之后,应用提早队列定时提交文章性能就算实现了。在测试过程中我发现一个问题,尽管数据做了长久化解决,然而当每次生产工作之后数据库中该条数据也会随之被清理掉,这时候还会存在数据失落的危险。为什么这么说呢,咱们的定时公布是依照上面的流程图进行的:2.代码对应的代码如下:@Autowiredprivate WmNewsAutoScanServiceImpl wmNewsAutoScanService; /** * 生产提早队列数据 */@Scheduled(fixedRate = 1000)@Override@SneakyThrowspublic void scanNewsByTask() { ResponseResult responseResult = scheduleClient.poll(TaskTypeEnum.NEWS_SCAN_TIME.getTaskType(), TaskTypeEnum.NEWS_SCAN_TIME.getPriority());if(responseResult.getCode().equals(200) && responseResult.getData() != null){ log.info("文章审核---生产工作执行---begin---"); String json_str = JSON.toJSONString(responseResult.getData()); Task task = JSON.parseObject(json_str, Task.class); byte[] parameters = task.getParameters(); WmNews wmNews = ProtostuffUtil.deserialize(parameters, WmNews.class); System.out.println(wmNews.getId()+"-----------"); wmNewsAutoScanService.autoScanWmNews(wmNews.getId()); log.info("文章审核---生产工作执行---end---");}}/** * 删除工作,更新日志 * @param taskId * @param status * @return */private Task UpdateDb(long taskId, int status) { Task task = null; try { //1.删除工作 log.info("删除数据库中的工作..."); taskInfoMapper.deleteById(taskId); //2.更新日志 log.info("更新工作日志..."); TaskinfoLogs taskinfoLogs = taskInfoLogsMapper.selectById(taskId); taskinfoLogs.setStatus(status); taskInfoLogsMapper.updateById(taskinfoLogs); //3.设置返回值 task = new Task(); BeanUtils.copyProperties(taskinfoLogs,task); task.setExecuteTime(taskinfoLogs.getExecuteTime().getTime()); } catch (BeansException e) { throw new RuntimeException(e); } return task;}/** * 生产工作 * @param type 工作类型 * @param priority 工作优先级 * @return Task */@Overridepublic Task poll(int type, int priority) { Task task = null; try { String key = type + "_" + priority; String task_json = cacheService.lRightPop(ScheduleConstants.TOPIC + key); if(StringUtils.isNotBlank(task_json)) { task = JSON.parseObject(task_json,Task.class); //更新数据库 UpdateDb(task.getTaskId(),ScheduleConstants.EXECUTED); } } catch (Exception e) { e.printStackTrace(); log.error("poll task exception"); } return task;}能够看到在redis中获取数据之后便将数据从数据库中删除,这时候如果前面的审核流程呈现问题或者保留文章时候挪动端微服务呈现故障导致文章不能保留,而这时候数据库中及redis中的数据都删除了,这就造成了数据的失落。二:第一次优化1.优化策略首先我想到的优化策略是当检测到文章审核或者文章保留值挪动端有异样时候就将曾经出队列的数据从新放回队列并且在5分钟之后再进行生产直到生产胜利,流程图见下图:2.代码实现WmAutoScanServiceImplpackage com.my.wemedia.service.impl; ...

August 30, 2022 · 3 min · jiezi

关于springcloud:面试突击78Autowired-和-Resource-有什么区别

@Autowired 和 @Resource 都是 Spring/Spring Boot 我的项目中,用来进行依赖注入的注解。它们都提供了将依赖对象注入到以后对象的性能,但二者却有泛滥不同,并且这也是常见的面试题之一,所以咱们明天就来盘它。@Autowired 和 @Resource 的区别次要体现在以下 5 点: 起源不同;依赖查找的程序不同;反对的参数不同;依赖注入的用法不同;编译器 IDEA 的提醒不同。1.起源不同@Autowired 和 @Resource 来自不同的“父类”,其中 @Autowired 是 Spring 定义的注解,而 @Resource 是 Java 定义的注解,它来自于 JSR-250(Java 250 标准提案)。 小常识:JSR 是 Java Specification Requests 的缩写,意思是“Java 标准提案”。任何人都能够提交 JSR 给 Java 官网,但只有最终确定的 JSR,才会以 JSR-XXX 的格局公布,如 JSR-250,而被公布的 JSR 就能够看作是 Java 语言的标准或规范。2.依赖查找程序不同依赖注入的性能,是通过先在 Spring IoC 容器中查找对象,再将对象注入引入到以后类中。而查找有分为两种实现:按名称(byName)查找或按类型(byType)查找,其中 @Autowired 和 @Resource 都是既应用了名称查找又应用了类型查找,但二者进行查找的程序却截然相同。 2.1 @Autowired 查找程序@Autowired 是先依据类型(byType)查找,如果存在多个 Bean 再依据名称(byName)进行查找,它的具体查找流程如下:对于以上流程,能够通过查看 Spring 源码中的 org.springframework.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor#postProcessPropertyValues 实现剖析得出,源码执行流程如下图所示: 2.2 @Resource 查找程序@Resource 是先依据名称查找,如果(依据名称)查找不到,再依据类型进行查找,它的具体流程如下图所示:对于以上流程能够在 Spring 源码的 org.springframework.context.annotation.CommonAnnotationBeanPostProcessor#postProcessPropertyValues 中剖析得出。尽管 @Resource 是 JSR-250 定义的,然而由 Spring 提供了具体实现,它的源码实现如下: ...

August 29, 2022 · 2 min · jiezi

关于springcloud:SpringCloud-Finchley三版本M2RELEASESR2微服务实战

download:SpringCloud Finchley三版本(M2+RELEASE+SR2)微服务实战从零开始自己动手写自旋锁咱们在写并发程序的时候,一个非常常见的需要就是保障在某一个时刻只有一个线程执行某段代码,像这种代码叫做临界区,而通常保障一个时刻只有一个线程执行临界区的代码的方法就是锁。在本篇文章当中咱们将会认真分析和学习自旋锁,所谓自旋锁就是通过while循环实现的,让拿到锁的线程进入临界区执行代码,让没有拿到锁的线程一直进行while死循环,这其实就是线程自己“旋”在while循环了,因而这种锁就叫做自旋锁。 原子性在谈自旋锁之前就不得不谈原子性了。所谓原子性简略说来就是一个一个操作要么不做要么全做,全做的意义就是在操作的过程当中不能够被中断,比方说对变量data进行加一操作,有以下三个步骤: 将data从内存加载到寄存器。将data这个值加一。将失去的后果写回内存。 原子性就示意一个线程在进行加一操作的时候,不能够被其余线程中断,只有这个线程执行完这三个过程的时候其余线程才能够操作数据data。咱们现在用代码体验一下,在Java当中咱们可能使用AtomicInteger进行对整型数据的原子操作: import java.util.concurrent.atomic.AtomicInteger; public class AtomicDemo { public static void main(String[] args) throws InterruptedException { AtomicInteger data = new AtomicInteger();data.set(0); // 将数据初始化位0Thread t1 = new Thread(() -> { for (int i = 0; i < 100000; i++) { data.addAndGet(1); // 对数据 data 进行原子加1操作 }});Thread t2 = new Thread(() -> { for (int i = 0; i < 100000; i++) { data.addAndGet(1);// 对数据 data 进行原子加1操作 }});// 启动两个线程t1.start();t2.start();// 等待两个线程执行实现t1.join();t2.join();// 打印最终的后果System.out.println(data); // 200000}} ...

August 17, 2022 · 1 min · jiezi

关于springcloud:springbootadmin一些功能说明26x

1. base path我的项目须要用到spring-boot-admin(后简写为sba)做监控,没有独立域名,应用主域名+ingress做门路辨认,所以须要配合contextPath应用,如何配置呢? 应用tomcat的bio通信模型时,通过 server.servlet.context-path=/xxx 就能够了,然而因为sba应用了netty+webflux的nio模型,所以要用 spring.webflux.base-path=/xx 来指定。服务启动之后,就能够通过 http://ip:port/xx 来拜访了。 但这时候有个问题,因为sba连上注册核心默认是把本人也注册下来的,监控他人顺便监控本人,没有问题,然而通过控制台能够看到sba状态是不通的,为什么呢? 点进去能够看到,health-check的endpoint是 http://ip:port/actuator/health 这个actuator组件提供的默认查看门路。因为咱们的sba后面配了basePath,正确的查看门路应该是http://ip:port/xxx/actuator/health 如何更改呢? 查看源码能够晓得,sba是通过注册节点的元数据来获取节点的各项指标数据对应的endpoint的,所以在注册的时候带上对应的metadata就能够了,应用nacos时能够通过增加这个配置来指定: spring: cloud: nacos: discovery: metadata: 'management.context-path': /sadmin/actuator 2. basic authsba我的项目,退出 spring-boot-starter-security 依赖包和如下配置: spring: security: user: name: admin password: 123456即可赋予sba控制台简略验证性能,十分好用。 然而如果sba监控的其余我的项目也应用了basic auth呢?申请的endpoint会被验证拦截,监控会全副生效。这时通过增加以下配置即可: spring: boot: admin: instance-auth: service-map: xxx: # 配置了验证的服务名 userName: admin # 用户名 userPassword: 123456 # 明码3. mail notifysba引入 spring-boot-starter-mail 包,在 spring.mail 节点增加发件服务器配置后,通过以下配置: spring: boot: admin: notify: mail: to: shoujianren1<name@domain.com>,shoujianren2<name2@domain.com>, from: fajianren@domain.cn enabled: true ignore-changes: "UNKNOWN:UP" # 哪些状态不告诉,能够应用*通配符即可开启sba的检测节点状态变更时的邮件告诉性能。当然除了邮件告诉,sba还内置了其余多种IM软件告诉形式,不够用了本人扩大也很不便。 ...

August 12, 2022 · 1 min · jiezi

关于spring-cloud:Spring-Cloud-Alibaba-微服务架构实战完结无密

download:Spring Cloud / Alibaba 微服务架构实战|完结无密OAuth2学习中的一些高频问题的QA对于OAuth2相信很多初学者都有一些疑难,胖哥将这些疑难一一收集了起来做成了QA,或者能帮助学习者。OAuth2相干的QA Q:OAuth2 的一些罕用场景? A: OAuth2次要用于API授权,是跨API服务之间授权的解决打算。它实用于单点登录(SSO)、微服务之间的授权鉴权、API开放平台等场景。 Q: 什么是OAuth2客户端? A: 在OAuth2授权服务器上注册为客户端,并获得专属client_id标识的才是OAuth2客户端。安卓利用、IOS利用、Web前端等客户端利用也要遵循这个原则,它们本身注册到OAuth2授权服务器才能成为OAuth2客户端,否则就不是OAuth2客户端,必须是它们本身,而不是撑持它们的后端服务。 Q:OAuth2 客户端为什么分为public和confidential两种类型,别离是什么场景? A:rfc6749#section-2.1 根据OAuth2客户端自身是否有能力保护客户端凭据(client credentials)的私密性,是否能平安地通过授权服务器对客户端的资质进行认证将OAuth2客户端分为机密客户端和公共客户端。大部分的后端数据服务都应该被注册为机密客户端;无奈保障自身凭据安全的都应该被注册为公共客户端,公共客户端是没有client_sercet的,间接注册到OAuth2授权服务器的执行客户端,不通过后端利用进行拜访令牌中继的都是公共客户端,例如在一些特定场景下需要直连授权服务器的Web利用、移动利用。 Q:OAuth2 的access_token和refresh_token应该间接返回给前端吗? A:能不能返回给前端取决于这个前端是不是间接在授权服务器的OAuth2客户端,如果不是,就不能持有access_token和refresh_token,access_token和refresh_token的签发目标只能是OAuth2客户端。如果暴露面放开,则很容易被盗用。 Q: 非OAuth2客户端的客户端利用既然不能间接持有access_token和refresh_token的话,应该如何获取授权状态? A:当授权胜利后,令牌和用户客户端侧可能借助于session或者cookie进行一个映射,当然也可能考虑计算出一个不通明令牌( Opaque Token )映射,具体根据业务考量。 Q:OAuth2中的scope是什么? A:OAuth2是一个授权框架,授权天然要划定一个范畴(scope),以保障OAuth2客户端在既定的范畴内行事而不越界。它起到的作用和RBAC中的role其实类似,都是用来限度资源的拜访权限的。 role针对的是资源具备者(Resource Owner),而scope针对的是OAuth2客户端。 当然openid是一个例外,这个是OIDC 1.0的标识,算一个关键字。 Q:OAuth2 中的登录页面和授权确认页面能不能用前后端分离的形式? A:很多开发者不心愿点击授权的时候被302重定向到授权服务器提供的登录页面,然而你得明确一个情理, OAuth2客户端和授权服务器之间并不是一个残缺信赖的关系。外卖小哥给你送外卖,你必定心愿发放给他的是一个临时门禁通行码,而不是一个罕用通行码。另外ajax无奈平安地处理OAuth2授权流程中的302重定向问题,这也是一个技术问题。 Q:OAuth2 客户端是否做用户认证? A:OAuth2本身并没有定义用户如何向OAuth2客户端认证身份,这里要和授权服务器上的用户认证区别开来。OAuth2客户端在实现授权时可能拿到授权凭据,然而并不能间接拿到用户信息,如果授权服务器提供了获取用户信息的资源接口,OAuth2客户端可能通过该接口尝试获取用户信息用来表明用户的身份,这取决于用户是否授权了OAuth2客户端这样做。OIDC 1.0补充定义了OAuth2客户端对用户进行认证的细节流程。 Q:OAuth2客户端认证是什么? A:confidential类型的OAuth2客户端诚然在OAuth2授权服务器注册,它们要根据一些策略(Client Authentication Method)来向授权服务器证实自己是非法的客户端。这样它们才能调用一些OAuth2规定的端点,比如/oauth2/token令牌端点、/oauth2/revoke令牌撤销端点等等。对于OAuth2客户端认证的细节可能参考胖哥专栏中的OAuth2客户端认证过滤器详解一文。 Q:OAuth2明码模式为什么被废除了? A:准确地说目前明码模式在OAuth2.1中被移除了,包含OAuth0、okta等出名三方授权服务机构都对明码模式进行了移除处理。明码模式诞生的时候,像React、Vue这种单页利用还没有衰亡,以至连框架都还没有呢。它更像一种为理解决遗留问题而采纳的过渡打算。在传统利用中,用户习惯了把明码间接交给客户端换取资源拜访权限,而不是跳来跳去去拉授权、确认授权。OAuth2诞生之时为了让用户从传统思维中慢慢转变过去就设计了这种模式。 它冲破了托付授权的模式,升高了OAuth2的安全性。更多的细节请参考我往期的相干文章。 Q:OAuth2中的资源服务器怎么讲? A:只需蕴含了需要OAuth2客户端携带access_token拜访的资源接口的服务器都可能认为是资源服务器,包含OAuth2客户端、OAuth2授权服务器都可能根据业务和架构承担资源服务器的功能。从用户(资源所有者)角度来说,存放用户可能授权的资源接口的服务器都可能是资源服务器。资源服务器可能对拜访令牌access_token进行解码、校验,并必定本次请求是否合规。 Q:微服务是否可能不使用OAuth2? 当然可能,OAuth2只不过是目前微服务访问控制的解决打算之一,并不是唯一选项。总结这就是最近胖哥被问的比较多的一些问题,相信能够帮助各位。OAuth2的货色并不简略,通过近三年内断断续续的学习,胖哥才完残缺全理解这个货色,所以各位学习者不要心急,学的枯燥的时候先晾一时间,学这个最重要的是理解它的概念和流程,这远比各种框架重要,OAuth2本身和语言是无关的。

June 10, 2022 · 1 min · jiezi

关于springcloud:Spring-Cloud-Alibaba入门实践二-Nacos

什么是Nacos?Nacos 致力于帮忙您发现、配置和治理微服务。Nacos 提供了一组简略易用的个性集,帮忙您疾速实现动静服务发现、服务配置、服务元数据及流量治理。Nacos 帮忙您更麻利和容易地构建、交付和治理微服务平台。 Nacos 是构建以“服务”为核心的古代利用架构 (例如微服务范式、云原生范式) 的服务基础设施。Nacos的作用服务发现和服务衰弱监测动静配置服务动静DNS服务服务及其元数据管理Nacos疾速入门Docker搭建Nacosclone我的项目 git clone https://github.com/nacos-group/nacos-docker.git我的项目文件夹如图:Nacos反对三种部署模式单机模式 - 用于测试和单机试用。集群模式 - 用于生产环境,确保高可用。多集群模式 - 用于多数据中心场景。抉择单机部署模式,启动容器 #执行standalone-derby.yaml脚本docker-compose -f standalone-derby.yaml up#容器查看是否启动胜利docker ps登录Nacos dashboard #部署Nacos机器的IP#用户和明码默认为nacos/nacoshttp://127.0.0.1:8848/nacos/#/Spring我的项目中引入Nacos服务发现和服务衰弱监测动静配置服务启动服务发现增加pom.xml依赖在application.yml增加配置将利用注册到Nacos #作用:此注解可能让注册核心可能发现,扫描到该服务。#用法:在启动类上增加该注解@EnableDiscoveryClient 启动配置管理增加pom.xml依赖 <dependency> <groupId>com.alibaba.cloud</groupId> <artifactId>spring-cloud-starter-alibaba-nacos-config</artifactId></dependency>在boostrap.yml增加配置 # bootstrap.yml(bootstrap.properties)用来程序疏导时执行,利用于更加晚期配置信息读取,如能够应用来配置application.yml中应用到参数等。# application.yml(application.properties) 应用程序特有配置信息,能够用来配置后续各个模块中需应用的公共参数等。# bootstrap.yml 先于 application.yml 加载。# 技术上,bootstrap.yml 是被一个父级的 Spring ApplicationContext 加载的。这个父级的 Spring ApplicationContext是先加载的,在加载application.yml 的 ApplicationContext之前。spring: profiles: active: dev application: #项目名称 name: gateway-service cloud: nacos: config: #装置nacos的服务器IP server-addr: 127.0.0.1:8848 file-extension: properties namespace: e63e5c13-3da2-41af-9d2e-176432cd856d group: DEFAULT_GROUP

May 27, 2022 · 1 min · jiezi

关于spring-cloud:Spring-Cloud使用了注册中心nacos的服务优雅下线方案

应用了注册核心的服务集群,各个业务节点通过RestTemplate、openFeign进行外部调用时,或者gateway做服务转发时,个别会应用从注册核心获取的服务节点列表进行负载路由,而当一个服务节点被暴力敞开时,从注册核心检测到节点处在不衰弱状态,到注册核心将该节点从保护列表中移除,再到其余业务节点将失效节点从本身保护的节点列表缓存数据中移除(定时拉取或播送告诉形式),两头个别会经验数秒时长,这时如果有转向失效节点的新申请,就会不得不等满一个timeout周期,而后再反馈回调用端去做下一步是重试还是标记熔断的解决。总之,有异样产生,不优雅。 (伪装有流程图) 现成的有不少优雅敞开服务的计划,比方应用actuator的shutdown端点、提供入口调用SpringApplication的exit()静态方法等,不过重要的是在做这些之前要能先被动的将节点从注册核心中下线,而后期待一个适合的时间段之后再敞开服务,这样能多给正在解决中的申请执行实现的机会。 上面是应用了nacos的服务下线示例代码: /** 应用了nacos注册核心的服务敞开端点配置 */@ConditionalOnClass(NacosAutoServiceRegistration.class)@RestController@RequestMapping("actuator")@RequiredArgsConstructor@Slf4jpublic class NacosStopEndpoint { private final NacosAutoServiceRegistration nacosAutoServiceRegistration; private final ApplicationContext context; /** 登记服务后敞开利用前期待的工夫(毫秒) */ @Value("${stopService.waitTime:10000}") private int waitTime; /** * 敞开服务 <br> * 只接管localhost发动的申请 * * @param request * @return */ @PostMapping("stopService") public ResponseEntity<Boolean> stopNacosService( HttpServletRequest request) { if (!request.getServerName().equalsIgnoreCase("localhost")) return ResponseEntity.status(HttpStatus.UNAUTHORIZED).body(false); new Thread( () -> { log.info("Ready to stop service"); nacosAutoServiceRegistration.stop(); log.info("Nacos instance has been de-registered"); log.info("Waiting {} milliseconds...", waitTime); try { Thread.sleep(waitTime); } catch (InterruptedException e) { log.info("interrupted!", e); } log.info("Closing application..."); SpringApplication.exit(context); ((ConfigurableApplicationContext) context).close(); }) .start(); return ResponseEntity.ok(true); }}这段代码提供了一个 /actuator/stopService 的POST端点,调用它即可优雅将服务下线,先把本身从nacos注册核心中移除,期待10秒后敞开spring利用。 ...

May 27, 2022 · 1 min · jiezi

关于spring-cloud:Spring-Cloud-Alibaba-微服务架构实战

Spring Cloud / Alibaba 微服务架构实战超清原画 残缺无密 包含所有视频课件以及源码 MP4格局 获取材料:网盘链接hashCode() 和 equals()的区别equals()equals() 方法用于比较两个对象是否相等,它与 == 相等比较符有着本质的不同。 在万物皆对象的 Java 体系中,零碎把判断对象是否相等的权力交给程序员。具体的措施是把 equals() 方法写到 Object 类中,并让所有类继承 Object 类。 这样程序员就能在自定义的类中重写 equals() 方法, 从而实现自己的比较逻辑。 hashCode()hashCode() 的意义是哈希值, 哈希值是经哈希函数运算后失去的后果,哈希函数能够保障雷同的输出能够失去雷同的输入(哈希值),然而不能够保障不同的输出总是能得出不同的输入。 当输出的样本量足够大时,是会产生哈希冲突的,也就是说不同的输出产生了雷同的输入。 暂且不谈冲突,就雷同的输出能够产生雷同的输入这点而言,是及其宝贵的。它使得零碎只需要通过简略的运算,在工夫复杂度O(1)的情况下就能得出数据的映射关系,根据这种个性,散列表应运而生。 一种支流的散列表实现是:用数组作为哈希函数的输入域,输出值通过哈希函数计算后失去哈希值。而后根据哈希值,在数组种找到对应的存储单元。当发生冲突时,对应的存储单元以链表的形式保存冲突的数据。 两者关系在大多数编程实践中,归根结底会落实到数据的存取问题上。 在汇编语言期间,你需要老诚恳实地对每个数据操作编写存取语句。 而随着期间发展到明天,咱们都用更便利灵活的高级语言编写代码,比如 Java。 Java 以面向对象为中心思想,封装了一系列操作数据的 api,升高了数据操作的复杂度。 但在咱们对数据进行操作之前,首先要把数据按照肯定的数据结构保存到存储单元中,否则操作数据将无从谈起。 然而不同的数据结构有各自的个性,咱们在存储数据的时候需要抉择合适的数据结构进行存储。 Java 根据不同的数据结构提供了丰富的容器类,便利程序员抉择适合业务的容器类进行开发。 通过继承关系图咱们看到 Java 的容器类被分为 Collection 和 Map 两大类,Collection 又可能进一步分为 List 和 Set。 其中 Map 和 Set 都是不容许元素重复的,严格来说Map存储的是键值对,它不容许重复的键值。 值得注意的是:Map 和 Set 的绝大多数实现类的底层都会用到散列表结构。 讲到这里咱们提取两个关键字不容许重复和散列表结构, 回顾 hashCode() 和 equals() 的个性,你是否想到了些什么货色呢?equals()力不从心下面提到 Set 和 Map 不存放重复的元素(key),这些容器在存储元素的时必须对元素做出判断:在以后的容器中有没有和新元素雷同的元素? ...

May 1, 2022 · 1 min · jiezi

关于springcloud:分布式1

Mark程序的分布式申请链路跟踪,反对应用Zipkin、HTrace和基于日志(例如ELK)的跟踪。Spring Cloud Stream轻量级事件驱动微服务框架,能够应用简略的申明式模型来发送及接管音讯,次要实现为Apache Kafka及RabbitMQ。Spring Cloud Task用于疾速构建短暂、无限数据处理工作的微服务框架,用于向利用中增加功能性和非功能性的个性。

April 26, 2022 · 1 min · jiezi

关于springcloud:微服务选型参考文档

微服务倒退单体利用->rpc->微服务 单体利用->rpc解决了单体利用复杂性的问题。每个服务能够独立扩大,更加有利于CI/CD施行。rpc->微服务网关/调用/发现/容错/部署 部署:Spring Cloud for Cloudfoundry/Spring Cloud for Amazon Web Services国内不多见,不赘述。 平台定位springcloud->开发层面/利用层面,与springcloud/dubbo等是一个层面上的货色。 目前大多是通过容器编排的形式来实现服务编排。更具体就是咱们须要借助k8s的能力来实现利用部署/监控/扩缩容等性能。 k8s->ci/cd,与cloudfoundary/swarm是一个层面上货色。 服务编排:大多指的是不通过编程,在容器云平台通过配置、映射等办法来实现服务间的调用、组合,部署成为一个新的服务或利用的过程。容器编排:是依据规定对容器进行调度、配置、组合、部署、回收、迁徙等,以提供利用部署、保护、拓展机制等性能。容器编排次要是K8S等容器编排调度框架要思考的问题。 架构设计架构指标 可能适配业务范围扩大可能比拟不便的满足咱们部门承当了研发和运维的职责,springcloud on k8s 是一个比拟正当的抉择。 可选项自研paas/腾讯云/阿里云均可能提供k8s服务。自研pass:腾讯云/阿里云:http://cloud.macloud.tech/pos...https://maoxian.de/2019/06/15...http://www.gdccia.com/h-nd-11...https://help.aliyun.com/docum... 部署服务注册/发现:高可用集群部署配置核心:高可用集群部署gateway:作为service集群部署服务监控:链路追踪: 参考文档http://dockone.io/article/2896https://kuboard.cn/learning/k...https://www.kubernetes.org.cn...https://cloud.tencent.com/dev...http://www.mydlq.club/article...https://aijishu.com/a/1060000...https://blog.csdn.net/boling_...https://blog.51cto.com/u_1549...https://blog.51cto.com/u_1518...https://blog.51cto.com/u_1362...

April 19, 2022 · 1 min · jiezi

关于springcloud:深入学习springCloudStream消息驱动

1.Stream音讯驱动是什么2.Stream音讯驱动案例阐明3.Stream音讯驱动之生产者4.Stream音讯驱动之消费者5.Stream音讯驱动分组生产和长久化 1.Stream音讯驱动是什么 1.1)队列和服务耦合带来的问题在咱们的日常开发当中,会应用到很多的队列,比方有rabbitmq,kafka,rocketMQ,kafka等等。 所以咱们在编写我的项目的时候,我的项目会和队列的api进行耦合,当咱们切换队列,或者队列与队列之间传输信息的时候,这种中间件的差异性会给咱们造成极大的困扰,如果咱们用了一种队列,前面又有新的业务需要,咱们想往另外一种音讯队列进行迁徙,这个时候无疑就是一种灾难性的,很多货色都要推倒重做,因为这些队列和咱们的零碎耦合了。 1.2)springCloud stream是什么?springCloud stream是一个让开发者调用下层api,就能屏蔽底层队列的区别,构建音讯驱动服务的框架。 所以咱们只须要搞清楚如何与Spring Cloud Stream 交互就能够方便使用音讯驱动的形式。 目前仅反对RabbitMQ、Kafka。 简略地来说,spring cloud stream就是一种屏蔽底层消息中间件的差别,升高切换老本,对立音讯的编程模型。 1.3)为什么要应用spring cloud stream 当咱们提出为什么要应用一个工具的时候,咱们要想不应用这个工具会有什么结果?咱们从下面的形容能够看出,stream音讯驱动是一个解耦工具,不应用这个工具,应用程序就会和队列进行耦合,为了解除这种耦合,咱们采纳了spring cloud stream。 1.4)stream凭什么能够对立底层差别? 咱们能够先来看一下,传统的mq是如何工作的? 传统的mq模型分为生产者,消费者,音讯通道。生产者把音讯通过音讯通道发送给消费者。 咱们再来看一下spring Cloud Stream给咱们提供了一种解耦的形式。 这里引出了一个很重要的概念Binder,在没有Binder这个概念的状况下,咱们的springBoot利用要间接与消息中间件进行信息交互,因为消息中间件构建的理念不同,它们的实现细节上会有较大的差别,应用办法也会有很大的差别,通过定义Binder为中间层,完满地实现了应用程序与消息中间件之间的隔离。 1.5)Spring Cloud Stream的几个重要概念 Binder:INPUT对应于消费者。OUTPUT对应于生产者。 这里咱们可能会感觉到很奇怪,咱们平时不是认为input是生产者,output是消费者吗?其实咱们只有转一个方向就明确了:out是发送信息的那一方,是生产者。input是信息的输出方,是消费者。而咱们平时可能是站在音讯通道的角度来看的,in是输出,是生产,out是输入,是生产。咱们站音讯通道的在里面,思考一下这个问题,就明确了。 Channel:通道,是队列Queue的一种形象,在音讯通信零碎中就是实现存储和转发的媒介,通过Channel对队列进行配置。 Source和Sink:Source:音讯发送者Sink:音讯接受者 1.6)罕用注解 组成阐明B@Input音讯输出通道,音讯的消费者@OutPut音讯输入通道,音讯的生产者@StreamListener监听队列,用于消费者的队列的音讯接管@EnableBinding指信道channel和exchange绑定在一起 2.Stream音讯驱动案例阐明 咱们创立三个我的项目,两个为消费者,一个为生产者。 3.Stream音讯驱动之生产者 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.2.2.RELEASE</version> <relativePath/> <!-- lookup parent from repository --> </parent> <groupId>com.example</groupId> <artifactId>service-stream-provider-8601</artifactId> <version>0.0.1-SNAPSHOT</version> <name>service-stream-provider-8601</name> <description>Demo project for Spring Boot</description> <properties> <java.version>1.8</java.version> <spring-cloud.version>Hoxton.SR1</spring-cloud.version> </properties> <dependencies> <dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-starter-netflix-eureka-client</artifactId> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-web</artifactId> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-actuator</artifactId> </dependency> <dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-starter-stream-rabbit</artifactId> </dependency> <dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-starter-netflix-hystrix</artifactId> </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> </plugin> </plugins> </build></project>yml: ...

April 13, 2022 · 3 min · jiezi

关于springcloud:深入学习springCloudHystrix服务熔断降级

1.分布式系统面临的重大问题2.Hystrix能施展的作用3.服务的异常现象4.Hystrix的服务降级5.Hystrix的服务熔断6.Hystrix的服务监控hystrixDashboard 1.分布式系统面临的重大问题简单的分布式系统中微服务的依赖关系往往非常复杂,很可能会呈现调用失败的状况。假如如图所示,一个申请须要调用到A,H,I,P四个服务,如果申请数不多,并发量不大的状况下,这个分布式系统不会呈现什么问题,然而一旦申请数减少到肯定的阈值,某些服务如果呈现了超时,产生什么? 服务的雪崩:如果多个服务在调用的时候,在调用链上的一个微服务呈现相应工夫过长或者报错导致的长期不可用,那么调用这些服务的服务调用者会积压越来越多的申请,占用越来越多的资源,从而引起解体,这就是所谓的“雪崩效应”。 对于繁多一个服务来说,被调用方产生了异样阻塞,那个调用方的资源很可能在几秒钟内饱和。比失败更蹩脚的是,被调用方产生异样后,还可能会使队列,线程池等资源越来越缓和,导致整个零碎产生联级故障。这些景象都证实了,要对服务的异样和提早进行隔离和治理,即使单个依赖的失败,也不能让其它服务出现异常,防止出现联级效应。 此时就要用咱们的Hystrix!Hystrix是一个解决分布式服务的提早和容错的开源库,在分布式系统中,许多依赖不可避免地会调用失败,Hystrix可能保障在一个依赖出问题的状况下,不会导致整体服务失败,防止联级故障,进步分布式系统的可用性。 “断路器”自身是一种开关安装,当某个服务单元产生故障当前,通过断路器的故障监控,向调用方返回一个合乎预期的,可解决的备选响应,而不是长时间的期待或者抛出调用办法无奈解决的异样,这样就保障了服务调用方不会被长时间,不必要地占用,从而避免了故障在分布式系统中的蔓延,雪崩。 很惋惜Hystrix也曾经进行更新了,不过咱们能够为后续学习SpringCloud AlibabaSentinel打下基础。 2.Hystrix能施展的作用 个别的来说Hystrix能施展三个作用:2.1)服务降级降级就是在被调用服务出问题的时候,不让客户端期待并返回一个敌对的提醒。当产生以下这种状况的时候,能够触发降级2.1.1)程序运行异样,报错2.1.2)超时2.1.3)服务熔断产生服务降级2.1.4)线程池/信号量打满产生服务降级 2.2)服务熔断服务达到最大的访问量后,或者服务调用失败(降级)超过肯定的次数,间接回绝拜访,而后调用服务降级的办法并返回敌对提醒。 2.3)服务限流依照服务器可能消化的能力,进行排队生产申请,就像队列一样。 3.服务的异常现象 咱们新建一个延时接口,而后对这个接口进行压力测试: @GetMapping(value = "/payment/get/delay/{id}") public String getPaymentDelayById(@PathVariable("id") Long id) { try { Thread.sleep(5000); } catch (InterruptedException e) { e.printStackTrace(); } return "调用胜利,服务端口为"+serverPort; } 咱们对这个延时接口进行压力测试,同时调用这个服务的其它接口,发现没有延时的接口也被影响了,也始终转圈圈。 为什么会始终在转圈圈? 因为tomcat的默认的工作线程数被打满了,没有多余的线程来合成和解决,此时再调用另外的接口,导致整个服务都呈现问题。 正因为会呈现下面这种,一个接口拖垮整个服务的景象,咱们才会有降级/熔断/限流等技术诞生。 咱们要解决的问题如下:1)服务提供者超时了,调用者不能始终卡死期待,必须有服务降级。2)服务提供者down机了,调用者不能始终卡死期待,比方有服务降级。3)服务提供者失常,调用者出现异常,也要本人进行降级。 4.Hystrix的服务降级 接下来,咱们就要应用Hystrix进行服务降级了,咱们能够在服务的调用者加上服务降级的注解。 在服务提供者中退出这个依赖,因为springCloud 在2021.0.1曾经移除了除了eureka的所有依赖,所以咱们这里对版本进行降级。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.2.2.RELEASE</version> <relativePath/> <!-- lookup parent from repository --> </parent> <groupId>com.example</groupId> <artifactId>service-provider-8501</artifactId> <version>0.0.1-SNAPSHOT</version> <name>service-provider-8501</name> <description>Demo project for Spring Boot</description> <properties> <java.version>1.8</java.version> <spring-cloud.version>Hoxton.SR1</spring-cloud.version> </properties> <dependencies> <dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-starter-netflix-eureka-client</artifactId> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-web</artifactId> </dependency> <dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-starter-netflix-hystrix</artifactId> </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> </plugin> </plugins> </build></project>主启动类: ...

April 11, 2022 · 2 min · jiezi

关于springcloud:深入学习springCloudRibbonOpenFeign负载均衡服务接口调用

1.Ribbon是什么2.Ribbon负载平衡演示3.Ribbon轮询算法原理和手写4.OpenFeign是什么5.OpenFeign应用步骤6.OpenFeign超时管制7.OpenFeign日志打印8.OpenFeign和Feign的区别 1.Ribbon是什么后面咱们学过了深刻学习springCloud——服务注册核心之eureka,然而服务和服务之间该如何通过注册核心进行调用,以及如果有多个服务提供者的话,如何提供负载平衡的策略,这都是咱们要思考的问题,此时就呈现了Ribbon! Ribbon是spring Cloud 的一套客户端负载平衡的工具! Ribbon次要提供的性能是提供客户端软件的负载平衡算法和服务调用。简略地说,Ribbon能获取该服务的所有实例,他会主动地帮你基于某种规定(比方轮询,随机等)算法去调用这些机器。咱们很容易地应用Ribbon实现自定义的的Load Balancer(简称LB)算法。 然而Ribbon目前也进入了保护模式,代替计划是OpenFeign,不过为了更好地学习OpenFeign,咱们就从Ribbon开始解说,缓缓过渡到OpenFeign. 为了更好地学习Ribbon,咱们先来理解一下负载平衡(LB)是什么:因为咱们的服务都是集群部署的,所以负载平衡就是将客户端的申请,均匀地调配到同一种集群服务的多个实例下面,从而让每一个服务承受到的申请数量差不多,达到HA(高可用)。 常见的负载平衡形式:1)Ribbon本地负载平衡在调用微服务接口的时候,调用者会从注册核心获取服务器注册表,而后通过算法进行均匀调用,负载平衡是由客户端实现的(过程内LB)。2)Nginx服务端负载平衡客户端先把所有申请交给nginx,而后由nginx转发实现申请,负载平衡是由服务器端实现的(集中式LB)。 2.Ribbon负载平衡演示 用Ribbon调用服务的流程图: Ribbon在工作的时候,有以下的步骤: 1)调用者先从Eureka中取出被调用者的服务列表2)依据用户的策略(轮询,随机等),从server取到的服务注册表中选取一个地址,进行调用。 咱们先筹备两个服务提供者,以便更好地显示出负载平衡的成果。 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.6.6</version> <relativePath/> <!-- lookup parent from repository --> </parent> <groupId>com.example</groupId> <artifactId>service-provider-8501</artifactId> <version>0.0.1-SNAPSHOT</version> <name>service-provider-8501</name> <description>Demo project for Spring Boot</description> <properties> <java.version>1.8</java.version> <spring-cloud.version>2021.0.1</spring-cloud.version> </properties> <dependencies> <!-- 这里应用eureka-client--> <dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-starter-netflix-eureka-client</artifactId> </dependency> <!-- 留神要援用spring-boot-starter-web--> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-web</artifactId> </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> </plugin> </plugins> </build></project>yml: ...

April 7, 2022 · 3 min · jiezi

关于spring-cloud:Spring-cloud-集成-SkyWalking-实现性能监控链路追踪日志收集

Why SkyWalking?Skywalking 是一个优良的APM(application performance monitor)利用性能监控零碎,针对微服务场景设计,能够不便的实现Spring cloud等微服务场景下的性能监控、链路追踪等。而v8.x版本也反对了日志收集性能,能够取代ELK作为分布式下日志收集的计划。一个零碎实现监控+追踪+日志的多个能力,无效升高微服务下运维的复杂度。 上面咱们以Spring cloud为例,一起玩转Skywalking1. 环境筹备与装置要实现监控+追踪+日志,咱们须要装置根底的 APM 和 Java agent。 进入下载页面: SkyWalking 下载下载 SkyWalking APM 以及 Java agent 如下两个压缩包: 下载实现后解压,尝试运行 /apache-skywalking-apm-bin/bin/startup.bat (或startup.sh)拜访 http://localhost:8080/,即可看到SkyWalking监控UI 以上装置为间接装置,如需docker等装置形式可参考SkyWalking官网文档2. 配置SkyWalking日志收集(logback为例)pom 中依赖 SkyWalking 的 logback 插件包: <!-- SkyWalking log collection --><dependency> <groupId>org.apache.skywalking</groupId> <artifactId>apm-toolkit-logback-1.x</artifactId> <version>8.9.0</version></dependency>增加/批改 logback.xml,启用 SkyWalking 提供的 appender,示例配置如下: <?xml version="1.0" encoding="UTF-8"?><configuration scan="true" scanPeriod="10 seconds"> <appender name="stdout" class="ch.qos.logback.core.ConsoleAppender"> <encoder class="ch.qos.logback.core.encoder.LayoutWrappingEncoder"> <layout class="org.apache.skywalking.apm.toolkit.log.logback.v1.x.TraceIdPatternLogbackLayout"> <Pattern>%d{yyyy-MM-dd HH:mm:ss.SSS} [%tid] [%thread] %-5level %logger{36} -%msg%n</Pattern> </layout> </encoder> </appender> <appender name="grpc" class="org.apache.skywalking.apm.toolkit.log.logback.v1.x.log.GRPCLogClientAppender"> <encoder class="ch.qos.logback.core.encoder.LayoutWrappingEncoder"> <layout class="org.apache.skywalking.apm.toolkit.log.logback.v1.x.mdc.TraceIdMDCPatternLogbackLayout"> <Pattern>%d{yyyy-MM-dd HH:mm:ss.SSS} [%X{tid}] [%thread] %-5level %logger{36} -%msg%n</Pattern> </layout> </encoder> </appender> <root level="INFO"> <appender-ref ref="stdout"/> <appender-ref ref="grpc"/> </root></configuration>3. 配置Java agentIDEA开发环境下配置Java agent: ...

April 6, 2022 · 1 min · jiezi

关于springcloud:NacosOpenFegin正确调用服务的姿势

Nacos 反对两种 HTTP 服务申请,一个是 REST Template,另一个是 Feign Client。之前的文章咱们介绍过 Rest Template 的调用形式,次要是通过 Ribbon(负载平衡) + RestTemplate 实现 HTTP 服务调用的,申请的外围代码是这样的: @RestControllerpublic class ConsumerController { @Resource private RestTemplate restTemplate; @GetMapping("/consumer") public String consumer(@RequestParam String name) { // 申请并获取后果(springcloud-nacos-provider 是 nacos 中的服务id) String result = restTemplate.getForObject("http://springcloud-nacos-provider/call/" + name, String.class); return result; }}从上述的实现代码咱们能够看出一个问题,尽管以上代码能够实现 HTTP 服务调用,但须要开发者手动拼接调用地址和参数,并且近程服务调用和客户端本身的业务逻辑实现是混合在一起,不利于前期的保护与扩大,那如何要解决这个问题呢?这就是咱们明天要介绍的 OpenFeign 的起因了。 OpenFeign 介绍OpenFeign 的全称是 Spring Cloud OpenFeign,它是 Spring 官网推出的一种申明式服务调用和负载平衡组件。它的呈现就是为了代替曾经进入停更保护状态的 Feign(Netflix Feign)的。也就是说 OpenFeign(Spring Cloud OpenFeign)是 Feign 的升级版,它们的关系如下图所示:因为 Feign 停更保护了,所以 Spring 官网须要推出了一个新的新的框架来对 Feign 性能进行降级和扩大。 ...

March 23, 2022 · 3 min · jiezi

关于springcloud:Spring-Cloud-Ribbon-中的-7-种负载均衡策略

负载平衡通器常有两种实现伎俩,一种是服务端负载均衡器,另一种是客户端负载均衡器,而咱们明天的配角 Ribbon 就属于后者——客户端负载均衡器。 服务端负载均衡器的问题是,它提供了更强的流量控制权,但无奈满足不同的消费者心愿应用不同负载平衡策略的需要,而应用不同负载平衡策略的场景的确是存在的,所以客户端负载平衡就提供了这种灵活性。 然而客户端负载平衡也有其毛病,如果配置不当,可能会导致服务提供者呈现热点,或者压根就拿不到任何服务的状况,所以咱们本文就来理解一下这 7 种内置负载平衡策略的具体规定。 Ribbon 介绍Ribbon 是 Spring Cloud 技术栈中十分重要的根底框架,它为 Spring Cloud 提供了负载平衡的能力,比方 Fegin 和 OpenFegin 都是基于 Ribbon 实现的,就连 Nacos 中的负载平衡也应用了 Ribbon 框架。 Ribbon 框架的弱小之处在于,它不仅内置了 7 种负载平衡策略,同时还反对用户自定义负载平衡策略,所以其开放性和便利性也是它得以风行的次要起因。 服务端负载均衡器和客户端负载均衡器的区别如下图所示:客户端负载均衡器的实现原理是通过注册核心,如 Nacos,将可用的服务列表拉取到本地(客户端),再通过客户端负载均衡器(设置的负载平衡策略)获取到某个服务器的具体 ip 和端口,而后再通过 Http 框架申请服务并失去后果,其执行流程如下图所示: 负载平衡设置以 Nacos 中的 Ribbon 负载平衡设置为例,在配置文件 application.yml 中设置如下配置即可: springcloud-nacos-provider: # nacos中的服务id ribbon: NFLoadBalancerRuleClassName: com.netflix.loadbalancer.RoundRobinRule #设置负载平衡策略因为 Nacos 中曾经内置了 Ribbon,所以在理论我的项目开发中无需再增加 Ribbon 依赖了,这一点咱们在 Nacos 的依赖树中就能够看到,如下图所示:Ribbon 默认的负载平衡策略是轮询模式,咱们配置 3 个服务提供者的执行后果如下图所示:而后,咱们再将 Ribbon 负载平衡策略设置为随机模式,配置内容如下: springcloud-nacos-provider: # nacos中的服务id ribbon: NFLoadBalancerRuleClassName: com.netflix.loadbalancer.RandomRule #设置随机负载平衡重启客户端,执行后果如下图所示: ...

March 14, 2022 · 1 min · jiezi

关于springcloud:Spring-Cloud-Gateway-不小心换了个-Web-容器就不能用了我-TM-人傻了

集体创作公约:自己申明创作的所有文章皆为本人原创,如果有参考任何文章的中央,会标注进去,如果有疏漏,欢送大家批评。如果大家发现网上有剽窃本文章的,欢送举报,并且踊跃向这个 github 仓库 提交 issue,谢谢反对~ 本文是我 TM 人傻了的第多少期我忘了,每一期总结一个坑以及对于坑的一些发散性想法,往期精彩回顾: 降级到Spring 5.3.x之后,GC次数急剧减少,我TM人傻了这个大表走索引字段查问的 SQL 怎么就成全扫描了,我TM人傻了获取异样信息里再出异样就找不到日志了,我TM人傻了spring-data-redis 连贯透露,我 TM 人傻了Spring Cloud Gateway 没有链路信息,我 TM 人傻了Spring Cloud Gateway 雪崩了,我 TM 人傻了启用 Spring-Cloud-OpenFeign 配置可刷新,我的项目无奈启动,我 TM 人傻了spring-data-redis 上百万的 QPS 压力太大连贯失败,我 TM 人傻了最近组员批改微服务的一些公共依赖,在某个依赖中须要针对咱们微服务应用的 Undertow 容器做一些订制,所以退出了 web 容器 Undertow 的依赖。然而,个别这种底层框架依赖,是要兼顾以后应用的这个我的项目的 web 容器是否是 Undertow,这位同学在配置类上写了 @Conditional: @Configuration(proxyBeanMethods = false)@ConditionalOnClass({ Undertow.class }) public class CustomizedUndertowConfiguration { .......}然而加的 undetow 依赖的 scope 没有设置为 provided,导致只有退出这个依赖就会退出 Undertow 的依赖。正好网关也用到了这个依赖,并且咱们的网关应用的是 Spring-Cloud-Gateway。这就导致了 Spring-Cloud-Gateway 自身的 Netty 的 Reactive 的 web 容器被替换成了 Undertow 的 Reactive 的 web 容器,从而导致了一系列的 Spring-Cloud-Gateway 不兼容的问题。 ...

March 12, 2022 · 3 min · jiezi

关于spring-cloud:Spring-Security-OAuth20-自定义授权模式

大家好,我是不才陈某~ 这是《Spring Cloud 进阶》第24篇文章,往期文章如下: 五十五张图通知你微服务的灵魂摆渡者Nacos到底有多强?openFeign夺命连环9问,这谁受得了?阿里面试这样问:Nacos、Apollo、Config配置核心如何选型?这10个维度通知你!阿里面试败北:5种微服务注册核心如何选型?这几个维度通知你!阿里限流神器Sentinel夺命连环 17 问?比照7种分布式事务计划,还是偏爱阿里开源的Seata,真香!(原理+实战)Spring Cloud Gateway夺命连环10问?Spring Cloud Gateway 整合阿里 Sentinel网关限流实战!分布式链路追踪之Spring Cloud Sleuth夺命连环9问?链路追踪自从用了SkyWalking,睡的真香!3本书了,7万+字,10篇文章,《Spring Cloud 进阶》根底版 PDF妹子始终没搞懂OAuth2.0,明天整合Spring Cloud Security 一次说明确!OAuth2.0实战!应用JWT令牌认证!OAuth2.0实战!玩转认证、资源服务异样自定义这些骚操作!实战干货!Spring Cloud Gateway 整合 OAuth2.0 实现分布式对立认证受权!字节面试这样问:跨库多表存在大量数据依赖问题有哪些解决方案?实战!退出登录时如何借助外力使JWT令牌生效?实战!Spring Cloud Gateway集成 RBAC 权限模型实现动静权限管制!实战!阿里神器 Seata 实现 TCC模式 解决分布式事务,真香!实战!openFeign如何实现全链路JWT令牌信息不失落?微服务下蓝绿公布、滚动公布、灰度公布等计划,必须懂!微服务如何聚合 API 文档?这波秀~Spring Cloud 2021.0.1 正式公布,卷不动了~本篇文章介绍一下Spring Security如何扩大新的受权类型,也是理论开发中十分重要的知识点。 目录如下: 为什么须要自定义受权类型?后面介绍OAuth2.0的根底知识点时介绍过反对的4种受权类型,别离如下: 受权码模式简化模式客户端模式明码模式对于上述4种受权类型不分明的,能够看之前的文章:妹子始终没搞懂OAuth2.0,明天整合Spring Cloud Security 一次说明确! 理论生产中上述四种受权类型基本不够用,比方常见的受权类型如下: 微信认证QQ认证手机号+验证码认证图形验证码认证邮箱认证因而咱们必须懂得OAuth2.0如何自定义受权类型,这也是本篇文章的重点。 实现思路Spring Security 定制受权类型其实很简略,次要是把握其中的思路,上面是明码模式的受权流程,如下图: 根据上述流程图能够跟着源码进去看看,不难发现有几个如下重要点: 每种受权类型都对应一个实现类TokenGranter,其中定义着受权类型所有 TokenGranter 实现类都通过 CompositeTokenGranter 中的 tokenGranters 汇合存起来。而后通过判断 grantType 参数来定位具体应用那个 TokenGranter 实现类来解决受权。每种受权形式都对应一个AuthenticationProviderTokenGranter 类会 new 一个 AuthenticationToken实现类,如 UsernamePasswordAuthenticationToken 传给 ProviderManager 类。因而想要自定义一个受权类型,必须构建本人的TokenGranter、AuthenticationProvider、AuthenticationToken。 ...

March 11, 2022 · 1 min · jiezi

关于springcloud:gateway使用全局过滤器进行token校验

引入依赖<dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-starter-gateway</artifactId></dependency>为什么不应用拦截器interceptor应用interceptor须要引入spring-boot-starter-web这个依赖,然而这个依赖会导致gateway服务无奈启动,报出No qualifying bean of type 'org.springframework.core.convert.ConversionService' available的异样,起因是gateway不能在tomcat等传统servlet容器中运行,而是须要netty,如果有这个报错则把spring-boot-starter-web依赖去掉即可。 编写过滤器@Component@Slf4jpublic class AuthFilter implements GlobalFilter, Ordered { private AntPathMatcher matcher = new AntPathMatcher(); @Override public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) { ServerHttpRequest request = exchange.getRequest(); String path = request.getURI().getPath(); log.info("申请门路: {}", path); if (matcher.match("/api/**/auth/**", path)){ if (getUserId(request) == null){ log.error("token不正确"); out(exchange.getResponse(), ResultCodeEnum.LOGIN_AUTH); } } return chain.filter(exchange); } private Long getUserId(ServerHttpRequest request){ List<String> tokens = request.getHeaders().get("token"); if (tokens == null || StringUtils.isEmpty(tokens)){ log.error("申请未携带token"); return null; } return JwtUtil.getUserId(tokens.get(0)); } /** * api接口鉴权失败返回数据 * @param response * @return */ private Mono<Void> out(ServerHttpResponse response, ResultCodeEnum resultCodeEnum) { Result result = Result.build(null, resultCodeEnum); byte[] bits = JSONObject.toJSONString(result).getBytes(StandardCharsets.UTF_8); DataBuffer buffer = response.bufferFactory().wrap(bits); //指定编码,否则在浏览器中会中文乱码 response.getHeaders().add("Content-Type", "application/json;charset=UTF-8"); return response.writeWith(Mono.just(buffer)); } @Override public int getOrder() { return 0; }}过滤器类须要实现GlobalFilter接口实现filter办法,以后的http申请对象request通过ServerWebExchange的getRequest()办法获取,request对象的getURI().getPath()办法能够取得申请的地址(例如申请拜访localhost:8080/test/name则地址为/test/name)。应用AntPathMatcher能够应用匹配字符串对申请地址进行匹配,示例中对带auth即须要登录的拜访进行了匹配拦挡,之后通过request获取header中的token进行token的验证。如果token验证失败,应用out办法将错误信息输入,这里采纳的是将输入对象进行json序列化后再转为bit流输入。实现Order接口是为了进行过滤器优先级的定义,即实现getOrder()办法,当有多个过滤器时,这个办法返回的值越小优先级越高。 ...

February 22, 2022 · 1 min · jiezi

关于springcloud:gateway解决跨域访问

增加依赖<dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-starter-gateway</artifactId></dependency>增加gateway依赖 增加配置类@Configurationpublic class CrosConfiguration { @Bean public CorsWebFilter corsFilter() { CorsConfiguration config = new CorsConfiguration(); config.addAllowedMethod("*"); config.addAllowedOrigin("*"); config.addAllowedHeader("*"); UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource(new PathPatternParser()); source.registerCorsConfiguration("/**", config); return new CorsWebFilter(source); }}在gateway我的项目中退出改配置类可解决跨域问题。 微服务环境中配置路由#路由的id,没有规定规定但要求惟一,倡议配合服务名spring.cloud.gateway.routes[2].id=service-user#匹配后提供服务的路由地址,在微服务环境中为lb:服务名,其余环境能够是具体域名或ipspring.cloud.gateway.routes[2].uri=lb://service-user#匹配规定,上面为申请门路中带userspring.cloud.gateway.routes[2].predicates= Path=/*/user/**例如gateway服务于8081端口启动,localhost:8081/api/user/getname这个申请会被转发到service-user/api/user/getname。

February 21, 2022 · 1 min · jiezi

关于springcloud:GatewayNacosKnife4jswagger的方案的补充

想把Knife4j集成到gateway里的办法,网上能搜寻到很多。这里我整顿一下,办法大抵是: Spring Cloud Gateway集成Knife4j然而,可能你们会遇到一个问题,就是doc页面关上后,能见到对应的微服务分组,然而,却看不到接口列表。 那是因为,你们的微服务的文档,是在/v2/apis-doc路由里。而gateway的nacos配置转发里,配的是这样的拦挡转发 - id: sys_route uri: lb://cloud-sys predicates: - Path=/api/sys/**就会导致微服务sys_route文档最终拼接进去的申请是/api/sys/v2/apis-doc 解决方案是,应用gateway的filters配置 - id: sys_route uri: lb://cloud-sys predicates: - Path=/api/sys/** filters: - RewritePath=/api/sys/v2/api-docs, /v2/api-docs(第一次接触filters的,举荐再看看StripPrefix属性) PS:Knife4j官网最近也出了Knife4jAggregation微服务版本,间接部署这个微服务就能够(然而要额定启动多一个微服务,内存缓和...)。

February 16, 2022 · 1 min · jiezi

关于springcloud:springcloud五大核心组件

Spring Cloud是一系列框架的有序汇合。它利用Spring Boot的开发便利性奇妙地简化了分布式系统基础设施的开发,如服务发现注册、配置核心、音讯总线、负载平衡、断路器、数据监控等,都能够用Spring Boot的开发格调做到一键启动和部署。Spring Cloud并没有反复制作轮子,它只是将各家公司开发的比拟成熟、经得起理论考验的服务框架组合起来,通过Spring Boot格调进行再封装屏蔽掉了简单的配置和实现原理,最终给开发者留出了一套简略易懂、易部署和易保护的分布式系统开发工具包。 ①. 服务发现——Netflix Eureka 一个RESTful服务,用来定位运行在AWS地区(Region)中的中间层服务。由两个组件组成:Eureka服务器和Eureka客户端。Eureka服务器用作服务注册服务器。Eureka客户端是一个java客户端,用来简化与服务器的交互、作为轮询负载均衡器,并提供服务的故障切换反对。Netflix在其生产环境中应用的是另外的客户端,它提供基于流量、资源利用率以及出错状态的加权负载平衡。 ②. 客服端负载平衡——Netflix Ribbon Ribbon,次要提供客户侧的软件负载平衡算法。Ribbon客户端组件提供一系列欠缺的配置选项,比方连贯超时、重试、重试算法等。Ribbon内置可插拔、可定制的负载平衡组件。 ③. 断路器——Netflix Hystrix 断路器能够避免一个应用程序屡次试图执行一个操作,即很可能失败,容许它持续而不期待故障复原或者节约 CPU 周期,而它确定该故障是长久的。断路器模式也使应用程序可能检测故障是否曾经解决。如果问题仿佛曾经失去纠正,应用程序能够尝试调用操作。 ④. 服务网关——Netflix Zuul 相似nginx,反向代理的性能,不过netflix本人减少了一些配合其余组件的个性。 ⑤. 分布式配置——Spring Cloud Config 这个还是动态的,得配合Spring Cloud Bus实现动静的配置更新。 关键词:java培训

February 10, 2022 · 1 min · jiezi

关于springcloud:SpringCloudEureka-Feign-Ribbon-Hystrix-Zuul等关键组件的学习与记录

SpringCloud——Eureka Feign Ribbon Hystrix Zuul等要害组件的学习与记录前言:本篇是对近日学习狂神SpringCloud教程之后的感想和总结,鉴于对SpringCloud体系的理解尚且处于初期阶段,在措辞、了解上难免会有偏颇,还请批评和斧正! 一、概述SpringCloud是一套微服务解决方案,在spring-cloud-dependencies Hoxton.SR8版本与spring-boot-dependencies 2.3.4.RELEASE版本的配合下,这一套解决方案提供了Eureka注册核心、Ribbon+RestTemplete或Feign的负载平衡计划、Hystrix熔断、Hystrix+Feign降级、HystrixDashboard服务监控以及Zuul路由网关。 不过,在spring-cloud-dependencies后续的版本中(如2020.x.x系列版本),上述提供的服务变动较大,尤其是Ribbon进行更新(IRule接口被移除)、Hystrix+Feign的变动使咱们应用自定义的负载平衡算法、进行服务降级时造成了一些艰难,这些局部我还在学习和摸索中,会在根本理解和把握之后再进行记录,因此本篇仍然基于稍早的spring-cloud-dependencies版本进行摘记。 (P.S. 只管Hoxton版本当初仍然处于反对中,不过依照NetFIix在新版本中的改变来看,兴许这一套解决方案被弃用是迟早的事件) 二、我的项目的组成1.我的项目的集成办法SpringCloud我的项目由一个总的pom.xml负责管理我的项目中可能会用到的所有依赖,这样治理的作用是不便版本的对立。子模块在应用雷同的依赖时,不用指定依赖的版本,因为这些版本曾经在总的pom.xml中指定好了。 在一个我的项目总的pom.xml中,咱们能够应用<dependencyManagement></dependencyManagement>标签对所有依赖进行治理,此时,在这之中的所有<dependency></dependency>将不会被导入,而是由子模块继承总的pom.xml并应用相干依赖后才会导入到相应的子模块中。 例如,下方展现的是总的pom.xml <?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 http://maven.apache.org/xsd/maven-4.0.0.xsd"> <modelVersion>4.0.0</modelVersion> <groupId>org.example</groupId> <artifactId>springclouddemo</artifactId> <version>1.0-SNAPSHOT</version> <modules> <module>springcloud-api</module> <module>springcloud-provider-dept-8001</module> <module>springcloud-consumer-dept-80</module> <module>springcloud-eureka-7001</module> <module>springcloud-eureka-7002</module> <module>springcloud-eureka-7003</module> <module>springcloud-provider-dept-8002</module> <module>springcloud-provider-dept-8003</module> <module>springcloud-consumer-dept-feign</module> <module>springcloud-provider-dept-hystrix-8001</module> <module>springcloud-consumer-hystrix-dashboard</module> <module>springcloud-zuul</module> <module>springcloud-config-server-3344</module> <module>spingcloud-config-client-3355</module> <module>springcloud-config-eureka-7001</module> <module>springcloud-config-dept-8001</module> </modules> <properties> <maven.compiler.source>8</maven.compiler.source> <maven.compiler.target>8</maven.compiler.target> <junit.version>4.12</junit.version> <druid.version>1.1.10</druid.version> <lombok.version>1.18.22</lombok.version> </properties> <packaging>pom</packaging> <dependencyManagement> <dependencies> <!-- https://mvnrepository.com/artifact/org.springframework.cloud/spring-cloud-dependencies --> <dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-dependencies</artifactId> <version>Hoxton.SR8</version> <type>pom</type> <scope>import</scope> </dependency> <!-- https://mvnrepository.com/artifact/org.springframework.boot/spring-boot-dependencies --> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-dependencies</artifactId> <version>2.3.4.RELEASE</version> <type>pom</type> <scope>import</scope> </dependency> <dependency> <groupId>mysql</groupId> <artifactId>mysql-connector-java</artifactId> <version>8.0.23</version> </dependency> <!-- https://mvnrepository.com/artifact/com.alibaba/druid --> <dependency> <groupId>com.alibaba</groupId> <artifactId>druid</artifactId> <version>${druid.version}</version> </dependency> <dependency> <groupId>org.mybatis.spring.boot</groupId> <artifactId>mybatis-spring-boot-starter</artifactId> <version>2.2.1</version> </dependency> <!--日志测试--> <dependency> <groupId>junit</groupId> <artifactId>junit</artifactId> <version>${junit.version}</version> </dependency> <dependency> <groupId>log4j</groupId> <artifactId>log4j</artifactId> <version>1.2.12</version> </dependency> <dependency> <groupId>ch.qos.logback</groupId> <artifactId>logback-core</artifactId> <version>1.2.7</version> </dependency> <dependency> <groupId>org.projectlombok</groupId> <artifactId>lombok</artifactId> <version>${lombok.version}</version> </dependency> </dependencies> </dependencyManagement></project>下方展现的是某一子模块对父pom.xml的继承和应用 ...

February 6, 2022 · 5 min · jiezi

关于spring-cloud:阿里神器Seata集成TCC模式解决分布式事务

大家好,我是不才陈某~ 这是《Spring Cloud 进阶》第19篇文章,往期文章如下: 五十五张图通知你微服务的灵魂摆渡者Nacos到底有多强?openFeign夺命连环9问,这谁受得了?阿里面试这样问:Nacos、Apollo、Config配置核心如何选型?这10个维度通知你!阿里面试败北:5种微服务注册核心如何选型?这几个维度通知你!阿里限流神器Sentinel夺命连环 17 问?比照7种分布式事务计划,还是偏爱阿里开源的Seata,真香!(原理+实战)Spring Cloud Gateway夺命连环10问?Spring Cloud Gateway 整合阿里 Sentinel网关限流实战!分布式链路追踪之Spring Cloud Sleuth夺命连环9问?链路追踪自从用了SkyWalking,睡的真香!3本书了,7万+字,10篇文章,《Spring Cloud 进阶》根底版 PDF妹子始终没搞懂OAuth2.0,明天整合Spring Cloud Security 一次说明确!OAuth2.0实战!应用JWT令牌认证!OAuth2.0实战!玩转认证、资源服务异样自定义这些骚操作!实战干货!Spring Cloud Gateway 整合 OAuth2.0 实现分布式对立认证受权!字节面试这样问:跨库多表存在大量数据依赖问题有哪些解决方案?实战!退出登录时如何借助外力使JWT令牌生效?实战!Spring Cloud Gateway集成 RBAC 权限模型实现动静权限管制!明天这篇文章介绍一下Seata如何实现TCC事务模式,文章目录如下: 什么是TCC模式?TCC(Try Confirm Cancel)计划是一种利用层面侵入业务的两阶段提交。是目前最火的一种柔性事务计划,其核心思想是:针对每个操作,都要注册一个与其对应的确认和弥补(撤销)操作。 TCC分为两个阶段,别离如下: 第一阶段:Try(尝试),次要是对业务零碎做检测及资源预留 (加锁,锁住资源)第二阶段:本阶段依据第一阶段的后果,决定是执行confirm还是cancel Confirm(确认):执行真正的业务(执行业务,开释锁)Cancle(勾销):是预留资源的勾销(出问题,开释锁) 为了不便了解,上面以电商下单为例进行计划解析,这里把整个过程简略分为扣减库存,订单创立 2 个步骤,库存服务和订单服务别离在不同的服务器节点上。 假如商品库存为 100,购买数量为 2,这里检查和更新库存的同时,解冻用户购买数量的库存,同时创立订单,订单状态为待确认。 ①Try 阶段TCC 机制中的 Try 仅是一个初步操作,它和后续的确认一起能力真正形成一个残缺的业务逻辑,这个阶段次要实现: 实现所有业务查看( 一致性 ) 。预留必须业务资源( 准隔离性 ) 。Try 尝试执行业务。 ②Confirm / Cancel 阶段依据 Try 阶段服务是否全副失常执行,继续执行确认操作(Confirm)或勾销操作(Cancel)。 Confirm 和 Cancel 操作满足幂等性,如果 Confirm 或 Cancel 操作执行失败,将会一直重试直到执行实现。 ...

January 18, 2022 · 2 min · jiezi

关于springcloud:SpringCloud之WebSocket配置的最佳方式

前言最近我的项目中有个私信性能,须要用到websocket,于是在网上找找材料并在实践中总结了一点教训分享给大家。 问题在操作之前我先抛一个问题: SpringBoot我的项目集成 webSocket,当客户端与服务器端建设连贯的时候,发现 server对象并未注入而是为 null。产生起因:spring治理的都是单例(singleton),和 websocket (多对象)相冲突。具体解释:我的项目启动时初始化,会初始化 websocket (非用户连贯的),spring 同时会为其注入 service,该对象的 service 不是 null,被胜利注入。然而,因为 spring 默认治理的是单例,所以只会注入一次 service。当客户端与服务器端进行连贯时,服务器端又会创立一个新的 websocket 对象,这时问题呈现了:spring 治理的都是单例,不会给第二个 websocket 对象注入 service,所以导致只有是用户连贯创立的 websocket 对象,都不能再注入了。像 controller 外面有 service, service 外面有 dao。因为 controller,service ,dao 都有是单例,所以注入时不会报 null。然而 websocket 不是单例,所以应用spring注入一次后,前面的对象就不会再注入了,会报NullException。上面会讲解决办法。 操作1、引入websocket依赖包 <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-websocket</artifactId></dependency>2、配置websocket @Configuration@EnableWebSocketpublic class WebSocketConfig implements WebSocketConfigurer { @Override public void registerWebSocketHandlers(WebSocketHandlerRegistry webSocketHandlerRegistry) { // webSocket通道 // 指定处理器和门路,如:http://www.baidu.com/service-name/websocket?uid=xxxx webSocketHandlerRegistry.addHandler(new WebSocketHandler(), "/websocket")// // 指定自定义拦截器 .addInterceptors(new WebSocketInterceptor()) // 容许跨域 .setAllowedOrigins("*"); }}3、增加获取websocket地址中的参数类 ...

January 14, 2022 · 4 min · jiezi

关于springcloud:SpringCloud之使用Feign跨服务调用最佳方式

前言最近在学习如何应用springcloud,当学习到跨服务调用接口时接触到Feign和Ribbon,网上有好多文章是介绍他们俩的区别的,有趣味的能够看看,本文次要举荐应用Feign并记录操作过程。 Feign和Ribbon比照RibbonRibbon 是一个基于 HTTP 和 TCP 客户端的负载均衡器它能够在客户端配置 ribbonServerList(服务端列表),而后轮询申请以实现平衡负载它在联结 Eureka 应用时ribbonServerList 会被 DiscoveryEnabledNIWSServerList 重写,扩大成从 Eureka 注册核心获取服务端列表同时它也会用 NIWSDiscoveryPing 来取代 IPing,它将职责委托给 Eureka 来确定服务端是否曾经启动 FeignSpring Cloud Netflix 的微服务都是以 HTTP 接口的模式裸露的,所以能够用 Apache 的 HttpClient 或 Spring 的 RestTemplate 去調用而 Feign 是一個应用起來更加不便的 HTTP 客戶端总结起来就是:公布到注册核心的服务方接口,是 HTTP 的,也能够不必 Ribbon 或者 Feign,间接浏览器一样可能拜访只不过 Ribbon 或者 Feign 调用起来要不便一些,最重要的是:它俩都反对软负载平衡留神:spring-cloud-starter-feign 外面曾经蕴含了 spring-cloud-starter-ribbon(Feign 中也应用了 Ribbon)从实际上看,采纳feign的形式更优雅(feign外部也应用了ribbon做负载平衡)。 操作1、引入feign依赖包 <dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-starter-openfeign</artifactId></dependency>2、启用feign:@EnableFeignClients @SpringBootApplication// 资源爱护服务@EnableResourceServer// 服务发现@EnableDiscoveryClient// 启用feign@EnableFeignClients@RefreshScopepublic class NofityServiceApplication { @Bean public BCryptPasswordEncoder passwordEncoder() { return new BCryptPasswordEncoder(); } public static void main(String[] args) { SpringApplication.run(NofityServiceApplication.class, args); }}3、配置feign传递token ...

January 14, 2022 · 1 min · jiezi

关于springcloud:Spring-Cloud-OpenFeign-超时与重试

明天给大家分享的是 feign 的超时与重试配置。 超时feign: client: config: default: connectTimeout: 1000 readTimeout: 1000须要留神以下几点: 1、连贯超时 (connectTimeout) 和 读取超时 (readTimeout) 同时配置时,才会失效。 2、超时单位为毫秒。 3、可依据服务名称独自定义超时。 比方, provider-get 服务提供的是查问接口,超时工夫能够设置短一些: feign: client: config: provider-get: connectTimeout: 1000 readTimeout: 6000而, provider-post 服务提供的是数据处理接口,超时工夫能够设置长一些: feign: client: config: provider-post: connectTimeout: 1000 readTimeout: 20000重试实现 feign.Retryer 接口 public class MyRetryer implements Retryer { @Override public void continueOrPropagate(RetryableException e) { throw e; } @Override public Retryer clone() { return new Default(100, TimeUnit.SECONDS.toMillis(1), 5); }}三个参数的了解: period:周期,重试间隔时间maxPeriod:最大周期,重试间隔时间依照肯定的规定逐步增大,但不能超过最大周期maxAttempts:最大尝试次数,重试次数之后,咱们能够进行配置: ...

January 11, 2022 · 1 min · jiezi

关于spring-cloud:实现微服务预热调用之后再开始服务下

持续剖析其余接入点。 其余须要初始化的接入点剖析咱们有时候还须要做一些自定义的初始化操作,然而如何在注册到注册核心状态为 UP 也就是开始解决申请之前做这些操作呢? 为了更加与云环境兼容,Spring Boot 从 2.3.0 版本之后引入了一些云上部署相干的概念: LivenessState(存活状态):就应用程序而言,存活状态是指应用程序的状态是否失常。如果存活状态不失常,则意味着应用程序自身已损坏,无奈复原。在 k8s 中,如果存活检测失败,则 kubelet 将杀死 Container,并且依据其重新启动策略进行重启: 在 spring boot 中对应的接口是 /actuator/health/liveness对应的枚举类是 org.springframework.boot.availability.LivenessState,包含上面两个状态: CORRECT:存活状态失常BROKEN:存活状态不失常Readiness(就绪状态):指的是应用程序是否已筹备好承受并解决客户端申请。出于任何起因,如果应用程序尚未筹备好解决服务申请,则应将其申明为忙碌,直到可能失常响应申请为止。如果 Readiness 状态尚未就绪,则不应将流量路由到该实例。在 k8s 中,如果就绪检测失败,则 Endpoints 控制器将从 Endpoints 中删除这个 Pod 的 IP 地址,如果你没有应用 k8s 的服务发现的话,就不必太关怀这个: 在 spring boot 中对应的接口是 /actuator/health/readiness对应的枚举类是 org.springframework.boot.availability.ReadinessState,包含上面两个状态: ACCEPTING_TRAFFIC:筹备好承受申请REFUSING_TRAFFIC:目前不能承受申请了默认状况下,Spring Boot 在初始化过程中会批改这些状态,对应源码(咱们只关怀 listeners 相干,这些标记着 Spring Boot 生命周期变动): SpringApplication.java public ConfigurableApplicationContext run(String... args) { StopWatch stopWatch = new StopWatch(); stopWatch.start(); DefaultBootstrapContext bootstrapContext = createBootstrapContext(); ConfigurableApplicationContext context = null; configureHeadlessProperty(); SpringApplicationRunListeners listeners = getRunListeners(args); //通知所有 Listener 启动中 listeners.starting(bootstrapContext, this.mainApplicationClass); try { ApplicationArguments applicationArguments = new DefaultApplicationArguments(args); ConfigurableEnvironment environment = prepareEnvironment(listeners, bootstrapContext, applicationArguments); configureIgnoreBeanInfo(environment); Banner printedBanner = printBanner(environment); context = createApplicationContext(); context.setApplicationStartup(this.applicationStartup); prepareContext(bootstrapContext, context, environment, listeners, applicationArguments, printedBanner); refreshContext(context); afterRefresh(context, applicationArguments); stopWatch.stop(); if (this.logStartupInfo) { new StartupInfoLogger(this.mainApplicationClass).logStarted(getApplicationLog(), stopWatch); } //通知所有 Listener 启动实现 listeners.started(context); //调用各种 SpringRunners + CommandRunners callRunners(context, applicationArguments); } catch (Throwable ex) { handleRunFailure(context, ex, listeners); throw new IllegalStateException(ex); } try { //告诉所有 Listener 运行中 listeners.running(context); } catch (Throwable ex) { handleRunFailure(context, ex, null); throw new IllegalStateException(ex); } return context;}其中,listeners.started 和 listeners.running 外面做的事件是: ...

January 2, 2022 · 2 min · jiezi

关于spring-cloud:实现微服务预热调用之后再开始服务上

最近线上发现一个景象,利用实例刚刚启动的时候,开始接管申请之后产生了一小段时间的申请阻塞,从 HTTP Servlet 申请队列监控上能够看出(基于 spring-web 的一般阻塞的 HTTP 服务器是有 HTTP 线程池的,当线程是满了之后,申请在阻塞队列中期待解决。基于 spring-webflux 的没有这个景象,然而思考的背压问题其实和这个场景相似): 而后阻塞数量很快就上来了,通过 JFR 发现和 Spring 各种懒加载的 Bean,各种资源或者连接池初始化等无关。这些资源能够了解为是懒加载的,是在申请真正用到的时候才会初始化。这些资源初始化之前,微服务就曾经注册到注册核心并开始承受申请了。这样在平时业务低峰公布的时候,是没有问题的,因为这些资源的初始化耗时也就在几十到几百毫秒之间。然而在业务顶峰须要动静扩容的时候,就会受一些影响,因为申请压力会立即大量打到这些新启动的实例上,这种状况下,初始化耗时的影响就比拟大了。 所以,咱们心愿在微服务开始真正提供服务之前,将这些比拟耗时的须要初始化的资源提前初始化实现之后,再通知注册核心咱们能够开始承受解决申请了。 Spring Boot 中的 MVC Servlet 与 Web Service Servlet 的提前初始化在微服务实例启动后,咱们发送第一个申请的时候,会看到相似于上面的日志: INFO: Initializing Servlet 'dispatcherServlet'INFO: Initializing Spring DispatcherServlet 'dispatcherServlet'这是在初始化 Servlet。 MVC Servlet 指的就是 Spring-MVC 的 Servlet,其实就是提供 HTTP 服务的一些外围 Servlet,例如最外围的 org.springframework.web.servlet.DispatcherServlet。这些默认是懒加载的,须要通过上面的配置关上: spring.mvc.servlet.load-on-startup: 1除了 MVC Servlet,另一些 Servlet 可能是提供除了 HTTP 以外的其余利用协定的 Servlet,这些 Servlet 默认也是懒加载的,须要通过上面的配置关上: spring.webservices.servlet.load-on-startup: 1例如 WebSocket 的 org.springframework.ws.transport.http.MessageDispatcherServlet 就是通过这个配置进行初始化的。 spring-data-redis 连接池的初始化咱们我的项目中应用的是 spring-data-redis + lettuce。如果没有应用 Pipeline 等须要独占连贯的 redis 操作,其实不必应用连接池。然而咱们在应用中为了效率,尽量都是用 Pipeline,所以咱们都启用了连接池配置。其连接池实现基于 common-pools2 库。相干配置如下所示: ...

January 1, 2022 · 2 min · jiezi

关于spring-cloud:实战干货Spring-Cloud-Gateway-整合-OAuth20-实现分布式统一认证授权

大家好,我是不才陈某~ 这是《Spring Cloud 进阶》第15篇文章,往期文章如下: 五十五张图通知你微服务的灵魂摆渡者Nacos到底有多强?openFeign夺命连环9问,这谁受得了?阿里面试这样问:Nacos、Apollo、Config配置核心如何选型?这10个维度通知你!阿里面试败北:5种微服务注册核心如何选型?这几个维度通知你!阿里限流神器Sentinel夺命连环 17 问?比照7种分布式事务计划,还是偏爱阿里开源的Seata,真香!(原理+实战)Spring Cloud Gateway夺命连环10问?Spring Cloud Gateway 整合阿里 Sentinel网关限流实战!分布式链路追踪之Spring Cloud Sleuth夺命连环9问?链路追踪自从用了SkyWalking,睡的真香!3本书了,7万+字,10篇文章,《Spring Cloud 进阶》根底版 PDF妹子始终没搞懂OAuth2.0,明天整合Spring Cloud Security 一次说明确!OAuth2.0实战!应用JWT令牌认证!OAuth2.0实战!玩转认证、资源服务异样自定义这些骚操作!明天这篇文章介绍一下Spring Cloud Gateway整合OAuth2.0实现认证受权,波及到的知识点有点多,有不分明的能够看下陈某的往期文章。 文章目录如下: 微服务认证计划微服务认证计划目前有很多种,每个企业也是大不相同,然而总体分为两类,如下: 网关只负责转发申请,认证鉴权交给每个微服务管制对立在网关层面认证鉴权,微服务只负责业务你们公司目前用的哪种计划? 先来说说第一种计划,有着很大的弊病,如下: 代码耦合重大,每个微服务都要保护一套认证鉴权无奈做到对立认证鉴权,开发难度太大第二种计划显著是比较简单的一种,长处如下: 实现了对立的认证鉴权,微服务只须要各司其职,专一于本身的业务代码耦合性低,不便后续的扩大上面陈某就以第二种计划为例,整合Spring Cloud Gateway+Spring Cloud Security 整合出一套对立认证鉴权案例。 案例架构开始撸代码之前,先来说说大抵的认证鉴权流程,架构如下图: 大抵分为四个角色,如下: 客户端:须要拜访微服务资源网关:负责转发、认证、鉴权OAuth2.0受权服务:负责认证受权颁发令牌微服务汇合:提供资源的一系列服务。大抵流程如下: 1、客户端发出请求给网关获取令牌 2、网关收到申请,间接转发给受权服务 3、受权服务验证用户名、明码等一系列身份,通过则颁发令牌给客户端 4、客户端携带令牌申请资源,申请间接到了网关层 5、网关对令牌进行校验(验签、过期工夫校验....)、鉴权(对以后令牌携带的权限)和拜访资源所需的权限进行比对,如果权限有交加则通过校验,间接转发给微服务 6、微服务进行逻辑解决 针对上述架构须要新建三个服务,别离如下: 名称性能oauth2-cloud-auth-serverOAuth2.0认证受权服oauth2-cloud-gateway网关服务oauth2-cloud-order-service订单资源服务案例源码目录如下: 认证受权服务搭建很多企业是将认证受权服务间接集成到网关中,这么做耦合性太高了,这里陈某间接将认证受权服务抽离进去。 认证服务的搭建这里就不再细说了,上一篇文章中曾经介绍的很分明了:OAuth2.0实战!应用JWT令牌认证! 新建一个oauth2-cloud-auth-server模块,目录如下: 和上篇文章不同的是创立了JwtTokenUserDetailsService这个类,用于从数据库中加载用户,如下: 为了演示只是模仿了从数据库中查问,其中存了两个用户,如下: user:具备ROLE_user权限admin:具备ROLE_admin、ROLE_user权限要想这个失效,还要在security的配置文件SecurityConfig中指定,如下图: 另外还整合了注册核心Nacos,具体配置就不贴了,能够看源码。有不分明Nacos,能够看之前文章:五十五张图通知你微服务的灵魂摆渡者Nacos到底有多强? 案例源码曾经上传GitHub,关注公众号:码猿技术专栏,回复关键词:9529 获取!网关服务搭建网关应用的是Spring Cloud Gateway,网关如何搭建这里就不再细说了,有不分明的能够看之前文章:Spring Cloud Gateway夺命连环10问? 新建一个oauth2-cloud-gateway模块,目录如下图: 1、增加依赖须要增加几个OAuth2.0相干的依赖,如下: 2、JWT令牌服务配置应用JWT令牌,配置要和认证服务的令牌配置雷同,代码如下: ...

December 23, 2021 · 1 min · jiezi

关于springcloud:Spring-Cloud基础之Hystrix熔断器

首先须要在Discovery Service章节中的创立Discovery Server服务创立weather-service服务 //导入包,理论是通过Spring Initializr导入的,Eureka Discovery,Spring Webspring-boot-starter-webspring-cloud-starter-netflix-eureka-client//配置启动类注解@SpringBootApplication@RestController@EnableDiscoveryClientpublic class WeatherServiceApplication { private String[] weather = new String[] {"sunny", "cloudy","rainy","windy"}; public static void main(String[] args) { SpringApplication.run(WeatherServiceApplication.class, args); } @GetMapping("/weather") public String getWeather(){ int rand = ThreadLocalRandom.current().nextInt(0,4); return weather[rand]; }}//配置文件server.port=9000spring.application.name=weather-serviceeureka.client.service-url.defaultZone=http://localhost:8761/eureka创立weather-app服务 //导入包,理论是通过Spring Initializr导入的,Eureka Discovery,Spring Web,Hystrix,Actuatorspring-boot-starter-webspring-cloud-starter-netflix-eureka-client//配置启动类注解@SpringBootApplication@EnableDiscoveryClient@EnableCircuitBreaker@RestControllerpublic class WeatherAppApplication { @Autowired public WeatherService weatherService; public static void main(String[] args) { SpringApplication.run(WeatherAppApplication.class, args); } @Bean @LoadBalanced public RestTemplate restTemplate(){ return new RestTemplate(); } @GetMapping("/current/weather") public String getWeather(){ return "The current weather is " +weatherService.getWeather(); }}//配置业务类,HystrixCommand配置了fallbackMethod办法为unknown@Servicepublic class WeatherService { @Autowired private RestTemplate restTemplate; @HystrixCommand(fallbackMethod = "unknown") public String getWeather() { return restTemplate.getForEntity("http://weather-service/weather",String.class).getBody(); } public String unknown(){ return "unknown"; }}//配置文件server.port=8000spring.application.name=weather-appeureka.client.service-url.defaultZone=http://localhost:8761/eureka//通过拜访http://localhost:8000/current/weather//当weather服务down掉时,输入The current weather is unknown//当weather服务ok时,输入The current weather is windy配置hystirx-dashboard服务 ...

December 15, 2021 · 1 min · jiezi

关于springcloud:Sentinel之流控规则

在上文Sentinel流量防守兵中讲到了Sentinel入门以及流控规定一小部分,而Sentinel还有以下规定: 熔断降级规定热点参数规定零碎规定黑白名单规定本文要讲的是流控规定 流量管制规定原理监控利用流量的 QPS 或并发线程数等指标,当达到指定的阈值时对流量进行管制,以防止被刹时的流量顶峰冲垮,从而保障利用的高可用性。 QPS限流这里咱们拜访一下/foo/test接口,触发Sentinel控制台初始化,就能够看到在簇点链路中刷新出了该接口的资源 而后咱们点击+流控增加流控规定,抉择QPS,并且限流为2 在高级选项中还有流控模式和流控成果两个抉择,默认为间接和疾速失败,具体含意见上面解释新增之后,在页面上疾速点击几次,就会看到咱们之前预设好的限流提醒 流控成果流控成果只针对于QPS的流量管制 疾速失败当QPS超过任意规定的阈值后,新的申请就会被立刻回绝,回绝形式为抛出FlowException。这种形式实用于对系统解决能力确切已知的状况下,比方通过压测确定了零碎的精确水位时。 案例见上 Warm Up预热/冷启动形式,当零碎长期处于低水位的状况下,当流量忽然减少时,间接把零碎拉升到高水位可能霎时把零碎压垮。通过"冷启动",让通过的流量迟缓减少,在肯定工夫内逐步减少到阈值下限,给冷零碎一个预热的工夫,防止冷零碎被压垮。 在控制台中删除到刚刚测试的疾速失败规定,新增一个Warm up成果的规定 这里我设置的qps阈值为10,预热3秒,等效于想要达到10qps,须要预热3秒。 这里测试须要用到一些压测工具,比方我用的是jmeter,毕竟在3秒内每秒连点10下我是做不到,认为本人行的能够本人试试。 以10qps进行压测之后,能够实时监控中看到这么一张效果图 在右边的线性图中能够看到通过的qps(绿线)是在匀速回升状态,直到3秒后达到10变为安稳状态,具体的数值能够从左边的表格看到。 排队期待排队期待即为匀速排队,该形式会严格控制申请通过的间隔时间,也即是让申请以平均的速度通过,对应的是漏桶算法。 同样的,在控制台新增规定 排队期待的阈值最高只能配1000哦,至于为什么小伙伴就本人想啦以12qps进行压测,查看实时监控面板 qps始终放弃在10, 规定失效了流控模式流控模式和调用关系无关,调用关系包含调用方、被调用方;一个办法又可能会调用其它办法,造成一个调用链路的档次关系。 间接依据调用起源进行限流,默认为default,即针对所有的起源,这外面还能够配置自定义的起源。 1.自定义起源自定义起源须要批改咱们的配置代码,更改形式如下 private void addSpringMvcInterceptor(InterceptorRegistry registry) { SentinelWebMvcConfig config = new SentinelWebMvcConfig(); config.setBlockExceptionHandler(new MyBlockExceptionHandler()); // 辨别申请形式 config.setHttpMethodSpecify(true); // 申请起源解析 config.setOriginParser(request -> request.getHeader("User-Agent")); registry.addInterceptor(new SentinelWebInterceptor(config)).addPathPatterns("/**");}在原来的配置中减少起源解析的配置,比方我这里就是获取申请头中的User-Agent作为申请起源,你也能够依据本人的需要决定,比方获取客户端的ip批改结束后,重启服务,在控制台新增一个起源为test的规定 而后在申请上加上User-Agent的header,测试 这里如果把User-Agent换成其余的,则不会被限流2. 其余其余的意思除了指定的起源都会被限流,看到这里的就会让人有所疑难 控制台减少了other起源的配置,之前的test起源就不会限流了吗?其实它的意思是这样的:除了test起源的申请,其余起源的qps都不能超过其余这条配置,举个例子 test起源限流的qps为2,other起源限流的qps为1,那么此时如果是来自test2起源的申请,qps超过1则会提醒已被限流,test起源的申请仍旧是超过2之后才会提醒被限流。 在控制台减少一条其余起源的配置 设置User-Agent为test2进行测试 能够看到,我这里只申请了1次就被限流了关联关联这个模式指的是如果一个资源被两个接口所拜访,那么在一个接口超过qps阈值时,能够对另一个接口进行限流。 举个例子来说,FooService同时被A接口和B接口所拜访,因为FooService总体可能承受的qps是恒定的,如果A接口qps过高,那么B接口的就会受到影响,如果咱们想要B接口优先,此时咱们就能够配置一条当B接口超过qps阈值时,就把A接口限流。 听起来是不是特地顺当, 如果这俩接口有思考能力,我自行脑补出了以下场景: ...

December 13, 2021 · 1 min · jiezi

关于springcloud:Spring-Cloud基础之Config-Server配置中心简单搭建

首先须要在Discovery Service章节中的创立Discovery Server服务创立Config Server服务 //导入包,理论是通过Spring Initializr导入的,Eureka Discovery,Config Server,Actuactorspring-cloud-config-serverspring-cloud-starter-netflix-eureka-serverspring-boot-starter-actuator//配置启动类注解EnableConfigServer@SpringBootApplication@EnableConfigServer@EnableDiscoveryClientpublic class ConfigServerApplication { public static void main(String[] args) { SpringApplication.run(ConfigServerApplication.class, args); }}//配置文件server.port=8888spring.cloud.config.server.git.uri=https://github.com/bu6030/scf-config-repository.gitspring.application.name=config-servereureka.client.service-url.defaultZone=http://localhost:8761/eureka启动时须要默认的SpringCloudserver曾经启动通过url能够找到对应的配置内容 //配置的Endpoint规定几种形式GET /{application}/{profile}[/{label}]/myap/dev/master,/myapp/prod/v2,/myapp/defaultGET /{application}-{profile}.(yml | properties)/myapp-dev.yml,/myapp-prod.properties,/myapp-default.propertiesGET /{label}-{application}-{profile}.(yml | properties)/master/myapp-dev.yml,/v2/myapp-prod.properties,/master/myapp-default.properties//http://localhost:8888/config-client-app.yml返回内容:some: other: property: global property: app specific overridden value//http://localhost:8888/config-client-app.properties返回内容some.other.property: globalsome.property: app specific overridden value//http://localhost:8888/config-client-app/prod返回内容{ "name": "config-client-app", "profiles": [ "prod" ], "label": null, "version": "1cb37c9ba1fa4c17d2ae7489c2e592eba1688547", "state": null, "propertySources": [ { "name": "https://github.com/bu6030/scf-config-repository.git/config-client-app-prod.properties", "source": { "some.property": "profile specific value", "some.other.property": "profile specific value" } }, { "name": "https://github.com/bu6030/scf-config-repository.git/config-client-app.properties", "source": { "some.property": "app specific overridden value" } }, { "name": "https://github.com/bu6030/scf-config-repository.git/application.properties", "source": { "some.property": "global", "some.other.property": "global" } } ]}//http://localhost:8888/config-client-app/default返回内容{ "name": "config-client-app", "profiles": [ "default" ], "label": null, "version": "1cb37c9ba1fa4c17d2ae7489c2e592eba1688547", "state": null, "propertySources": [ { "name": "https://github.com/bu6030/scf-config-repository.git/config-client-app.properties", "source": { "some.property": "app specific overridden value" } }, { "name": "https://github.com/bu6030/scf-config-repository.git/application.properties", "source": { "some.property": "global", "some.other.property": "global" } } ]}配置config client ...

December 9, 2021 · 2 min · jiezi

关于springcloud:Spring-Cloud基础之Discovery-Service服务发现简单搭建

1.创立Discovery Server服务 //导入包,理论是通过Spring Initializr导入的,Eureka Server,DevTools,Actuactorspring-boot-devtoolsspring-cloud-starter-netflix-eureka-serverspring-boot-starter-actuator//配置启动类注解EnableEurekaServer@EnableEurekaServer@SpringBootApplicationpublic class DiscoveryServerApplication { public static void main(String[] args) { SpringApplication.run(DiscoveryServerApplication.class, args); }}//此时启动会报错,须要配置spring.application.name=discovery-servereureka.client.register-with-eureka=falseeureka.client.fetch-registry=falseserver.port=87612.创立Service服务 //导入包,理论是通过Spring Initializr导入的,Eureka Discovery,DevTools,Actuactorspring-cloud-starter-netflix-eureka-clientspring-boot-starter-actuatorspring-boot-devtools//配置启动类注解EnableDiscoveryClient@EnableDiscoveryClient@SpringBootApplication@RestControllerpublic class ServiceApplication { @Value("${service.instance.name}") private String instance; public static void main(String[] args) { SpringApplication.run(ServiceApplication.class, args); } @RequestMapping("/") public String message(){ return "Hello from " + instance; }}//配置文件spring.application.name=serviceeureka.client.service-url.defaultZone=http://localhost:8761/eureka3.别离配置两个启动服务,每个配置端口以及节点名称,第一个为instance1 8081,第二个为instance2 8082 //第一个节点配置service.instance.name= instance 1server.port=8081//第二个节点配置service.instance.name= instance 2server.port=80824.启动后,两个servic日志中会显示204,示意注册胜利 2020-04-11 21:51:03.000 INFO 964 --- [nfoReplicator-0] com.netflix.discovery.DiscoveryClient : DiscoveryClient_SERVICE/localhost:service:8081: registering service...2020-04-11 21:51:03.072 INFO 964 --- [nfoReplicator-0] com.netflix.discovery.DiscoveryClient : DiscoveryClient_SERVICE/localhost:service:8081 - registration status: 2045.server端会显示两个节点注册胜利 ...

December 8, 2021 · 1 min · jiezi

关于springcloud:Sentinel流量防卫兵

前言在咱们平时工作中,总会有这样的事件产生:服务无奈接受过多的申请而被打挂。 个别咱们能够从两个方面解决: 减少节点,程度扩大(钱总是万能的)对申请量过高的接口进行限流(没钱也不是不能够)突发状况下咱们会先用第一种计划,而后再过渡到第二种。毕竟:穷就一个字 随着这样的事件产生多了,零碎就会能够预计的朝这样的方向演变: 单个接口的限流 -> 多个接口的限流 沉睡能力:限流能够配置,想要对哪个接口进行限流,就改下配置,立刻失效。 单个零碎须要限流 -> 多个零碎须要限流 沉睡能力:限流性能组件化,后续还有零碎须要限流性能,引入依赖即可,不须要反复开发。 等等通过这样的推论:每个零碎都会产生高并发 -> 每个零碎都会朝这个方向演变 -> 总有演变了很久的零碎 -> 网上是否曾经存在这样的轮子? 别说,真的有!明天咱们要意识的配角Sentinel就是这样的又大又圆的轮子~ 介绍随着微服务的风行,服务和服务之间的稳定性变得越来越重要。Sentinel 是面向分布式服务架构的流量管制组件,次要以流量为切入点,从流量管制、熔断降级、零碎自适应爱护等多个维度来帮忙您保障微服务的稳定性。 官网地址:https://sentinelguard.io/zh-cn/ 话不多说,先来个案例感触感触 案例需要:要求每秒钟通过的qps限定在20 注:案例中所有统计相干的代码只是为了更加直观的体现sentinel的作用 引入依赖: <dependency> <groupId>com.alibaba.csp</groupId> <artifactId>sentinel-core</artifactId> <version>1.8.2</version></dependency>1. 定义流控规定private void initFlowRules() { // 定义流控规定 FlowRule rule = new FlowRule(); // 资源名与须要限流的资源名雷同 rule.setResource("HelloWorld"); // 设置限流形式为QPS rule.setGrade(RuleConstant.FLOW_GRADE_QPS); // 设置QPS为20 rule.setCount(20); // 加载规定 FlowRuleManager.loadRules(Collections.singletonList(rule));}2. 模仿申请// 记录申请总数private static final AtomicInteger TOTAL = new AtomicInteger();// 记录申请通过数private static final AtomicInteger PASS = new AtomicInteger();// 记录申请回绝数private static final AtomicInteger BLOCK = new AtomicInteger();private void request() { for (int i = 0; i < 30; i++) { new Thread(() -> { while (true){ // 记录总qps TOTAL.incrementAndGet(); // 进行限流 try (Entry entry = SphU.entry("HelloWorld")) { // 记录通过数 PASS.incrementAndGet(); } catch (BlockException e) { // 记录回绝数 BLOCK.incrementAndGet(); } // 模仿业务期待0-50毫秒 try { TimeUnit.MILLISECONDS.sleep(new Random().nextInt(50)); } catch (InterruptedException ignored) { } } }).start(); }}3. 统计public void count() { new Thread(() -> { int oldTotal = 0, oldPass = 0, oldBlock = 0; while (true){ // 计算以后qps int total = TOTAL.get(); int secondsTotal = total - oldTotal; oldTotal = total; // 计算每秒通过数 int pass = PASS.get(); int secondsPass = pass - oldPass; oldPass = pass; // 计算每秒回绝数 int block = BLOCK.get(); int secondsBlock = block - oldBlock; oldBlock = block; log.info("以后qps:{}, pass: {}, block:{}", secondsTotal, secondsPass, secondsBlock); try { // 进展一秒 TimeUnit.SECONDS.sleep(1); } catch (InterruptedException ignored) { } } }).start();}4.测试@Testpublic void testBlock() throws IOException { // 初始化规定 this.initFlowRules(); // 模仿高并发拜访 this.request(); // 统计qps this.count(); // 避免程序终止 System.in.read();}5.测试后果 ...

December 6, 2021 · 3 min · jiezi

关于spring-cloud:SpringCloud升级之路20200x版45-实现公共日志记录

本系列代码地址:https://github.com/JoJoTec/sp...咱们这一节在后面实现的带有链路信息的 Publisher 的工厂的根底上,实现公共日志记录的 GlobalFilter。回顾下咱们的需要: 咱们须要在网关记录每个申请的: HTTP 相干元素: URL 相干信息申请信息,例如 HTTP HEADER,申请工夫等等某些类型的申请体响应信息,例如响应码某些类型响应的响应体链路信息记录申请与响应的 Body 须要留神的中央后面的章节咱们提到过,对于申请与响应的 body 解决,如果用其后果放入主链路的话,会造成 Spring Cloud Sleuth 的链路信息失落。还有两个要留神的中央是: TCP 粘包拆包导致一个申请体宰割成好几份或者一个包蕴含几个申请读取后要开释本来的申请 body 读取进去的 DataBuffer为何要开释本来的申请 body 读取进去的 DataBuffer?因为读取进去后占用的 DataBuffer 如果手动不开释那么底层的计数始终不归零会造成内存透露。能够参考框架代码看出,这里的 DataBuffer 是须要手动开释的,参考源码: ByteBufferDecoder.java @Overridepublic ByteBuffer decode(DataBuffer dataBuffer, ResolvableType elementType, @Nullable MimeType mimeType, @Nullable Map<String, Object> hints) { int byteCount = dataBuffer.readableByteCount(); ByteBuffer copy = ByteBuffer.allocate(byteCount); copy.put(dataBuffer.asByteBuffer()); copy.flip(); DataBufferUtils.release(dataBuffer); if (logger.isDebugEnabled()) { logger.debug(Hints.getLogPrefix(hints) + "Read " + byteCount + " bytes"); } return copy;}咱们是想把能够输入到日志的 body 转换成字符串进行输入,为了代码简洁避免出错,咱们应用一个工具类来实现将 DataBuffer 读取成字符串并开释的操作: ...

December 1, 2021 · 3 min · jiezi

关于spring-cloud:SpringCloud升级之路20200x版44避免链路信息丢失做的设计2

本系列代码地址:https://github.com/JoJoTec/sp...咱们在这一节咱们将持续解说防止链路信息失落做的设计,次要针对获取到现有 Span 之后,如何保障每个 GlobalFilter 都能放弃链路信息。首先,咱们自定义 Reactor 的外围 Publisher 即 Mono 和 Flux 的工厂,将链路信息封装进去,保障由这个工厂生成的 Mono 和 Flux,都是只有是这个工厂生成的 Mono 和 Flux 之间无论怎么拼接都会放弃链路信息的: 自定义 Mono 和 Flux 的工厂公共 Subscriber 封装,将 reactor Subscriber 的所有要害接口,都查看以后上下文是否有链路信息,即 Span,如果没有就包裹上,如果有则间接执行即可。 public class TracedCoreSubscriber<T> implements Subscriber<T>{ private final Subscriber<T> delegate; private final Tracer tracer; private final CurrentTraceContext currentTraceContext; private final Span span; TracedCoreSubscriber(Subscriber<T> delegate, Tracer tracer, CurrentTraceContext currentTraceContext, Span span) { this.delegate = delegate; this.tracer = tracer; this.currentTraceContext = currentTraceContext; this.span = span; } @Override public void onSubscribe(Subscription s) { executeWithinScope(() -> { delegate.onSubscribe(s); }); } @Override public void onError(Throwable t) { executeWithinScope(() -> { delegate.onError(t); }); } @Override public void onComplete() { executeWithinScope(() -> { delegate.onComplete(); }); } @Override public void onNext(T o) { executeWithinScope(() -> { delegate.onNext(o); }); } private void executeWithinScope(Runnable runnable) { //如果以后没有链路信息,强制包裹 if (tracer.currentSpan() == null) { try (CurrentTraceContext.Scope scope = this.currentTraceContext.maybeScope(this.span.context())) { runnable.run(); } } else { //如果以后已有链路信息,则间接执行 runnable.run(); } }}之后别离定义所有 Flux 的代理 TracedFlux,和所有 Mono 的代理 TracedMono,其实就是在 subscribe 的时候,用 TracedCoreSubscriber 包装传入的 CoreSubscriber: ...

November 30, 2021 · 3 min · jiezi

关于spring-cloud:SpringCloud升级之路20200x版44避免链路信息丢失做的设计1

本系列代码地址:https://github.com/JoJoTec/sp...咱们在这一节首先剖析下 Spring Cloud Gateway 一些其余可能失落链路信息的点,之后来做一些能够防止链路信息失落的设计,之后基于这个设计去实现咱们须要的一些定制化的 GlobalFilter Spring Cloud Gateway 其余的可能失落链路信息的点通过后面的剖析,咱们能够看出,不止这里,还有其余中央会导致 Spring Cloud Sleuth 的链路追踪信息隐没,这里举几个大家常见的例子: 1.在 GatewayFilter 中指定了异步执行某些工作,因为线程切换了,并且这时候可能 Span 曾经完结了,所以没有链路信息,例如: @Overridepublic Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) { return chain.filter(exchange).publishOn(Schedulers.parallel()).doOnSuccess(o -> { //这里就没有链路信息了 log.info("success"); });}2.将 GatewayFilter 中持续链路的 chain.filter(exchange) 放到了异步工作中执行,下面的 AdaptCachedBodyGlobalFilter 就属于这种状况,这样会导致之后的 GatewayFilter 都没有链路信息,例如: @Overridepublic Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) { return Mono.delay(Duration.ofSeconds(1)).then(chain.filter(exchange));}Java 并发编程模型与 Project Reactor 编程模型的抵触思考Java 中的很多框架,都用到了 ThreadLocal,或者通过 Thread 来标识唯一性。例如: 日志框架中的 MDC,个别都是 ThreadLocal 实现。所有的锁、基于 AQS 的数据结构,都是通过 Thread 的属性来惟一标识谁获取到了锁的。分布式锁等数据结构,也是通过 Thread 的属性来惟一标识谁获取到了锁的,例如 Redisson 中分布式 Redis 锁的实现。然而放到 Project Reactor 编程模型,这就显得心心相印了,因为 Project Reactor 异步响应式编程就是不固定线程,没法保障提交工作和回调能在同一个线程,所以 ThreadLocal 的语义在这里很难成立。Project Reactor 尽管提供了对标 ThreadLocal 的 Context,然而支流框架还没有兼容这个 Context,所以给 Spring Cloud Sleuth 粘合这些链路追踪带来了很大艰难,因为 MDC 是一个 ThreadLocal 的 Map 实现,而不是基于 Context 的 Map。这就须要 Spring Cloud Sleuth 在订阅一开始,就须要将链路信息放入 MDC,同时还须要保障运行时不切换线程。 ...

November 29, 2021 · 2 min · jiezi

关于spring-cloud:SpringCloud升级之路20200x版43为何-SpringCloudGateway-中会有链路信息丢失

本系列代码地址:https://github.com/JoJoTec/sp...在开始编写咱们本人的日志 Filter 之前,还有一个问题我想在这里和大家分享,即在 Spring Cloud Gateway 中可能产生链路信息失落的问题。 次要抵触 - Project Reactor 与 Java Logger MDC 之间的设计抵触Poject Reactor 是基于异步响应式设计的编程模式的实现,它的次要实现思路是先编写执行链路,最初 sub 执行整个链路。然而链路的每一部分,到底是哪个线程执行的,是不确定的。 Java 的日志框架设计,其上下文 MDC(Mapped Diagnostic Context)信息,是基于线程设计的,其实能够简略了解为一个 ThreadLocal 的 Map。日志的链路信息,是保留在这个 MDC 中的。 这样其实能够看出 Project Reactor 与日志框架的 MDC 默认是不兼容的,只有产生异步线程切换,这个 MDC 就变了。Spring Cloud Sleuth 为此加了很多粘合代码,然而智者千虑必有一失,Project Reactor 利用场景和库也在一直倒退和壮大,Spring Cloud Sleuth 也可能会漏掉一些场景导致链路信息失落。 一种 Spring Cloud Gateway 常见的链路信息失落的场景咱们编写一个简略的测试项目(我的项目地址): 引入依赖: <parent> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-parent</artifactId> <version>2.4.6</version></parent><dependencies> <dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-starter-gateway</artifactId> </dependency> <dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-starter-sleuth</artifactId> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-log4j2</artifactId> </dependency> <!--log4j2异步日志须要的依赖,所有我的项目都必须用log4j2和异步日志配置--> <dependency> <groupId>com.lmax</groupId> <artifactId>disruptor</artifactId> <version>${disruptor.version}</version> </dependency></dependencies><dependencyManagement> <dependencies> <dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-dependencies</artifactId> <version>2020.0.3</version> <type>pom</type> <scope>import</scope> </dependency> </dependencies></dependencyManagement>对所有门路开启 AdaptCachedBodyGlobalFilter: ...

November 28, 2021 · 3 min · jiezi

关于spring-cloud:SpringCloud升级之路20200x版42SpringCloudGateway-现有的可供分析的请求日志以及缺陷

本系列代码地址:https://github.com/JoJoTec/sp...网关因为是所有内部用户申请的入口,记录这些申请中咱们须要的元素,对于线上监控以及业务问题定位,是十分重要的。并且,在这些元素中,链路信息也是十分重要的。通过链路信息,咱们能够找到申请调用全链路相干的日志。并且,网关也是大部分申请链路起始的中央,记录申请中的元素的同时,也要带上链路信息。 咱们须要在网关记录每个申请的: HTTP 相干元素:URL 相干信息申请信息,例如 HTTP HEADER,申请工夫等等某些类型的申请体响应信息,例如响应码某些类型响应的响应体链路信息现有的可供剖析的日志以及缺点 首先咱们来看 Spring Cloud Gateway 中自身咱们能够利用的日志。Spring Cloud Gateway 基于 Spring-WebFlux,Spring-WebFlux 基于 Project Reactor,咱们没有在网关退出额定的 Web 容器依赖,所以 Web 容器用的是默认的基于 Project Reactor 的 reactor-netty 实现的 Web 容器。 netty 抓包日志 应用了 netty 咱们能够联想到 netty 的抓包日志,Spring Cloud Gateway 封装了这个性能,并裸露了配置。Spring Cloud Gateway 是一个网关,他会作为 HTTP 服务器承受 HTTP 申请的同时,还在作为 HTTP 客户端将申请转发到上游的微服务。所以,这里有两种抓包日志,一种是作为 HTTP 服务器接管到的申请和响应,另一种是做为 HTTP 客户端收回的申请和响应。别离对应两个配置: spring.cloud.gateway: httpserver: wiretap: truehttpclient: wiretap: true常常有读者私信我问如何看 spring cloud 有哪些配置,官网文档感觉不够分明全面。我个别是看源码,然而鉴于很多人没有精力去钻研源码,一种偷懒的形式是去看 jar 包外面的 spring-configuration-metadata.json。外面蕴含了比拟全的配置,以及配置类(如果存在的话),这是很不便的。例如咱们这里的两个配置,在这个 json 中对应: { "name": "spring.cloud.gateway.httpclient.wiretap", "type": "java.lang.Boolean", "description": "Enables wiretap debugging for Netty HttpClient.", "sourceType": "org.springframework.cloud.gateway.config.HttpClientProperties", "defaultValue": false},{ "name": "spring.cloud.gateway.httpserver.wiretap", "type": "java.lang.Boolean", "description": "Enables wiretap debugging for Netty HttpServer.", "defaultValue": "false"},能够看出,spring.cloud.gateway.httpclient.wiretap 对应配置类 org.springframework.cloud.gateway.config.HttpClientProperties(这个配置类外面的配置咱们前面还会用到,到时候会详细分析其中的配置项),默认为 false。spring.cloud.gateway.httpserver.wiretap 没有配置类,他是被间接应用的,对应源码: ...

November 27, 2021 · 22 min · jiezi

关于spring-cloud:SpringCloud升级之路20200x版41-SpringCloudGateway-基本流程讲解3

本系列代码地址:https://github.com/JoJoTec/sp...咱们持续剖析上一节提到的 WebHandler。退出 Spring Cloud Sleuth 以及 Prometheus 相干依赖之后, Spring Cloud Gateway 的解决流程如下所示: Spring Cloud Gateway 入口 -> WebFlux 的 DefaultWebFilterChainSpring Cloud Gateway 是基于 Spring WebFlux 开发的异步响应式网关,异步响应式代码比拟难以了解和浏览,我这里给大家分享一种办法去了解,通过这个流程来了解 Spring Cloud Gateway 的工作流程以及底层原理。其实能够了解为,上图这个流程,就是拼出来一个残缺的 Mono(或者 Flux)流,最初 subscribe 执行。 当收到一个申请的时候,会通过 org.springframework.web.server.handler.DefaultWebFilterChain,这是 WebFilter 的调用链,这个链路包含三个 WebFilter: org.springframework.boot.actuate.metrics.web.reactive.server.MetricsWebFilter:增加 Prometheus 相干依赖之后,会有这个 MetricsWebFilter,用于记录申请解决耗时,采集相干指标。org.springframework.cloud.sleuth.instrument.web.TraceWebFilter:增加 Spring Cloud Sleuth 相干依赖之后,会有这个 TraceWebFilter。org.springframework.cloud.gateway.handler.predicate.WeightCalculatorWebFilter:Spring Cloud Gateway 路由权重相干配置性能相干实现类,这个咱们这里不关怀。在这个 DefaultWebFilterChain 会造成这样一个 Mono,咱们顺次将他们标记进去,首先是入口代码 org.springframework.web.server.handler.DefaultWebFilterChain#filter: public Mono<Void> filter(ServerWebExchange exchange) { return Mono.defer(() -> // this.currentFilter != null 代表 WebFilter 链还没有完结 // this.chain != null 代表 WebFilter 链不为空 this.currentFilter != null && this.chain != null ? //在 WebFilter 链没有完结的状况下,调用 WebFilter invokeFilter(this.currentFilter, this.chain, exchange) : //在 WebFilter 完结的状况下,调用 handler this.handler.handle(exchange));}对于咱们这里的 WebFilter 链的第一个 MetricsWebFilter,假如启用了对应的采集统计的话,这时候生成的 Mono 就是: ...

November 26, 2021 · 5 min · jiezi

关于spring-cloud:SpringCloud升级之路20200x版41-SpringCloudGateway-基本流程讲解2

本系列代码地址:https://github.com/JoJoTec/sp...咱们持续剖析上一节提到的 WebHandler,通过将申请封装成 ServerWebExchange 的 HttpWebHandlerAdapter 之后,申请会通过 ExceptionHandlingWebHandler 全局 Web 解决异样处理器的接入点 - ExceptionHandlingWebHandler之前有网友私信问过笔者,如何给 Spring Cloud Gateway 加全局异样处理器,其实和给基于 Spring-Flux 的异步 Web 服务加是一样的,都是通过实现并注册一个 WebExceptionHandler Bean: WebExceptionHandler.java public interface WebExceptionHandler { Mono<Void> handle(ServerWebExchange exchange, Throwable ex);}这些 Bean,就是在 ExceptionHandlingWebHandler 被退出到整个申请解决链路中的: ExceptionHandlingWebHandler.java @Overridepublic Mono<Void> handle(ServerWebExchange exchange) { Mono<Void> completion; try { //这里其实就是组装前面的链路,即调用前面的 FilteringWebHandler 的 handle completion = super.handle(exchange); } catch (Throwable ex) { completion = Mono.error(ex); } for (WebExceptionHandler handler : this.exceptionHandlers) { completion = completion.onErrorResume(ex -> handler.handle(exchange, ex)); } return completion;}从源码能够看出,这里将每个 WebExceptionHandler 作为 Mono 的异样解决 onErrorResume 退出了链路。onErrorResume 的意思是如果链路后面产生异样,则在这里捕捉住异样同时调用 handler.handle(exchange, ex) 进行解决,如果应用阻塞代码了解,就相当于: ...

November 25, 2021 · 2 min · jiezi

关于spring-cloud:SpringCloud升级之路20200x版41-SpringCloudGateway-基本流程讲解1

本系列代码地址:https://github.com/JoJoTec/sp...接下来,将进入咱们降级之路的又一大模块,即网关模块。网关模块咱们废除了曾经进入保护状态的 zuul,选用了 Spring Cloud Gateway 作为外部网关。为何抉择 Spring Cloud Gateway 而不是 nginx 还有 Kong 的起因是: 项目组对于 Java 更加相熟,并且对于 Project Reactor 异步编程也比拟相熟,这个比拟重要须要在网关中应用咱们之前实现的基于申请的有状态重试的压力敏感的负载均衡器须要在网关中实现重试须要在网关中实现实例门路断路须要在网关中进行业务对立加解密须要在网关中实现 BFF(Backends For Frontends)接口,即依据客户端申请,将某几个不同接口的申请一次性组合返回须要在网关中应用 Redis 记录一些与 Token 相干的值因而,咱们应用了 Spring Cloud Gateway 作为外部网关,接下来,咱们就来顺次实现下面说的这些性能。同时在本次降级应用过程中, Spring Cloud Gateway 也有一些坑,例如: 联合应用 spring-cloud-sleuth 会有链路信息追踪,然而某些状况链路信息会失落。对于三方 Reactor 封装的异步 API (例如后面提到的操作 Redis 应用的 spring-data-redis)了解不到位导致要害线程被占用。然而首先,咱们须要简略了解下 Spring Cloud Gateway 到底包含哪些组件以及整个调用流程是什么样子的。因为 Spring Cloud Gateway 基于 Spring-Boot 和 Spring-Webflux 实现,所以咱们会从外层 WebFilter 开始阐明,而后剖析如何走到 Spring Cloud Gateway 的封装逻辑,以及 Spring Cloud Gateway 蕴含的组件,申请是如何转发进来,回来后又通过了哪些解决,这些咱们都会逐个剖析。 创立一个简略的 API 网关为了详细分析流程,咱们先来创立一个简略的网关,用于疾速上手并剖析。 ...

November 24, 2021 · 2 min · jiezi

关于spring-cloud:SpringCloud升级之路20200x版40-spock-单元测试封装的-WebClient下

本系列代码地址:https://github.com/JoJoTec/sp...咱们持续上一节,持续应用 spock 测试咱们本人封装的 WebClient 测试针对 readTimeout 重试针对响应超时,咱们须要验证重试仅针对能够重试的办法(包含 GET 办法以及配置的可重试办法),针对不可重试的办法没有重试。咱们能够通过 spock 单元测试中,查看对于负载均衡器获取实例办法的调用次数看进去是否有重试 咱们通过 httpbin.org 的 '/delay/秒' 实现 readTimeout,别离验证: 测试 GET 提早 2 秒返回,超过读取超时,这时候会重试测试 POST 提早 3 秒返回,超过读取超时,同时门路在重试门路中,这样也是会重试的测试 POST 提早 2 秒返回,超过读取超时,同时门路在重试门路中,这样不会重试代码如下: @SpringBootTest( properties = [ "webclient.configs.testServiceWithCannotConnect.baseUrl=http://testServiceWithCannotConnect", "webclient.configs.testServiceWithCannotConnect.serviceName=testServiceWithCannotConnect", "webclient.configs.testService.baseUrl=http://testService", "webclient.configs.testService.serviceName=testService", "webclient.configs.testService.responseTimeout=1s", "webclient.configs.testService.retryablePaths[0]=/delay/3", "webclient.configs.testService.retryablePaths[1]=/status/4*", "spring.cloud.loadbalancer.zone=zone1", "resilience4j.retry.configs.default.maxAttempts=3", "resilience4j.circuitbreaker.configs.default.failureRateThreshold=50", "resilience4j.circuitbreaker.configs.default.slidingWindowType=TIME_BASED", "resilience4j.circuitbreaker.configs.default.slidingWindowSize=5", //因为重试是 3 次,为了避免断路器关上影响测试,设置为正好比重试多一次的次数,避免触发 //同时咱们在测试的时候也须要手动清空断路器统计 "resilience4j.circuitbreaker.configs.default.minimumNumberOfCalls=4", "resilience4j.circuitbreaker.configs.default.recordExceptions=java.lang.Exception" ], classes = MockConfig)class WebClientUnitTest extends Specification { @SpringBootApplication static class MockConfig { } @SpringBean private LoadBalancerClientFactory loadBalancerClientFactory = Mock() @Autowired private CircuitBreakerRegistry circuitBreakerRegistry @Autowired private Tracer tracer @Autowired private ServiceInstanceMetrics serviceInstanceMetrics @Autowired private WebClientNamedContextFactory webClientNamedContextFactory //不同的测试方法的类对象不是同一个对象,会从新生成,保障相互没有影响 def zone1Instance1 = new DefaultServiceInstance(instanceId: "instance1", host: "www.httpbin.org", port: 80, metadata: Map.ofEntries(Map.entry("zone", "zone1"))) def zone1Instance2 = new DefaultServiceInstance(instanceId: "instance2", host: "www.httpbin.org", port: 8081, metadata: Map.ofEntries(Map.entry("zone", "zone1"))) def zone1Instance3 = new DefaultServiceInstance(instanceId: "instance3", host: "httpbin.org", port: 80, metadata: Map.ofEntries(Map.entry("zone", "zone1"))) RoundRobinWithRequestSeparatedPositionLoadBalancer loadBalancerClientFactoryInstance = Spy(); ServiceInstanceListSupplier serviceInstanceListSupplier = Spy(); //所有测试的办法执行前会调用的办法 def setup() { //初始化 loadBalancerClientFactoryInstance 负载均衡器 loadBalancerClientFactoryInstance.setTracer(tracer) loadBalancerClientFactoryInstance.setServiceInstanceMetrics(serviceInstanceMetrics) loadBalancerClientFactoryInstance.setServiceInstanceListSupplier(serviceInstanceListSupplier) } def "测试针对 readTimeout 重试"() { given: "设置 testService 的实例都是失常实例" loadBalancerClientFactory.getInstance("testService") >> loadBalancerClientFactoryInstance serviceInstanceListSupplier.get() >> Flux.just(Lists.newArrayList(zone1Instance1, zone1Instance3)) when: "测试 GET 提早 2 秒返回,超过读取超时" //革除断路器影响 circuitBreakerRegistry.getAllCircuitBreakers().forEach({ c -> c.reset() }) try { webClientNamedContextFactory.getWebClient("testService") .get().uri("/delay/2").retrieve() .bodyToMono(String.class).block(); } catch (WebClientRequestException e) { if (e.getCause() in ReadTimeoutException) { //读取超时疏忽 } else { throw e; } } then: "每次都会超时所以会重试,依据配置一共有 3 次" 3 * loadBalancerClientFactoryInstance.getInstanceResponseByRoundRobin(*_) when: "测试 POST 提早 3 秒返回,超过读取超时,同时门路在重试门路中" //革除断路器影响 circuitBreakerRegistry.getAllCircuitBreakers().forEach({ c -> c.reset() }) try { webClientNamedContextFactory.getWebClient("testService") .post().uri("/delay/3").retrieve() .bodyToMono(String.class).block(); } catch (WebClientRequestException e) { if (e.getCause() in ReadTimeoutException) { //读取超时疏忽 } else { throw e; } } then: "每次都会超时所以会重试,依据配置一共有 3 次" 3 * loadBalancerClientFactoryInstance.getInstanceResponseByRoundRobin(*_) when: "测试 POST 提早 2 秒返回,超过读取超时,这个不能重试" //革除断路器影响 circuitBreakerRegistry.getAllCircuitBreakers().forEach({ c -> c.reset() }) try { webClientNamedContextFactory.getWebClient("testService") .post().uri("/delay/2").retrieve() .bodyToMono(String.class).block(); } catch (WebClientRequestException e) { if (e.getCause() in ReadTimeoutException) { //读取超时疏忽 } else { throw e; } } then: "没有重试,只有一次调用" 1 * loadBalancerClientFactoryInstance.getInstanceResponseByRoundRobin(*_) }}测试非 2xx 响应码返回的重试对于非 2xx 的响应码,代表申请失败,咱们须要测试: ...

November 23, 2021 · 3 min · jiezi

关于spring-cloud:SpringCloud升级之路20200x版40-spock-单元测试封装的-WebClient上

本系列代码地址:https://github.com/JoJoTec/sp...咱们来测试下后面封装好的 WebClient,这里开始,咱们应用 spock 编写 groovy 单元测试,这种编写进去的单元测试,代码更加简洁,同时更加灵便,咱们在接下来的单元测试代码中就能看进去。 编写基于 spock 的 spring-boot context 测试咱们退出后面设计的配置,编写测试类: @SpringBootTest( properties = [ "webclient.configs.testServiceWithCannotConnect.baseUrl=http://testServiceWithCannotConnect", "webclient.configs.testServiceWithCannotConnect.serviceName=testServiceWithCannotConnect", "webclient.configs.testService.baseUrl=http://testService", "webclient.configs.testService.serviceName=testService", "webclient.configs.testService.responseTimeout=1s", "webclient.configs.testService.retryablePaths[0]=/delay/3", "webclient.configs.testService.retryablePaths[1]=/status/4*", "spring.cloud.loadbalancer.zone=zone1", "resilience4j.retry.configs.default.maxAttempts=3", "resilience4j.circuitbreaker.configs.default.failureRateThreshold=50", "resilience4j.circuitbreaker.configs.default.slidingWindowType=TIME_BASED", "resilience4j.circuitbreaker.configs.default.slidingWindowSize=5", //因为重试是 3 次,为了避免断路器关上影响测试,设置为正好比重试多一次的次数,避免触发 //同时咱们在测试的时候也须要手动清空断路器统计 "resilience4j.circuitbreaker.configs.default.minimumNumberOfCalls=4", "resilience4j.circuitbreaker.configs.default.recordExceptions=java.lang.Exception" ], classes = MockConfig)class WebClientUnitTest extends Specification { @SpringBootApplication static class MockConfig { }}咱们退出三个服务实例供单元测试调用: class WebClientUnitTest extends Specification { def zone1Instance1 = new DefaultServiceInstance(instanceId: "instance1", host: "www.httpbin.org", port: 80, metadata: Map.ofEntries(Map.entry("zone", "zone1"))) def zone1Instance2 = new DefaultServiceInstance(instanceId: "instance2", host: "www.httpbin.org", port: 8081, metadata: Map.ofEntries(Map.entry("zone", "zone1"))) def zone1Instance3 = new DefaultServiceInstance(instanceId: "instance3", host: "httpbin.org", port: 80, metadata: Map.ofEntries(Map.entry("zone", "zone1")))}咱们要动静的指定负载平衡获取服务实例列表的响应,即去 Mock 负载均衡器的 ServiceInstanceListSupplier 并笼罩: ...

November 22, 2021 · 3 min · jiezi

关于spring-cloud:SpringCloud升级之路20200x版39-改造-resilience4j-粘合-WebClient

本系列代码地址:https://github.com/JoJoTec/sp...要想实现咱们上一节中提到的: 须要在重试以及断路中加一些日志,便于日后的优化须要定义重试的 Exception,并且与断路器相结合,将非 2xx 的响应码也封装成特定的异样须要在断路器相干的 Operator 中减少相似于 FeignClient 中的负载平衡的数据更新,使得负载平衡更加智能咱们须要将 resilience4j 自身提供的粘合库做一些革新,其实次要就是对 resilience4j 实现的 project reactor 的 Operator 进行革新。 对于断路器的革新首先,WebClient 的返回对象只可能是 ClientResponse 类型,所以咱们这里革新进去的 Operator 不用带上形参,只须要针对 ClientResponse 即可,即: public class ClientResponseCircuitBreakerOperator implements UnaryOperator<Publisher<ClientResponse>> { ...}在原有的断路器逻辑中,咱们须要退出针对 GET 办法以及之前定义的能够重试的门路匹配配置能够重试的逻辑,这须要咱们拿到原有申请的 URL 信息。然而 ClientResponse 中并没有裸露这些信息的接口,其默认实现 DefaultClientResponse(咱们只有没有本人给 WebClient 退出非凡的革新逻辑,实现都是 DefaultClientResponse) 中的 request() 办法能够获取申请 HttpRequest,其中蕴含 url 信息。然而这个类还有办法都是 package-private 的,咱们须要反射进去: ClientResponseCircuitBreakerSubscriber private static final Class<?> aClass;private static final Method request;static { try { aClass = Class.forName("org.springframework.web.reactive.function.client.DefaultClientResponse"); request = ReflectionUtils.findMethod(aClass, "request"); request.setAccessible(true); } catch (Exception e) { throw new RuntimeException(e); }}之后,在获取到 ClientResponse 之后记录断路器的逻辑中,须要退出下面提到的对于重试的革新,以及负载均衡器的记录: ...

November 21, 2021 · 4 min · jiezi

关于spring-cloud:SpringCloud升级之路20200x版38-实现自定义-WebClientNamedContextFactory

本系列代码地址:https://github.com/JoJoTec/sp...实现 WeClient 的 NamedContextFactory咱们要实现的是不同微服务主动配置装载不同的 WebClient Bean,这样就能够通过 NamedContextFactory 实现。咱们先来编写下实现这个 NamedContextFactory 整个的加载流程的代码,其结构图如下所示: spring.factories # AutoConfigurationorg.springframework.boot.autoconfigure.EnableAutoConfiguration=\com.github.jojotech.spring.cloud.webflux.auto.WebClientAutoConfiguration在 spring.factories 定义了主动装载的主动配置类 WebClientAutoConfiguration WebClientAutoConfiguration @Import(WebClientConfiguration.class)@Configuration(proxyBeanMethods = false)public class WebClientAutoConfiguration {}WebClientAutoConfiguration 这个主动配置类 Import 了 WebClientConfiguration WebClientConfiguration @Configuration(proxyBeanMethods = false)@EnableConfigurationProperties(WebClientConfigurationProperties.class)public class WebClientConfiguration { @Bean public WebClientNamedContextFactory getWebClientNamedContextFactory() { return new WebClientNamedContextFactory(); }}WebClientConfiguration 中创立了 WebClientNamedContextFactory 这个 NamedContextFactory 的 Bean。在这个 NamedContextFactory 中,定义了默认配置 WebClientDefaultConfiguration。在这个默认配置中,次要是给每个微服务都定义了一个 WebClient 定义 WebClient 的配置类咱们编写下上一节定义的配置,包含: 微服务名称微服务地址,服务地址,不填写则为 http://微服务名称连贯超时,应用 Duration,这样咱们能够用更直观的配置了,例如 5ms,6s,7m 等等响应超时,应用 Duration,这样咱们能够用更直观的配置了,例如 5ms,6s,7m 等等能够重试的门路,默认只对 GET 办法重试,通过这个配置减少针对某些非 GET 办法的门路的重试;同时,这些门路能够应用 * 等门路匹配符,即 Spring 中的 AntPathMatcher 进行门路匹配多个门路。例如 /query/order/**WebClientConfigurationProperties ...

November 20, 2021 · 3 min · jiezi

关于spring-cloud:SpringCloud升级之路20200x版37-实现异步的客户端封装配置管理的意义与设计

本系列代码地址:https://github.com/JoJoTec/sp...为何须要封装异步 HTTP 客户端 WebClient对于同步的申请,咱们应用 spring-cloud-openfeign 封装的 FeignClient,并做了额定的定制。对于异步的申请,应用的是异步 Http 客户端即 WebClient。WebClient 应用也比较简单,举一个简略的例子即: //应用 WebClient 的 Builder 创立 WebClientWebClient client = WebClient.builder() //指定基址 .baseUrl("http://httpbin.org") //能够指定一些默认的参数,例如默认 Cookie,默认 HttpHeader 等等 .defaultCookie("cookieKey", "cookieValue") .defaultHeader(HttpHeaders.CONTENT_TYPE, MediaType.APPLICATION_JSON_VALUE) .build();创立好 WebClient 后即能够应用这个 WebClient 进行调用: // GET 申请 /anything 并将 body 转化为 StringMono<String> stringMono = client.get().uri("/anything").retrieve().bodyToMono(String.class);//这里为了测试,采纳阻塞获取String block = stringMono.block();返回的后果如下所示(申请 http://httporg.bin/anything 会将申请中的所有内容一成不变返回,从这里咱们能够看出下面测试的 Header 还有 cokkie 都被返回了): { "args": {}, "data": "", "files": {}, "form": {}, "headers": { "Accept": "*/*", "Accept-Encoding": "gzip", "Cookie": "TestCookie=TestCookieValue,getAnythingCookie=getAnythingCookieValue", "Getanythingheader": "getAnythingHeaderValue", "Host": "httpbin.org", "Testheader": "TestHeaderValue", "User-Agent": "ReactorNetty/1.0.7" }, "json": null, "method": "GET", "origin": "12.12.12.12", "url": "http://httpbin.org/anything"}咱们也能够退出负载平衡的性能,让 WebClient 利用咱们外部的 LoadBalancer,负载平衡调用其余微服务,首先注入负载平衡 Filter: ...

November 19, 2021 · 1 min · jiezi

关于spring-cloud:System-Performance-读书笔记-操作系统1

本系列是针对 Systems Performance: Enterprise and the Cloud, 2nd Edition (2020) 书籍的读书笔记,退出了一些集体了解以及拓展,并且针对一些难以了解的中央提供了一些额定的参考内核(Kernel)经典模型中,内核在操作系统构造中的地位如图所示: 从里到外别离是: 硬件(Hardware):操作系统运行在的硬件设施。内核(Kernel):操作系统的外围软件,内核治理着 CPU 调度、内存、文件系统、网络协议以及各种零碎设施(磁盘 IO、网络 IO 等等)。通过零碎调用提供服务。零碎调用(System Calls):提供拜访硬件设施或者内核服务的程序接口。例如 open, close, read, write, ioctl等,需蕴含头文件unistd.h。零碎库(System Libraries):间接用零碎调用可能不太不便,咱们能够应用封装好的库函数进行编程应用。从图上能够看出,这里其实有个缺口,因为利用也能够不应用零碎库而是间接应用零碎调用。例如像是 Go 语言运行环境,他就应用了本人封装的零碎调用层而不是规范库 libc。目前很多操作系统都在这个模型的根底上做了变种,之后咱们会详细分析。 内核执行通过一直地迭代,内核目前曾经十分宏大,有上百万的代码。内核的执行是按需的,例如当用户级别的应用程序发动了零碎调用,或者设施发送了一个中断(interrupt)的时候。另外,某些内核线程回异步执行一些维护性的工作,可能蕴含内核时钟程序以及内存治理工作,然而这些工作都会尽量放弃轻量级并只占用很少的 CPU 资源。 像 Web 服务器这种 I/O 密集型的利用(一直的承受申请返回响应),会常常在内核上下文中执行。计算密集型的利用则会尽量不打搅内核,能够不中断地在 CPU 上执行。内核调度器会决定那个线程会运行,哪个会期待,以及调度到哪个 CPU 上。内核会抉择硬件缓存更热或者对于这个过程本地性更好的 CPU,来进步性能。 内核态以及用户态内核态(kernel mode):运行内核程序的时候,CPU 处于的模式即内核态,在这一状态下,设施的所有拜访以及各种特权命令执行都是被容许的。内核管制对于设施的拜访来实现多过程解决。除非明确指定,否则过程之间或者用户之间的数据是无奈相互拜访的 用户态(user mode):运行用户程序的时候,CPU 处于的模式。通过零碎调用,会从用户态切换到内核态用更高的权限级别执行: 用户态切换到内核态是一种模式切换(mode switch),所有的零碎调用都会模式切换,某些零碎调用还会上下文切换:遇到硬盘 IO 或者网络 IO 的线程会上下文切换到能够运行的线程。这种切换都是有性能损耗的,个别通过如下几种优化来防止: 用户模式零碎调用(User-mode syscalls):能够在用户模式库实现一些零碎调用。Linux 通过裸露 virtual dynamic shared object (vDSO)来实现,能够参考:https://man7.org/linux/man-pa...内存映射(Memory mappings):用于按需装载内存页(缺页中断),前面还会提到。这样能防止间接拜访 IO 造成零碎调用。内核绕开(Kernel bypass):能够让用户态程序间接拜访设施,例如 DPDK(Data Plane Development Kit),这里举荐一篇对于 DPDK 的文章内核态利用:例如运行在内核的 TUX 服务器,以及 BPF(Berkeley Packet Filter). 对于 BPF,有一个驰名的基于 BPF 实现的工具汇合是:https://github.com/iovisor/bcc ...

November 17, 2021 · 1 min · jiezi

关于spring-cloud:SpringCloud升级之路20200x版35-验证线程隔离正确性

本系列代码地址:https://github.com/JoJoTec/sp...上一节咱们通过单元测试验证了重试的正确性,这一节咱们来验证咱们线程隔离的正确性,次要包含: 验证配置正确加载:即咱们在 Spring 配置(例如 application.yml)中的退出的 Resilience4j 的配置被正确加载利用了。雷同微服务调用不同实例的时候,应用的是不同的线程(池)。验证配置正确加载与之前验证重试相似,咱们能够定义不同的 FeignClient,之后查看 resilience4j 加载的线程隔离配置来验证线程隔离配置的正确加载。 并且,与重试配置不同的是,通过系列后面的源码剖析,咱们晓得 spring-cloud-openfeign 的 FeignClient 其实是懒加载的。所以咱们实现的线程隔离也是懒加载的,须要先调用,之后才会初始化线程池。所以这里咱们须要先进行调用之后,再验证线程池配置。 首先定义两个 FeignClient,微服务别离是 testService1 和 testService2,contextId 别离是 testService1Client 和 testService2Client @FeignClient(name = "testService1", contextId = "testService1Client")public interface TestService1Client { @GetMapping("/anything") HttpBinAnythingResponse anything();}@FeignClient(name = "testService2", contextId = "testService2Client") public interface TestService2Client { @GetMapping("/anything") HttpBinAnythingResponse anything();}而后,咱们减少 Spring 配置,并且给两个微服务都增加一个实例,应用 SpringExtension 编写单元测试类: //SpringExtension也蕴含了 Mockito 相干的 Extension,所以 @Mock 等注解也失效了@ExtendWith(SpringExtension.class)@SpringBootTest(properties = { //默认申请重试次数为 3 "resilience4j.retry.configs.default.maxAttempts=3", // testService2Client 外面的所有办法申请重试次数为 2 "resilience4j.retry.configs.testService2Client.maxAttempts=2", //默认线程池配置 "resilience4j.thread-pool-bulkhead.configs.default.coreThreadPoolSize=10", "resilience4j.thread-pool-bulkhead.configs.default.maxThreadPoolSize=10", "resilience4j.thread-pool-bulkhead.configs.default.queueCapacity=1" , //testService2Client 的线程池配置 "resilience4j.thread-pool-bulkhead.configs.testService2Client.coreThreadPoolSize=5", "resilience4j.thread-pool-bulkhead.configs.testService2Client.maxThreadPoolSize=5", "resilience4j.thread-pool-bulkhead.configs.testService2Client.queueCapacity=1",})@Log4j2public class OpenFeignClientTest { @SpringBootApplication @Configuration public static class App { @Bean public DiscoveryClient discoveryClient() { //模仿两个服务实例 ServiceInstance service1Instance1 = Mockito.spy(ServiceInstance.class); ServiceInstance service2Instance2 = Mockito.spy(ServiceInstance.class); Map<String, String> zone1 = Map.ofEntries( Map.entry("zone", "zone1") ); when(service1Instance1.getMetadata()).thenReturn(zone1); when(service1Instance1.getInstanceId()).thenReturn("service1Instance1"); when(service1Instance1.getHost()).thenReturn("www.httpbin.org"); when(service1Instance1.getPort()).thenReturn(80); when(service2Instance2.getInstanceId()).thenReturn("service1Instance2"); when(service2Instance2.getHost()).thenReturn("httpbin.org"); when(service2Instance2.getPort()).thenReturn(80); DiscoveryClient spy = Mockito.spy(DiscoveryClient.class); Mockito.when(spy.getInstances("testService1")) .thenReturn(List.of(service1Instance1)); Mockito.when(spy.getInstances("testService2")) .thenReturn(List.of(service2Instance2)); return spy; } }}编写测试代码,验证配置正确: ...

November 16, 2021 · 2 min · jiezi

关于spring-cloud:SpringCloud升级之路20200x版34验证重试配置正确性3

本系列代码地址:https://github.com/JoJoTec/sp...咱们持续上一节针对咱们的重试进行测试 验证针对可重试的办法响应超时异样重试正确咱们能够通过 httpbin.org 的 /delay/响应工夫秒 来实现申请响应超时。例如 /delay/3 就会提早三秒后返回。这个接口也是能够承受任何类型的 HTTP 申请办法。 咱们先来指定对于 Feign 超时的配置 Options: //SpringExtension也蕴含了 Mockito 相干的 Extension,所以 @Mock 等注解也失效了@ExtendWith(SpringExtension.class)@SpringBootTest(properties = { //敞开 eureka client "eureka.client.enabled=false", //默认申请重试次数为 3 "resilience4j.retry.configs.default.maxAttempts=3", //指定默认响应超时为 2s "feign.client.config.default.readTimeout=2000",})@Log4j2public class OpenFeignClientTest { @SpringBootApplication @Configuration public static class App { @Bean public DiscoveryClient discoveryClient() { //模仿两个服务实例 ServiceInstance service1Instance1 = Mockito.spy(ServiceInstance.class); ServiceInstance service1Instance3 = Mockito.spy(ServiceInstance.class); Map<String, String> zone1 = Map.ofEntries( Map.entry("zone", "zone1") ); when(service1Instance1.getMetadata()).thenReturn(zone1); when(service1Instance1.getInstanceId()).thenReturn("service1Instance1"); when(service1Instance1.getHost()).thenReturn("httpbin.org"); when(service1Instance1.getPort()).thenReturn(80); DiscoveryClient spy = Mockito.spy(DiscoveryClient.class); //微服务 testService1 有一个实例即 service1Instance1 Mockito.when(spy.getInstances("testService1")) .thenReturn(List.of(service1Instance1)); return spy; } }}咱们别离定义会超时和不会超时的接口: ...

November 15, 2021 · 2 min · jiezi

关于spring-cloud:SpringCloud升级之路20200x版34验证重试配置正确性2

本系列代码地址:https://github.com/JoJoTec/sp...咱们持续上一节针对咱们的重试进行测试 验证针对限流器异样的重试正确通过系列后面的源码剖析,咱们晓得 spring-cloud-openfeign 的 FeignClient 其实是懒加载的。所以咱们实现的断路器也是懒加载的,须要先调用,之后才会初始化线程隔离。所以这里如果咱们要模仿线程隔离满的异样,须要先手动读取载入线程隔离,之后能力获取对应实例的线程隔离,将线程池填充斥。 咱们先定义一个 FeignClient: @FeignClient(name = "testService1", contextId = "testService1Client")public interface TestService1Client { @GetMapping("/anything") HttpBinAnythingResponse anything();}应用后面同样的形式,给这个微服务增加实例: //SpringExtension也蕴含了 Mockito 相干的 Extension,所以 @Mock 等注解也失效了@ExtendWith(SpringExtension.class)@SpringBootTest(properties = { //敞开 eureka client "eureka.client.enabled=false", //默认申请重试次数为 3 "resilience4j.retry.configs.default.maxAttempts=3", //减少断路器配置 "resilience4j.circuitbreaker.configs.default.failureRateThreshold=50", "resilience4j.circuitbreaker.configs.default.slidingWindowType=COUNT_BASED", "resilience4j.circuitbreaker.configs.default.slidingWindowSize=5", "resilience4j.circuitbreaker.configs.default.minimumNumberOfCalls=2",})@Log4j2public class OpenFeignClientTest { @SpringBootApplication @Configuration public static class App { @Bean public DiscoveryClient discoveryClient() { //模仿两个服务实例 ServiceInstance service1Instance1 = Mockito.spy(ServiceInstance.class); ServiceInstance service1Instance3 = Mockito.spy(ServiceInstance.class); Map<String, String> zone1 = Map.ofEntries( Map.entry("zone", "zone1") ); when(service1Instance1.getMetadata()).thenReturn(zone1); when(service1Instance1.getInstanceId()).thenReturn("service1Instance1"); when(service1Instance1.getHost()).thenReturn("httpbin.org"); when(service1Instance1.getPort()).thenReturn(80); when(service1Instance3.getMetadata()).thenReturn(zone1); when(service1Instance3.getInstanceId()).thenReturn("service1Instance3"); //这其实就是 httpbin.org ,为了和第一个实例进行辨别加上 www when(service1Instance3.getHost()).thenReturn("www.httpbin.org"); DiscoveryClient spy = Mockito.spy(DiscoveryClient.class); //微服务 testService3 有两个实例即 service1Instance1 和 service1Instance4 Mockito.when(spy.getInstances("testService1")) .thenReturn(List.of(service1Instance1, service1Instance3)); return spy; } }}而后,编写测试代码: ...

November 14, 2021 · 2 min · jiezi

关于spring-cloud:SpringCloud升级之路20200x版34验证重试配置正确性1

本系列代码地址:https://github.com/JoJoTec/sp...在后面一节,咱们利用 resilience4j 粘合了 OpenFeign 实现了断路器、重试以及线程隔离,并应用了新的负载平衡算法优化了业务激增时的负载平衡算法体现。这一节,咱们开始编写单元测试验证这些性能的正确性,以便于日后降级依赖,批改的时候能保障正确性。同时,通过单元测试,咱们更能深刻了解 Spring Cloud。 验证重试配置对于咱们实现的重试,咱们须要验证: 验证配置正确加载:即咱们在 Spring 配置(例如 application.yml)中的退出的 Resilience4j 的配置被正确加载利用了。验证针对 ConnectTimeout 重试正确:FeignClient 能够配置 ConnectTimeout 连贯超时工夫,如果连贯超时会有连贯超时异样抛出,对于这种异样无论什么申请都应该重试,因为申请并没有收回。验证针对断路器异样的重试正确:断路器是微服务实例办法级别的,如果抛出断路器关上异样,应该间接重试下一个实例。验证针对限流器异样的重试正确:当某个实例线程隔离满了的时候,抛出线程限流异样应该间接重试下一个实例。验证针对非 2xx 响应码可重试的办法重试正确验证针对非 2xx 响应码不可重试的办法没有重试验证针对可重试的办法响应超时异样重试正确:FeignClient 能够配置 ReadTimeout 即响应超时,如果办法能够重试,则须要重试。验证针对不可重试的办法响应超时异样不能重试:FeignClient 能够配置 ReadTimeout 即响应超时,如果办法不能够重试,则不能重试。验证配置正确加载咱们能够定义不同的 FeignClient,之后查看 resilience4j 加载的重试配置来验证重试配置的正确加载。 首先定义两个 FeignClient,微服务别离是 testService1 和 testService2,contextId 别离是 testService1Client 和 testService2Client @FeignClient(name = "testService1", contextId = "testService1Client")public interface TestService1Client { @GetMapping("/anything") HttpBinAnythingResponse anything();}@FeignClient(name = "testService2", contextId = "testService2Client") public interface TestService2Client { @GetMapping("/anything") HttpBinAnythingResponse anything();}而后,咱们减少 Spring 配置,应用 SpringExtension 编写单元测试类: ...

November 13, 2021 · 3 min · jiezi

关于spring-cloud:SpringCloud升级之路20200x版33-实现重试断路器以及线程隔离源码

本系列代码地址:https://github.com/JoJoTec/sp...在后面两节,咱们梳理了实现 Feign 断路器以及线程隔离的思路,并阐明了如何优化目前的负载平衡算法。然而如何更新负载平衡的数据缓存,以及实现重试、断路器以及线程隔离的源码还没提,这一节咱们会详细分析。 首先,从 spring.factories 引入,减少咱们自定义 OpenFeign 配置的加载: spring.factories # AutoConfigurationorg.springframework.boot.autoconfigure.EnableAutoConfiguration=\com.github.jojotech.spring.cloud.webmvc.auto.OpenFeignAutoConfiguration主动配置类是 OpenFeignAutoConfiguration,其内容是: OpenFeignAutoConfiguration.java //设置 `@Configuration(proxyBeanMethods=false)`,因为没有 @Bean 的办法相互调用须要每次返回同一个 Bean,没必要代理,敞开减少启动速度@Configuration(proxyBeanMethods = false)//加载配置,CommonOpenFeignConfiguration@Import(CommonOpenFeignConfiguration.class)//启用 OpenFeign 注解扫描和配置,默认配置为 DefaultOpenFeignConfiguration,其实就是 Feign 的 NamedContextFactory(即 FeignContext)的默认配置类是 DefaultOpenFeignConfiguration@EnableFeignClients(value = "com.github.jojotech", defaultConfiguration = DefaultOpenFeignConfiguration.class)public class OpenFeignAutoConfiguration {}为何要加这一层而不是间接应用 Import 的 CommonOpenFeignConfiguration?应用 @AutoConfigurationBefore 和 @AutoConfigurationAfter 配置和其余 AutoConfiguration 加载的前后程序。 @AutoConfigurationBefore 和 @AutoConfigurationAfter 是 spring-boot 的注解,只对于 spring.factories 加载的 AutoConfiguration 失效。所以在设计上要加上这一层,避免咱们将来可能会用到这些注解。 CommonOpenFeignConfiguration 中蕴含所有 OpenFeign 的共用的一些 Bean,这些 Bean 是单例被所有 FeignClient 专用的,包含: FeignClient 要用的 Client 的底层 HTTP Client,咱们这里应用 Apache HttpClient将 Apache HttpClient 封装成 FeignClient 要用的 Client 的 ApacheHttpClientspring-cloud-openfeign 的 FeignClient 用的 Client 的负载平衡实现外围类是 FeignBlockingLoadBalancerClient,咱们须要将其封装代理从而实现断路器和线程隔离以及负载平衡数据采集,封装类是咱们本人实现的 FeignBlockingLoadBalancerClientDelegate。外围实现断路器和线程隔离逻辑的类是 Resilience4jFeignClient。CommonOpenFeignConfiguration.java ...

November 12, 2021 · 5 min · jiezi

关于spring-cloud:SpringCloud升级之路20200x版32-改进负载均衡算法

本系列代码地址:https://github.com/JoJoTec/sp...在后面一节,咱们梳理了实现 Feign 断路器以及线程隔离的思路,这一节,咱们先不看如何源码实现(因为源码中会蕴含负载平衡算法的改良局部),先来探讨下如何优化目前的负载平衡算法。 之前的负载平衡算法获取服务实例列表,将实例列表依照 ip 端口排序,如果不排序即便 position 是下一个可能也代表的是之前曾经调用过的实例依据申请中的 traceId,从本地缓存中以 traceId 为 key 获取一个初始值为随机数的原子变量 position,这样避免所有申请都从第一个实例开始调用,之后第二个、第三个这样。position 原子加一,之后对实例个数取余,返回对应下标的实例进行调用其中申请蕴含 traceId 是来自于咱们应用了 spring-cloud-sleuth 链路追踪,基于这种机制咱们能保障申请不会重试到之前曾经调用过的实例。源码是: //肯定必须是实现ReactorServiceInstanceLoadBalancer//而不是ReactorLoadBalancer<ServiceInstance>//因为注册的时候是ReactorServiceInstanceLoadBalancer@Log4j2public class RoundRobinWithRequestSeparatedPositionLoadBalancer implements ReactorServiceInstanceLoadBalancer { private final ServiceInstanceListSupplier serviceInstanceListSupplier; //每次申请算上重试不会超过1分钟 //对于超过1分钟的,这种申请必定比拟重,不应该重试 private final LoadingCache<Long, AtomicInteger> positionCache = Caffeine.newBuilder().expireAfterWrite(1, TimeUnit.MINUTES) //随机初始值,避免每次都是从第一个开始调用 .build(k -> new AtomicInteger(ThreadLocalRandom.current().nextInt(0, 1000))); private final String serviceId; private final Tracer tracer; public RoundRobinWithRequestSeparatedPositionLoadBalancer(ServiceInstanceListSupplier serviceInstanceListSupplier, String serviceId, Tracer tracer) { this.serviceInstanceListSupplier = serviceInstanceListSupplier; this.serviceId = serviceId; this.tracer = tracer; } //每次重试,其实都会调用这个 choose 办法从新获取一个实例 @Override public Mono<Response<ServiceInstance>> choose(Request request) { return serviceInstanceListSupplier.get().next().map(serviceInstances -> getInstanceResponse(serviceInstances)); } private Response<ServiceInstance> getInstanceResponse(List<ServiceInstance> serviceInstances) { if (serviceInstances.isEmpty()) { log.warn("No servers available for service: " + this.serviceId); return new EmptyResponse(); } return getInstanceResponseByRoundRobin(serviceInstances); } private Response<ServiceInstance> getInstanceResponseByRoundRobin(List<ServiceInstance> serviceInstances) { if (serviceInstances.isEmpty()) { log.warn("No servers available for service: " + this.serviceId); return new EmptyResponse(); } //为了解决原始算法不同调用并发可能导致一个申请重试雷同的实例 //从 sleuth 的 Tracer 中获取以后申请的上下文 Span currentSpan = tracer.currentSpan(); //如果上下文不存在,则可能不是前端用户申请,而是其余某些机制触发,咱们就创立一个新的上下文 if (currentSpan == null) { currentSpan = tracer.newTrace(); } //从申请上下文中获取申请的 traceId,用来惟一标识一个申请 long l = currentSpan.context().traceId(); AtomicInteger seed = positionCache.get(l); int s = seed.getAndIncrement(); int pos = s % serviceInstances.size(); log.info("position {}, seed: {}, instances count: {}", pos, s, serviceInstances.size()); return new DefaultResponse(serviceInstances.stream() //实例返回列表程序可能不同,为了保持一致,先排序再取 .sorted(Comparator.comparing(ServiceInstance::getInstanceId)) .collect(Collectors.toList()).get(pos)); }}然而在这次申请突增很多的时候,这种负载平衡算法还是给咱们带来了问题。 ...

November 11, 2021 · 4 min · jiezi

关于spring-cloud:SpringCloud升级之路20200x版31-FeignClient-实现断路器以及线程隔离限流的思路

本系列代码地址:https://github.com/JoJoTec/sp...在后面一节,咱们实现了 FeignClient 粘合 resilience4j 的 Retry 实现重试。仔细的读者可能会问,为何在这里的实现,不把断路器和线程限流一起加上呢: @Beanpublic FeignDecorators.Builder defaultBuilder( Environment environment, RetryRegistry retryRegistry) { //获取微服务名称 String name = environment.getProperty("feign.client.name"); Retry retry = null; try { retry = retryRegistry.retry(name, name); } catch (ConfigurationNotFoundException e) { retry = retryRegistry.retry(name); } //笼罩其中的异样判断,只针对 feign.RetryableException 进行重试,所有须要重试的异样咱们都在 DefaultErrorDecoder 以及 Resilience4jFeignClient 中封装成了 RetryableException retry = Retry.of(name, RetryConfig.from(retry.getRetryConfig()).retryOnException(throwable -> { return throwable instanceof feign.RetryableException; }).build()); return FeignDecorators.builder().withRetry( retry );}次要起因是,这里减少断路器以及线程隔离,其粒度是微服务级别的,这样的害处是: 微服务中只有有一个实例始终异样,整个微服务就会被断路微服务只有有一个办法始终异样,整个微服务就会被断路微服务的某个实例比较慢,其余实例失常,然而轮询的负载平衡模式导致线程池被这个实例的申请堵满。因为这一个慢实例,倒是整个微服务的申请都被拖慢回顾咱们想要实现的微服务重试、断路、线程隔离申请重试来看几个场景: 1.在线公布服务的时候,或者某个服务呈现问题下线的时候,旧服务实例曾经在注册核心下线并且实例曾经敞开,然而其余微服务本地有服务实例缓存或者正在应用这个服务实例进行调用,这时候个别会因为无奈建设 TCP 连贯而抛出一个 java.io.IOException,不同框架应用的是这个异样的不同子异样,然而提示信息个别有 connect time out 或者 no route to host。这时候如果重试,并且重试的实例不是这个实例而是失常的实例,就能调用胜利。如下图所示: ...

November 10, 2021 · 2 min · jiezi

关于spring-cloud:SpringCloud升级之路20200x版30-FeignClient-实现重试

本系列代码地址:https://github.com/JoJoTec/sp...须要重试的场景微服务零碎中,会遇到在线公布,个别的公布更新策略是:启动一个新的,启动胜利之后,敞开一个旧的,直到所有的旧的都被敞开。Spring Boot 具备优雅敞开的性能,能够保障申请解决完再敞开,同时会回绝新的申请。对于这些回绝的申请,为了保障用户体验不受影响,是须要重试的。 云上部署的微服务,对于同一个服务,同一个申请,很可能不会所有实例都同时异样,例如: Kubernetes 集群部署的实例,可能同一个虚拟机 Node 在闲时部署了多个不同微服务实例,当压力变大时,就须要迁徙和扩容。这时候因为不同的微服务压力不同,过后处于哪一个 Node 也说不定,有的可能处于压力大的,有的可能处于压力小的。对于同一个微服务,可能并不会所有实例位于的 Node 压力都大。云上部署个别会跨可用区部署,如果有一个可用区异样,另一个可用区还能够持续提供服务。某个业务触发了 Bug,导致实例始终在 GC,然而这种申请个别很不常见,不会发到所有实例上。这时候,就须要咱们对申请进行无感知的重试。 重试须要思考的问题重试须要重试与之前不同的实例,甚至是不处于同一个虚拟机 Node 的实例,这个次要通过 LoadBalancer 实现,能够参考之前的 LoadBalancer 局部。前面的文章,咱们还会改良 LoadBalancer重试须要思考到底什么申请能重试,以及什么异样能重试: 假如咱们有查问接口,和没有做幂等性的扣款接口,那么很直观的就能感觉出查问接口是能够重试的,没有做幂等性的扣款接口是不能重试的。业务上不能重试的接口,对于非凡的异样(其实是示意申请并没有收回去的异样),咱们是能够重试的。尽管是没有做幂等性的扣款接口,然而如果抛出的是起因是 Connect Timeout 的 IOException,这样的异样代表申请还没有收回去,是能够重试的。重试策略:重试几次,重试距离。类比多处理器编程模式中的 Busy Spin 策略会造成很大的总线通量从而升高性能这个景象,如果失败立即重试,那么在某一个实例异样导致超时的时候,会在同一时间有很多申请重试到其余实例。最好加上肯定提早。应用 resilience4j 实现 FeignClient 重试FeignClient 自身带重试,然而重试策略绝对比较简单,同时咱们还想应用断路器以及限流器还有线程隔离,resilience4j 就蕴含这些组件。 原理简介Resilience4J 提供了 Retryer 重试器,官网文档地址:https://resilience4j.readme.i... 从配置上就能了解其中的原理,然而官网文档配置并不全面,如果想看所有的配置,最好还是通过源码: RetryConfigurationProperties.java //重试距离,默认 500ms@Nullableprivate Duration waitDuration;//重试间隔时间函数,和 waitDuration 只能设置一个,默认就是 waitDuration@Nullableprivate Class<? extends IntervalBiFunction<Object>> intervalBiFunction;//最大重试次数,包含自身那次调用@Nullableprivate Integer maxAttempts;//通过抛出的异样判断是否重试,默认是只有有异样就会重试@Nullableprivate Class<? extends Predicate<Throwable>> retryExceptionPredicate;//通过后果判断是否重试,默认是只有获取到后果就不重试@Nullableprivate Class<? extends Predicate<Object>> resultPredicate;//配置抛出这些异样以及子类则会重试@SuppressWarnings("unchecked")@Nullableprivate Class<? extends Throwable>[] retryExceptions;//配置抛出这些异样以及子类则不会重试@SuppressWarnings("unchecked")@Nullableprivate Class<? extends Throwable>[] ignoreExceptions;//启用 ExponentialBackoff 提早算法,首次重试延迟时间为 waitDuration,之后每次重试延迟时间都乘以 exponentialBackoffMultiplier,直到 exponentialMaxWaitDuration@Nullableprivate Boolean enableExponentialBackoff;private Double exponentialBackoffMultiplier;private Duration exponentialMaxWaitDuration;//启用随机提早算法,范畴是 waitDuration - randomizedWaitFactor*waitDuration ~ waitDuration + randomizedWaitFactor*waitDuration@Nullableprivate Boolean enableRandomizedWait;private Double randomizedWaitFactor;@Nullableprivate Boolean failAfterMaxAttempts;引入 resilience4j-spring-boot2 的依赖,就能够通过 Properties 配置的形式去配置 Retryer 等所有 resilience4j 组件,例如: ...

November 9, 2021 · 2 min · jiezi

关于spring-cloud:SpringCloud升级之路20200x版29Spring-Cloud-OpenFeign-的解析2

本系列代码地址:https://github.com/JoJoTec/sp...在应用云原生的很多微服务中,比拟小规模的可能间接依附云服务中的负载均衡器进行外部域名与服务映射,通过健康检查接口判断实例衰弱状态,而后间接应用 OpenFeign 生成对应域名的 Feign Client。Spring Cloud 生态中,对 OpenFeign 进行了封装,其中的 Feign Client 的各个组件,也是做了肯定的定制化,能够实现在 OpenFeign Client 中集成服务发现与负载平衡。在此基础上,咱们还联合了 Resilience4J 组件,实现了微服务实例级别的线程隔离,微服务办法级别的断路器以及重试。 咱们先来剖析下 Spring Cloud OpenFeign Spring Cloud OpenFeign 解析HTTP 编码解码器,与 spring-boot 中的编码解码器相结合Spring Cloud 中的任何组件,都是基于 Spring Boot 而实现的。因为 Spring Boot 中曾经有了 HTTP 编码解码器,就能够不必独自给 OpenFeign 独自再实现 HTTP 编码解码器了,而是思考将 OpenFeign 的编码解码器接口用 Spring Boot 的 HTTP 编码解码器实现。 在 FeignClientsConfiguration 中,提供了默认的实现: //因为初始化程序以及 NamedContextFactory 的 Configuration 初始化的起因,这里须要注入 ObjectFactory 而不是间接注入 HttpMessageConverters 避免找不到 Bean@Autowiredprivate ObjectFactory<HttpMessageConverters> messageConverters;@Bean@ConditionalOnMissingBeanpublic Decoder feignDecoder() { return new OptionalDecoder(new ResponseEntityDecoder(new SpringDecoder(this.messageConverters)));}@Bean@ConditionalOnMissingBean//咱们这里疏忽 Pageable 类存在的状况//针对 Spring Data 的分页包装 Pageable 的兼容实现也比较简单,这里疏忽@ConditionalOnMissingClass("org.springframework.data.domain.Pageable")public Encoder feignEncoder(ObjectProvider<AbstractFormWriter> formWriterProvider) { return springEncoder(formWriterProvider, encoderProperties);}private Encoder springEncoder(ObjectProvider<AbstractFormWriter> formWriterProvider, FeignEncoderProperties encoderProperties) { AbstractFormWriter formWriter = formWriterProvider.getIfAvailable(); if (formWriter != null) { return new SpringEncoder(new SpringPojoFormEncoder(formWriter), this.messageConverters, encoderProperties); } else { return new SpringEncoder(new SpringFormEncoder(), this.messageConverters, encoderProperties); }}基于 SpringDecoder 的解码器通过源码能够看出,默认的 Decoder 是通过几层包装的 Decoder,别离包含: ...

November 8, 2021 · 3 min · jiezi

关于spring-cloud:SpringCloud升级之路20200x版29Spring-Cloud-OpenFeign-的解析1

本系列代码地址:https://github.com/JoJoTec/sp...在应用云原生的很多微服务中,比拟小规模的可能间接依附云服务中的负载均衡器进行外部域名与服务映射,通过健康检查接口判断实例衰弱状态,而后间接应用 OpenFeign 生成对应域名的 Feign Client。Spring Cloud 生态中,对 OpenFeign 进行了封装,其中的 Feign Client 的各个组件,也是做了肯定的定制化,能够实现在 OpenFeign Client 中集成服务发现与负载平衡。在此基础上,咱们还联合了 Resilience4J 组件,实现了微服务实例级别的线程隔离,微服务办法级别的断路器以及重试。 咱们先来剖析下 Spring Cloud OpenFeign Spring Cloud OpenFeign 解析从 NamedContextFactory 动手Spring Cloud OpenFeign 的 github 地址:https://github.com/spring-clo... 首先,依据咱们之前剖析 spring-cloud-loadbalancer 的流程,咱们先从继承 NamedContextFactory 的类动手,这里是 FeignContext,通过其构造函数,失去其中的默认配置类: FeignContext.java public FeignContext() { super(FeignClientsConfiguration.class, "feign", "feign.client.name");}从构造方法能够看出,默认的配置类是:FeignClientsConfiguration。咱们接下来详细分析这个配置类中的元素,并与咱们之前剖析的 OpenFeign 的组件联合起来。 负责解析类元数据的 Contract,与 spring-web 的 HTTP 注解相结合为了开发人员更好上手应用和了解,最好能实现应用 spring-web 的 HTTP 注解(例如 @RequestMapping,@GetMapping 等等)去定义 FeignClient 接口。在 FeignClientsConfiguration 中就是这么做的: FeignClientsConfiguration.java @Autowired(required = false)private FeignClientProperties feignClientProperties;@Autowired(required = false)private List<AnnotatedParameterProcessor> parameterProcessors = new ArrayList<>();@Autowired(required = false)private List<FeignFormatterRegistrar> feignFormatterRegistrars = new ArrayList<>();@Bean@ConditionalOnMissingBeanpublic Contract feignContract(ConversionService feignConversionService) { boolean decodeSlash = feignClientProperties == null || feignClientProperties.isDecodeSlash(); return new SpringMvcContract(this.parameterProcessors, feignConversionService, decodeSlash);}@Beanpublic FormattingConversionService feignConversionService() { FormattingConversionService conversionService = new DefaultFormattingConversionService(); for (FeignFormatterRegistrar feignFormatterRegistrar : this.feignFormatterRegistrars) { feignFormatterRegistrar.registerFormatters(conversionService); } return conversionService;}其外围提供的 Feign 的 Contract 就是 SpringMvcContract,SpringMvcContract 次要蕴含两局部外围逻辑: ...

November 7, 2021 · 3 min · jiezi

关于springcloud:spring和nacos的服务注册

Spring Cloud Commons提供了服务发现、负载平衡和断路器等模式的一个公共形象层,所有 Spring Cloud 客户端都能够应用该形象层,独立于实现(例如,通过 Nacos 或 Consul 进行发现)。 得益于Spring Commons的标准,Nacos也实现了该标准,所以开发过程中只须要调用相干接口,次要应用的是 1.DiscoveryClient接口,提供了获取所有服务和所有实例的办法; 2.ServiceRegistry接口,该接口提供了相似的办法register(Registration),deregister(Registration)并容许您提供自定义注册和登记服务。服务列表和状态会主动即时更新到gateway,主动进行负载平衡,具体操作都由Nacos实现,对开发通明。

November 3, 2021 · 1 min · jiezi

关于springcloud:Spring-Cloud自定义引导属性源

疏导过程增加的内部配置的默认属性源是Config Server,但您能够通过将PropertySourceLocator类型的bean增加到疏导上下文(通过spring.factories)增加其余源。您能够应用此办法从其余服务器或数据库中插入其余属性。 作为一个例子,请思考以下微不足道的自定义定位器:@Configurationpublic class CustomPropertySourceLocator implements PropertySourceLocator { @Override public PropertySource<?> locate(Environment environment) { return new MapPropertySource("customProperty", Collections.<String, Object>singletonMap("property.from.sample.custom.source", "worked as intended")); }} 传入的Environment是要创立的ApplicationContext的Environment,即为咱们提供额定的属性起源的。它将曾经具备失常的Spring Boot提供的资源起源,因而您能够应用它们来定位特定于此Environment的属性源(例如通过将其绑定在spring.application.name上,如在默认状况下所做的那样Config Server属性源定位器)。 如果你在这个类中创立一个jar,而后增加一个META-INF/spring.factories蕴含: org.springframework.cloud.bootstrap.BootstrapConfiguration=sample.custom.CustomPropertySourceLocator那么“customProperty”PropertySource将显示在其类门路中蕴含该jar的任何应用程序中。

October 29, 2021 · 1 min · jiezi

关于spring-cloud:SpringCloud升级之路20200x版28OpenFeign的生命周期进行调用

本系列代码地址:https://github.com/JoJoTec/sp...接下来,咱们开始剖析 OpenFeign 同步环境下的生命周期的第二局部,应用 SynchronousMethodHandler 进行理论调用,其流程能够总结为: 调用代理类的办法理论调用的是后面一章中生成的 InvocationHandler 的 invoke 办法。默认实现是查问 Map<Method, MethodHandler> methodToHandler 找到对应的 MethodHandler 进行调用,对于同步 Feign,其实就是 SynchronousMethodHandler对于 SynchronousMethodHandler: 应用后面一章剖析创立的创立的申请模板工厂 RequestTemplate.Factory,创立申请模板 RequestTemplate。读取 Options 配置应用配置的 Retryer 创立新的 Retryer执行申请并将响应反序列化 - executeAndDecode:如果配置了 RequestInterceptor,则执行每一个 RequestInterceptor将申请模板 RequestTemplate 转化为理论申请 Request通过 Client 执行 Request如果响应码是 2XX,应用 Decoder 解析 Response如果响应码是 404,并且在后面一章介绍的配置中配置了 decode404 为 true, 应用 Decoder 解析 Response对于其余响应码,应用 errorDecoder 解析,能够本人实现 errorDecoder 抛出 RetryableException 来走入重试逻辑如果以上步骤抛出 IOException,间接封装成 RetryableException 抛出 如果第 4 步抛出 RetryableException,则应用第三步创立的 Retryer 判断是否重试,如果须要重试,则从新走第 4 步,否则,抛出异样。给出这个流程后,咱们来详细分析 OpenFeign的生命周期-进行调用源码剖析后面一章的最初,咱们曾经从源码中看到了这一章结尾提到的流程的前两步,咱们间接从第三步开始剖析。 SynchronousMethodHandler ...

October 17, 2021 · 3 min · jiezi

关于spring-cloud:SpringCloud升级之路20200x版27OpenFeign的生命周期创建代理

本系列代码地址:https://github.com/JoJoTec/sp...接下来,咱们开始剖析 OpenFeign 的生命周期,联合 OpenFeign 自身的源代码。首先是从接口定义创立 OpenFeign 代理开始。咱们这里只关怀同步客户端,因为异步客户端目前还在实现中,并且在咱们的我的项目中,异步响应式的客户端不必 OpenFeign,而是用的官网的 WebClient 创立 OpenFeign 代理创立 OpenFeign 代理,次要分为以下几步: 应用 Contract 解析接口的每一个办法,生成每一个办法的元数据列表:List<MethodMetadata> metadata依据每一个 MethodMetadata,生成对应的申请模板工厂 RequestTemplate.Factory,用于生成前面的申请。同时,应用这个模板工厂以及其余配置生成对应的办法处理器 MethodHandler,对于同步的 OpenFeign,MethodHandler 实现为 SynchronousMethodHandler。将接口办法与 MethodHandler 一一对应建设映射,后果为 Map<Method, MethodHandler> methodToHandler。对于 Java 8 引入的 interface default 办法,须要用不同 MethodHandler,即 DefaultMethodHandler ,因为这种办法不必代理,不必生成对应的 http 调用,其实现为间接调用对应的 default 办法代码。应用 InvocationHandlerFactory 这个工厂,创立 InvocationHandler 用于代理调用。调用 JDK 动静代理生成类办法应用 InvocationHandler 创立代理类。创立 OpenFeign 代理,次要基于 JDK 的动静代理实现。咱们先举一个简略的例子,创立一个 JDK 动静代理,用来类比。 JDK 动静代理应用 JDK 动静代理,须要如下几个步骤: 1. 编写接口以及对应的代理类。咱们这里编写一个简略的接口和对应的实现类: public interface TestService { void test();}public class TestServiceImpl implements TestService { @Override public void test() { System.out.println("TestServiceImpl#test is called"); }}2.创立代理类实现java.lang.reflect.InvocationHandler,并且,在外围办法中,调用理论的对象,这里即咱们下面 TestService 的实现类 TestServiceImpl 的对象。 ...

October 16, 2021 · 5 min · jiezi

关于spring-cloud:SpringCloud升级之路20200x版26OpenFeign的组件

本系列代码地址:https://github.com/JoJoTec/sp...首先,咱们给出官网文档中的组件结构图: 官网文档中的组件,是以实现性能为维度的,咱们这里是以源码实现为维度的(因为之后咱们应用的时候,须要依据须要定制这些组件,所以须要从源码角度去拆分剖析),可能会有一些小差别。 负责解析类元数据的 ContractOpenFeign 是通过代理类元数据来主动生成 HTTP API 的,那么到底解析哪些类元数据,哪些类元数据是无效的,是通过指定 Contract 来实现的,咱们能够通过实现这个 Contract 来自定义一些类元数据的解析,例如,咱们自定义一个注解: //仅可用于办法上@java.lang.annotation.Target(METHOD)//指定注解放弃到运行时@Retention(RUNTIME)@interface Get { //申请 uri String uri();}这个注解很简略,标注了这个注解的办法会被主动封装成 GET 申请,申请 uri 为 uri() 的返回。 而后,咱们自定义一个 Contract 来解决这个注解。因为 MethodMetadata 是 final 并且是 package private 的,所以咱们只能继承 Contract.BaseContract 去自定义注解解析: //内部自定义必须继承 BaseContract,因为外面生成的 MethodMetadata 的结构器是 package private 的static class CustomizedContract extends Contract.BaseContract { @Override protected void processAnnotationOnClass(MethodMetadata data, Class<?> clz) { //解决类下面的注解,这里没用到 } @Override protected void processAnnotationOnMethod(MethodMetadata data, Annotation annotation, Method method) { //解决办法下面的注解 Get get = method.getAnnotation(Get.class); //如果 Get 注解存在,则指定办法 HTTP 申请形式为 GET,同时 uri 指定为注解 uri() 的返回 if (get != null) { data.template().method(Request.HttpMethod.GET); data.template().uri(get.uri()); } } @Override protected boolean processAnnotationsOnParameter(MethodMetadata data, Annotation[] annotations, int paramIndex) { //解决参数下面的注解,这里没用到 return false; }}而后,咱们来应用这个 Contract: ...

October 7, 2021 · 5 min · jiezi

关于spring-cloud:Spring-Cloud-Gateway-动态修改请求参数解决-URL-编码错误传参问题

Spring Cloud Gateway 动静批改申请参数解决 # URL 编码谬误传参问题继实现动静批改申请 Body 以及重试带 Body 的申请之后,咱们又遇到了一个小问题。最近很多接口,收到了谬误的参数,在接口层报的错是: class org.springframework.web.method.annotation.MethodArgumentTypeMismatchException, Failed to convert value of type 'java.lang.String' to required type 'java.lang.Integer'; nested exception is java.lang.NumberFormatException: For input string: "10#scrollTop=8178" 例如下面这个报错即原本应该是一个数字,后果收到的是 10#scrollTop=8178 导致转换异样。 失常的申请,是能够带 # 的,# 前面的局部属于 fragment。一个 URI 包含: 然而对于这些报错的申请,咱们发现,发送的申请的原始 URI 中, # 被谬误的 URL 编码了,变成了 %23,例如下面的申请,发到后端的是: https://zhxhash@example.com:8081/test/service?id=test&number=10%23segment1这样,后端解析到的 number 的值,就是 number=10#segment1,这样就会产生结尾提到的报错。 因为前端没能复现这个问题,并且问题集中于某几个零碎的浏览器版本,这个问题只能通过后盾网关做批改解决。 咱们的网关应用的是 Spring Cloud Gateway,咱们能够针对全局申请增加全局 Filter,动静修改 URI,解决这个问题,代码如下: @Log4j2@Componentpublic class QueryNormalizationFilter implements GlobalFilter, Ordered { @Override @SneakyThrows public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) { String originUriString = exchange.getRequest().getURI().toString(); if (originUriString.contains("%23")) { //将编码后的 %23 替换为 #,从新用这个字符串生成 URI URI replaced = new URI(originUriString.replace("%23", "#")); return chain.filter( exchange.mutate() .request( new ServerHttpRequestDecorator(exchange.getRequest()) { /** * 这个是影响转发到后盾服务的 uri * * @return */ @Override public URI getURI() { return replaced; } /** * 批改这个次要为了前面的 Filter 获取查问参数是精确的 * * @return */ @Override public MultiValueMap<String, String> getQueryParams() { return UriComponentsBuilder.fromUri(replaced).build().getQueryParams(); } } ).build() ); } else { return chain.filter(exchange); } } @Override public int getOrder() { return Ordered.HIGHEST_PRECEDENCE; }}留神点是: ...

October 5, 2021 · 1 min · jiezi

关于spring-cloud:SpringCloud升级之路20200x版25OpenFeign简介与使用

本系列代码地址:https://github.com/JoJoTec/sp...OpenFeign 的由来和实现思路在微服务零碎中,咱们常常会进行 RPC 调用。在 Spring Cloud 体系中,RPC 调用个别就是 HTTP 协定的调用。对于每次调用,根本都要通过如下步骤: 找到微服务实例列表并抉择一个实例调用参数序列化应用 Http 客户端将申请发送进来响应解决,反序列化等等除了这些公共逻辑,业务上只须要定义参数,HTTP 办法,HTTP URI,响应就能够,也就是应用接口就能定义: interface HttpBin { @Get(uri = "/get") String get(@Param("param") String param);}例如下面这个接口,就定义了一个 HTTP 申请,HTTP 办法为 GET,门路是 /get,参数是 param,响应为 String 类型。之后只有定义好公共逻辑,就能应用这个接口进行调用了。 对于这些公共逻辑的实现设计,咱们很天然的就能想到切面与动静代理。之前的章节,咱们提到过 JDK 中有针对接口的动静代理,其实就是实现 java.lang.reflect.InvocationHandler 而后针对这个接口实现代理类。之后应用这个代理类进行调用即可走入 InvocationHandler 中定义的逻辑。 以上,就是 OpenFeign 的设计实现思路与用处。 OpenFeign 简介OpenFeign 是一个基于申明式(通过类元数据定义,例如注解等)定义的 HTTP 申请客户端。这个库能够让你通过注解来主动生成调用对应 HTTP 服务的客户端,从代码上看调用这个近程服务和调用本地服务办法一样。OpenFeign 反对多种 HTTP 注解,包含 Feign 注解和 JAX-RS 注解,并且能够通过配置相似于插件的模式反对不同品种的注解。同时,还能够配置编码器,解码器,来编码申请并解码响应。底层的 HTTP Client 也是能够配置的,你能够应用 Java 原生的 Http 链接,也能够应用 Apache HttpClient 还有 OkHttpClient 等等。 ...

October 3, 2021 · 2 min · jiezi

关于springcloud:启用-SpringCloudOpenFeign-配置可刷新项目无法启动我-TM-人傻了下

本篇文章波及底层设计以及原理,以及问题定位,比拟深刻,篇幅较长,所以拆分成高低两篇: 上:问题简略形容以及 Spring Cloud RefreshScope 的原理下:以后 spring-cloud-openfeign + spring-cloud-sleuth 带来的 bug 以及如何修复Spring Cloud 中的配置动静刷新其实在测试的程序中,咱们曾经实现了一个简略的 Bean 刷新的设计。Spring Cloud 的主动刷新中,蕴含两种元素的刷新,别离是: 配置刷新,即 Environment.getProperties 和 @ConfigurationProperties 相干 Bean 的刷新增加了 @RefreshScope 注解的 Bean 的刷新@RefreshScope 注解其实和咱们下面自定义 Scope 应用的注解配置相似,即指定名称为 refresh,同时应用 CGLIB 代理: RefreshScope @Target({ ElementType.TYPE, ElementType.METHOD })@Retention(RetentionPolicy.RUNTIME)@Scope("refresh")@Documentedpublic @interface RefreshScope { ScopedProxyMode proxyMode() default ScopedProxyMode.TARGET_CLASS;}同时须要自定义 Scope 进行注册,这个自定义的 Scope 即 org.springframework.cloud.context.scope.refresh.RefreshScope,他继承了 GenericScope,咱们先来看这个父类,咱们专一咱们后面测试的那三个 Scope 接口办法,首先是 get: private BeanLifecycleWrapperCache cache = new BeanLifecycleWrapperCache(new StandardScopeCache());@Overridepublic Object get(String name, ObjectFactory<?> objectFactory) { //放入缓存 BeanLifecycleWrapper value = this.cache.put(name, new BeanLifecycleWrapper(name, objectFactory)); this.locks.putIfAbsent(name, new ReentrantReadWriteLock()); try { //这里在第一次调用会创立 Bean 实例,所以须要上锁,保障只创立一次 return value.getBean(); } catch (RuntimeException e) { this.errors.put(name, e); throw e; }}而后是注册 Destroy 的回调,其实就放在对应的 Bean 中,在移除的时候,会调用这个回调: ...

October 2, 2021 · 4 min · jiezi

关于spring-cloud:启用-SpringCloudOpenFeign-配置可刷新项目无法启动我-TM-人傻了上

本篇文章波及底层设计以及原理,以及问题定位,比拟深刻,篇幅较长,所以拆分成高低两篇: 上:问题简略形容以及 Spring Cloud RefreshScope 的原理下:以后 spring-cloud-openfeign + spring-cloud-sleuth 带来的 bug 以及如何修复最近在我的项目中想实现 OpenFeign 的配置能够动静刷新(次要是 Feign 的 Options 配置),例如: feign: client: config: default: # 链接超时 connectTimeout: 500 # 读取超时 readTimeout: 8000咱们可能会察看到调用某个 FeignClient 的超时工夫不合理,须要长期批改下,咱们不想因为这种事件重启过程或者刷新整个 ApplicationContext,所以将这部分配置放入 spring-cloud-config 中并应用动静刷新的机制进行刷新。官网提供了这个配置办法,参考:官网文档 - Spring @RefreshScope Support 即在我的项目中减少配置: feign.client.refresh-enabled: true然而在咱们的我的项目中,减少了这个配置后,启动失败,报找不到相干 Bean 的谬误: Caused by: org.springframework.beans.factory.NoSuchBeanDefinitionException: No bean named 'feign.Request.Options-testService1Client' available at org.springframework.beans.factory.support.DefaultListableBeanFactory.getBeanDefinition(DefaultListableBeanFactory.java:863) at org.springframework.beans.factory.support.AbstractBeanFactory.getMergedLocalBeanDefinition(AbstractBeanFactory.java:1344) at org.springframework.beans.factory.support.AbstractBeanFactory.doGetBean(AbstractBeanFactory.java:309) at org.springframework.beans.factory.support.AbstractBeanFactory.getBean(AbstractBeanFactory.java:213) at org.springframework.context.support.AbstractApplicationContext.getBean(AbstractApplicationContext.java:1160) at org.springframework.cloud.openfeign.FeignContext.getInstance(FeignContext.java:57) at org.springframework.cloud.openfeign.FeignClientFactoryBean.getOptionsByName(FeignClientFactoryBean.java:363) at org.springframework.cloud.openfeign.FeignClientFactoryBean.configureUsingConfiguration(FeignClientFactoryBean.java:195) at org.springframework.cloud.openfeign.FeignClientFactoryBean.configureFeign(FeignClientFactoryBean.java:158) at org.springframework.cloud.openfeign.FeignClientFactoryBean.feign(FeignClientFactoryBean.java:132) at org.springframework.cloud.openfeign.FeignClientFactoryBean.getTarget(FeignClientFactoryBean.java:382) at org.springframework.cloud.openfeign.FeignClientFactoryBean.getObject(FeignClientFactoryBean.java:371) at org.springframework.cloud.openfeign.FeignClientsRegistrar.lambda$registerFeignClient$0(FeignClientsRegistrar.java:235) at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.obtainFromSupplier(AbstractAutowireCapableBeanFactory.java:1231) at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBeanInstance(AbstractAutowireCapableBeanFactory.java:1173) at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.doCreateBean(AbstractAutowireCapableBeanFactory.java:564) at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBean(AbstractAutowireCapableBeanFactory.java:524) ... 74 more问题剖析通过这个 Bean 名称,其实能够看进去这个 Bean 是咱们开始提到要动静刷新的 Feign.Options,外面有连贯超时、读取超时等配置。名字前面的局部是咱们创立的 FeignClient 下面 @FeignClient 注解外面的 contextId。 ...

October 1, 2021 · 8 min · jiezi