呃, ok, 同学们,那前面的话咱们已经定位到了,这个重新注册是在哪发起的啊?知道是基于一个定时任务限时发起来执行这个方法,那现在咱们就往里看他。 ok, 来到咱们的源码这 好了,这个是咱们刚才看到的 read 度 fincense, 哎,可以看到一个放循环啊,这里面是基于 read 度 service 一个方法,叫做 find 的 incense read 度 data。 咱们之前不就是在往 concurrent 哈希 map 里面存这个数据吗? 那它这里面很明显就是从那个 concurrent 哈希 map 里面把这些数据都拿出来。好吧,所以说可以先看一下这个逻辑干嘛了, 哎,太熟悉了吧,兄弟们,咱们那个肯凯尔的哈西麦朋吗?对吧?在这个里面啊,直接放循环,便利到他的每一个 value, 然后呢,做了一个判断,看一下,哎,这玩意是否需要锐度啊?需要的话我就给他放到这个 result 的 这个哈西赛的集合里,然后返回就可以了 啊。所以说这一部分代码的话,咱们可以很清晰的知道他在干什么事了,就是把它先粘到咱这吧 啊,发起锐度,操作好。然后呢?第一步啊,这基于 这个逻辑啊,拿到 concurrent 哈希 map 里 所有是我所拥有啊,需要锐度的实力,那什么叫做需要锐度的实力呢?因为咱们说过锐度能干的事情很多,对吧?重新注册呀,或者是这个下线啊,或者是移除服务,那他这边呢,做了一个判断,服务很多,但并不是每一个都需要重新的做些事, 因为咱们之前在注册成功之后还记得走的这个逻辑吗?注册成功之后我改了点属性代表,哎,我这个不需要发起重新注册。那同样的, 之前修改的是把 rejected 改为了 true, 按 rejecting 改为了 false, 那 如果配合咱们现在这个里面的叫做 isne 的 锐度,是否需要锐度的逻辑?咱们进去看一下。 好, read to type。 哎,啥是 read to type 呢?它是个媒局啊,媒局里面有四个东西, register, i register remove, 还有一个 non, 而 non 就 代表什么事呢?我什么都不需要做。 而如果是 register 说明我要重新发起注册, i register 说明我要重新发起下线,而 remove 就 代表我要重新发起移除服务的事。 而对应上咱们这个逻辑,如果他什么事都不需要做,很明显他是个浪,所以这块做了一个判断,哎,你是不是等于浪啊?如果是浪的话,好了,那我就不需要往里添加,如果不是浪,哎,那我就往里放, 所以这块你会发现它里面做了一个非的判断,如果是呢,好了, if 不 会进去返回的 false 吗?那如果不是呢,那我就往里扔,那就基于它去走了,而它这不搁这呢吗? 好吧,然后看这块,其实这个代码都不用看,你看前面这个逻辑就可以了, register 等于处 i register 是 false, should not do anything。 说人话就是啊,注册成功了啊,这个 unregressing 是 false, 就 你带什么事都不用做。而咱们之前好像就是这么个事啊,处 false, 哎,我把它粘过来吧, 方便咱们去那块儿查看呀,我这点哪去了兄弟。呃咦 sorry, 我 有点找不到了啊,搁这儿啊,然后 那里个推啊,这里的逻辑有点乱啊。呃这啊,我复制一下往原版这块对比一波。同学们, ok 了吧。同学们所以说现在如果说我注册成功之后这两个属性对应的是不是我啥事都不用做呀。那同理你再对应上别的,如果注册成功了, i reject 零是处,那就代表什么?哎我需要干嘛 下线?应该是啊,这个应该是下线,然后这块呢看 false false, 哎代表我没有注册成功,需要重新注册。那如果是 false 处,就代表我这个服务应该是写要移除了吗? 我没写啊,不过,呃有没有移除这块有移除啊,这块可能还要配合一个结果来判断我是否需要是重新注册还是做一个移除。但无论怎么样只关注咱们现在的逻辑 以咱们现在这哥俩的情况,我把他们对的齐一点。兄弟们,他这个等号没有空格,那我也把空格去掉。好吧, 如果以我现在的情况,我是不是不我什么事都不用我什么事都不需要做对吧我什么事都不需要做但是咱们现在要看的是重新发起注册吗?对吧。所以你就可以大概理解为他就要走这个逻辑。 regener 是 false, 而这哥们也是 false, 因为默认值就是 false。 好 吧,他的默认值就是 false, 而这个也是 false。 为什么他俩的默认值是 false 呢? 因为这哥俩是布尔类型吗?布尔类型我在构建实力的时候很明显。我有给他俩赋值吗?我没赋值,没赋值他俩都是什么啊?都是 false 呗。所以说在都是 false 的 情况下,我要做的事就是重新发起注册。好吧,行, 那咱们不去细抠这块逻辑了,感兴趣你自己稍微看一下。但咱们现在得知了一个事,这里有一个,哎呀,我得把它找出来啊,我跳哪去了? 好,就这拿到实力之后去走他的一字逆的锐度的逻辑来看一下我是什么事都不做,还是需要做点什么事,好吧, 然后再加上一个,在获取实力后还会走一波这个判断, 这个判断啊,来查看是否是否啊需要锐度一些事情 好呢,只有啊,在啊,这个这个细节我就不写了吧,写什么写什么,反正咱都已经弄出来了。只有在什么情况下呢?只有在这个情况下什么事都不需要走好吧,因为你可以看下面逻辑,只有这一块返回的是 no 好 吧,剩下的话要么是下线,要么是重新注册,要么是移除好,其他细节先不看就走这个逻辑。 只有嗯,这个情况才是闹什么都不做好了。所以说能到这个位置的就是能到这个逻辑的 必然要啊,做点事无非是重新注册呀,或者是重新下线啊,重新下线或者是重新移除 这种操作,而咱们说过暂时只看重新注册,所以说咱们可以往这个里面去走了,好吧,来, 返回到咱们的循环好, read for instance 好, 这块就是他后续重新注册的一些逻辑了,我再把它转过来一下 好了。那这里就是啊,这个实力啊,需要 read 度一些 read 度一些事情啊,就会到这个逻辑 啊,看干点什么事啊。首先呢, redo data 点 get redo type, 说白了是你,是你要 redo, 你 要 redo 点啥,对吧?说获取需要重新干的事,哈哈哈,干的事以及一些服务信息,而这个服务信息就是服务名和主名啊,这个就不用多说了啊,日期不管, 然后紧接着啊, switch 嘛,对吧?基于 switch 啊,这个选择嘛。咦,基于 走分支啊,看一下到底要干点啥,而这边你会发现这不仨分支嘛,重新注册, 重新下线,屏幕移除。那咱们说过要看谁注册嘛,对吧?就这块就是重新注册, 下面这些注示我就不写了好吧,什么重新下线啊,什么重新移除啊,不管他,所以说,哎,走的逻辑是不是就是他了? proxy register redo, 把 redo data 和 service 跟分组名看服务名和组名都扔过来了,所以这块就是重新发起注册。好了,到地儿了,同学们 进来吧。好,首先这边呢,还看一下你的类型是不是 batch, 是 不是要批量做,那我这块暂时不是批量。好吧,按照咱们之前看的逻辑都是什么?单个的实力,所以这块不会走。那要走谁呢? 走外面来呗,这个衣服进不去,走外头。而 do register service 还用了 client proxy, 而且我这个 client proxy 很 明显是谁呀?是 g r p c 的。 好吧,因为咱们之前看过整个的构建过程,是不是基于 grpc client proxy 构建出来的?我的 reduce with, 所以 必然是 grpc 的。 那到了我的这个位置, 这代码就看过了吧,同学们,好了,这就回到了咱们之前的逻辑了, ok, 所以 说没啥聊的,哈哈,没啥聊的,那我就呃看看怎么写啊, 然后在这个逻辑里会查看一下是否是批量重新注册 啊。批量重新注册,然后呢,咱们现在看的逻辑啊,都是单个注册,您说这个批量注册是怎么弄的? 呃,首先咱们正常的基于 spring boot 那 种的 spring cloud 里的 nikes 是 很少有这种批量注册的,更多是咱们在这块儿做测试的时候,你可以去走你可 let 里面的一些种 bios, 看它有 bios register insense, 然后在里面给服务名,给分组名里面加成多个实力。好吧,那咱们正常都是一个好吧,正常都是一个,所以这个逻辑咱们一般呃用不到好吧,一般用不到。然后,呃,大部分 大部分逻辑都是单个注册,而单个注册的话呢,就定位到了咱们的这个逻辑啦。回去回去, 单个注册就到了。这个逻辑。好了,很明显,到这就回到之前看的三步走了。哪三步走啊? 我在这封装 request 发起。实力啊,这个发起请求到我的 nexus server 后面,注册成功了我就把 redo service 改一下。 好吧,行,那这个整理一下吧。三步走了,分别是,呃,一封装 request, 二发起。哎呀,又发起发起请求,然后第三步修改入党, ok, 所以 说到咱们重新发起请求的这个流程 找好了。然后呢,这边第一步就是基于之前的肯坎特哈西 map 里存储的 read do data 啊,或者这个基于之前肯坎特哈西 map 获取, 呃,获取维度 data 啊,或或或者这么说吧,获取需要做维度的一些维度 data 啊,应该能理解我的意思吧,需要重做一些事情的这个维度 data。 然后呢,结论下,基于 每个维度 data 的 这个,这个这个 type 啊, type 就是 这个维度 type 来决定啊,我要做什么事 来决定做什么事情。而咱们已经看过了,翻过来倒过去就三个事,重新注册、重新下线,以及这个这个这个重新移除,对吧?然后呢?最后啊,基于呃逻辑可以定位到 再次执行之前的三步,而那三步就是咱们刚才的这三步。哎,我在这可以站 呃,在这。好了,那就到了咱们之前注册流程的那最后一步了,好吧,又是在这个位置。 ok, 那 这样一来,咱们重新发起注册是如何触发的?一触发之后大概流程也就 ok 了,所以说重新注册搞定。那这样一来, 这根线 ok 了,下节课要去看他了,我 nicholas 服务里面是怎么接收注册请求的,并且我把你发过来的数据存放到哪,算是我注册成功了。 ok, 那 到这给他听一个,咱们下一课到这。
粉丝1559获赞9075

nikex 配置中心怎么实现配置同步?客户端又是怎么拿配置的?百分之九十的人一上来就说客户端定期轮询拉起配置,你只说定时拉取,面试官马上就会追问定时多久?定时拉取配置延迟怎么解决的?频繁轮询会不会压垮服务端?大概率问到这里就答不上来了。 如果你还不知道怎么准备面试,建议参考我整理的 java 高频面试题,大概市面上百分之九十的技术场景题,短时间内快速提升面试通过率。只要你是我的粉丝,扣八八八打包带走。 首先考懂第一个核心问题,应用第一次启动是怎么拿到 nikos 配置的?应用刚启动的时候,会发起一个简短的 http 短请求,主动从 nikos 服务端拉取对应的配置。拿到配置后,客户端会做两件关键的事情, 第一呢是直接缓存到本地内存,后续业务代码读取配置优先走内存,速度飞快。第二呢是持久化落地到本地磁盘文件,就算后面服务重启,不用依赖网络,直接读取本地文件就能恢复配置,极大减少网络开销,提升整体性能。 那么第二个关键的问题就来了, nikos 服务端配置改了,客户端怎么立刻感知做到低延迟同步的呢?这里根本不是简单的定时轮询, nikos 用的是经典长轮询机制, 客户端初次拉取完配置不会结束链接会持续给服务端发一个检查更新的请求。服务端收到请求后不会立刻返回,直接把连接挂起,默认等待三十秒,这三十秒内如果配置有变更,服务端立马响应通知客户端如果一直没有变化超时呢,就会返回空结果 客户端马上再发起新一轮乘踏巡。这种设计既做到了配置变更几乎实时感知,解决了定时拉取的延迟问题,又避免了短轮巡频繁请求把 nikos 服务端压垮的情况。 最后再讲一部客户端感知到配置变更后到底会做什么?收到变更通知会重新拉取最新完整配置,同步更新内存、缓存和本地硬盘文件,同时自动触发我们注册好的监听器 listen, 执行自定义业务逻辑。 像我们常用的艾特 v 六注解属性刷新动态重新出使画,并全都是靠这个机制实现的,真正做到了配置动态生效,不用重启服务。如果你还有不懂的技术问题,欢迎留言一起讨论哟!

最近跟很多做后端的同行还有面试的朋友聊天,发现大家对奈克斯配置中心的底层原理都是一个一知半解的状态,只知道简单的引入依赖配置地址就能用,就搞不懂客户端到底是怎么拉取配置的,配置改了之后又是怎么实时同步过来的。 而且啊,这也是面试里高频被问到的一个点,很多人只能模糊的回答,定期拉取。再往深问延迟怎么解决,本地怎么缓存,瞬间就答不上来了。针对近期讨论的面试考核方向,我特意整理了一份面试资料, 包含经常被问到的一些技术站场景题,针对每个知识点都有很详细的解析思路,只要你是我的粉丝,扣六六六打包带走。首先,我们应用刚启动的时候,客户端是怎么拿到配置的? 其实很简单,项目启动瞬间,纳普斯客户端会发起一次简短的 http 短连接请求,主动向服务端拉取我们绑定的配置信息。拿到配置之后呢,客户端不会只用一次就完事, 而是做了两层缓存,一份存在应用的内存当中,方便业务代码随时快速提取,另一份会持久化落地到本地的磁盘文件。 这么设计最大的好处就是,就算服务端网络出现问题或者项目重启,也能优先从本地的文件加载配置, 不用完全依赖网络,稳定性会高很多。或许我们业务独取配置也都是优先走本地划算,极大的减少了网络的开销。那很多人好奇,奈克斯控制台改了配置,客户端怎么能立刻感知到呢?不会有明显的延迟呢?这里核心就靠的是长轮询机制, 客户端首次拉取配置完后,并不会断开连接,反而会持续的向服务端发起检测更新的请求。服务端收到这个请求不会立刻返回结果,而是先把连接挂起, 默认等待三十秒。这三十秒里如果配置发生变更,服务端会立马响应推送更新,要是一直没有变动,超时后就会返回一个空结果,紧接着客户端会自动发起下一轮 长轮巡。这种方式既做到了配置变更近乎的实时同步,又不会像短轮巡那样频繁的发请求,给服务端造成巨大的压力。客户端一旦检测到配置有更新啊,就会重新拉取完成的配置,覆盖掉本地内存和硬盘的旧配置, 同时还会触发我们预先注册的监听器自动刷新 at 外流注解的属性,甚至重新促使化相关的业务,并让新配置不用重启,项目就能动态生效。其实整体逻辑并不复杂,无非就是启动主动拉取 本地双缓存兜底,靠长轮巡实现配置的实时监听,再通过监听器完成业务动态刷新,把这套逻辑理解透彻,不管是平时开发排查问题,还是面试被问到,都能说的明明白白。听完我的回答,你知道该怎么回答这个面试题了吗?如果你还有什么不懂的,欢迎在评论区一起讨论。

呃, ok, 同学们,那前面的话呢,整个发起注册流程也就搞定了,那再往下,咱们要看一下这个 nikos 的 客户端是怎么重新发起注册流程的,而这个位置呢,先要加句话啊,呃,咱们要看的是如何发起,又发起了发起 重新注册的流程啊,大哥啊,这个逻辑里不仅仅是重新发起注册, 重新发发,发起注册还包含了下线以及移除服务的流程啊, 所以说大家要清楚啊,这里看的话呢,咱们只看重新注册,但里面还有下线和移除的过程。好了,那怎么去看呢?首先第一点啊,啊,基于前面代码的分析,咱们得知 重新发起注册是基于一个叫做 rio service 的 实力去搞的,而这个 rio service 呢,是它啊, nico, 这个这个,这个内名 g r p c rio service, 我 把它复制一下, 诶,基于它去存储的这个这个,这个实力信息。 好,咱们之前只看到这啊,他的肯坎达哈奇 mac 里面啊,存了一点信息,但是怎么重新发起注册,咱们并不知道,对吧?所以说,咱们要定位到这个实力是何时被构建出来的啊? 嗯,得知这个得知啊,啊,那咱们现在啊,需要定位到整个这个实力 是何时被构建出来的啊?好了,那回到咱们之前的代码,咱们写过一个测试类,还记得吧, my test, 在 my test 里面,咱们只做了一个事,促使化了这个可烂的对象,也就是咱们的 nicholas naming service, 咱们只拗了它, 所以说在我拗他的时候,肯定会关联到咱们当前这个实力的构建。那咱们这边要一步一步的往里去走。好,同学们,跟着我一块走啊,先是构建他,我要去看他的有三构造好,进来好,到了有三构造之后呢,他执行了一个 init 到下面这吗?这不是,对吧?到这好,那在我构建 nicholas naming service 之后,往下看看,咱们接触过的有一个东西叫 naming client proxy delegate, 哎,那个委托吗?不是,在这个位置选择到底用的是 g r p c 还是 http? 好, 就这块咱们整理一下啊,在啊,之前啊,咱们,呃,之前写过一个测试方法,将当前服务注册到 neo soul 那, 呃,这个测试方法只构建了, 好,那咱们就顺着这个实力实力 的构建啊往下走好,首先第一个呢是构建它,那在构建它之后,咱们发现,哎,构建它的时候呢,会再次构建咱们的 naming client proxy delegate, 就是 咱们那个委托,基于这个委托,咱们要选择到底是用 l t d p 还是 g r p c, 而在这个里面 构建它的时候,你发现啊, l t v p 和 grpc 都是在这儿构建的,而咱们现在是走的 grpc 的 流程,所以说我要看它构建的时候做了什么事 一样的站过来,基于委托构建了我的 grpc, 而我的 grpc 里面再往下看,哎, reduce service, 哎,它拗了一个 name, g r p c reduce service 好, 到,这定位到了咱们这个 reduce service 实体的构建了, 好,那整个流程咱们定位到了,它确实是基于这样的方式构建出来的,那在构建我的 reduce service 的 时候里面做了什么事呢?来 呀,这东西有点熟啊,同学们,它构建了一个锐度 exquisitor, 而这块的实力是 scheduled 四 red pool exquisitor。 那 这就没啥说的了啊,定时任务现成值嘛, 对吧?指定了一下现成个数啊,指定了一下你这边的这个现成工厂,把你的每个现成的名字起个名啊,这就是你那个现成的名字啊。这个没啥说的好吧。然后呢,构建完毕之后, 直接利用它搞了一个周期性执行的一个任务,这个任务叫做 reduce cad 了的 task, 而这里面啊,加了一些对应的延迟时间。好吧,这块也都是看延迟时间啊,这个时间是多少啊?呃,可以往前翻,应该是可以定位到的。 那我看看在哪能翻到。呃,这 read do service properties, 那 应该是在这个 properties 里面设置,但是咱们先不管它啊,无所谓,最关键是它会发起这个任务,而这个任务 看,虽然说没有直接的看到它去实现 url, 但是你都看到它重写转换方法了,所以它继承的这个赋类里面必然有一个 url 的 接口,你往里找就可以。好吧, sorry, 这能看到吧,说重写乱方法没毛病,那我的定时任务必然就要执行这个乱方法好了。 那咱们大概知道是如何发起重新注册的。说人话就是在我构建好这个锐度 service 之后,它内部就有一个定时任务的限程值,再以一个周期的形式去执行这里的乱方法,而这里的乱方法必然会干嘛? reidefault instance 重新注册实力,而下面这是啥呀? reidefault sabot scripts 啊,重新发起订阅,哈哈。啊,虽说咱们说过啊,这个 reidef 里面做了很多事,咱们暂时只关注重新发起注册有这上面这个,好吧, 行,那到这咱们发现了一个事啊,在嘿嘿嘿,构建咱们的 name g r p c reidef service 时啊, 他创建了一个定时任务限程池啊,并且在这个限程池内部提交了一个周期性执行的任务 啊,那这部分就是咱们看他的有三构造,我给他粘过来吧,返回一下,就是这个位置放到咱的。 好,那前面这个就不管它了,这块主要就是这个,这个构建定时任务限程值。好,然后紧接着下面这块的话呢,就是提交一个周期性 执行的任务,而这个任务呢,就是 reduce scheduled task, 把这口先粘过来, double ok, 那 到这个位置之后呢,咱们再需要看的话,就是谁呢?再次查看 reduce cad 了的 task, 咱们看一下这个任务是什么鬼。好,那其实咱们刚才已经 low 了一眼了,这哥们本身就是一个 relevant 对吧?他就是个任务,所以说会执行他的乱方法,那关键就看他的乱方法里面干了一个什么事。首先这种介入性判断咱们就不说了,就是你这个锐度 service 啊,是不是连接着,没连接着我就直接结束了,我就不走了。 好吧,那这种属性默认的话,他肯定得是个处啊之类的,代表我是正常连接开启的。看啊,连接是开启的,所以咱们呢,直接往下看,重新发起注册就可以了。好吧,结束还是先回到笔记,这 在内部可以看到,他本身就是一个 roll 方法,而在他的 roll 方法中啊,主要 包含了两个逻辑,分别是重新发起注册和重新发起订阅。好,我把这两个小方法拿过来,而前面这个见仁性判断,咱们就不看他了。好吧,就这俩 缩进一下,粘到咱的笔记。这好,然后呢,咱们主要查看谁呢?主要查看 redo for instance 的 逻辑即可。啊,这里是重新发起好了,所以到这咱们知道是如何触发的了。 好吧,那再往下,咱们要看这里面到底干了点什么事。 ok, 那 这边线再停一个,然后呢,咱们后面继续往下搞。

一上来先放个狠话出去的,他以为 nuke 挂了,服务一定会崩。很多人对 nuke 的 理解还停留在注册中心这四个字,先听我讲完这一分钟,你对 nuke 的 理解可能会直接升一个档次。很多人认为服务调用是这样的,一会请求过来服务 a 区的 nuke, 服务 b 的 地址在哪,然后等 nuke 返回 ip 才能调用。 如果真是这样,那 nasa 一 挂,系统确实当场去世。但问题是,现在主流的微服务框架根本不是这么玩的。真正的流程其实是这样的,服务启动时,先从 nasa 拿取服务列表,然后缓存在本地,后面有服务之间的调用,很多时候根本不需要实时请求 nasa。 比如像 ruby 使用 cloud 的 double, 本质上都会在本地维护一份服务地址列表。 什么意思? nasa 更像是一个通讯录管理员,平时先把号码同步给你,真正打电话的时候,你直接翻本地通讯录,不会每打一通电话都会重新跑去问运营商。 所以很多情况下,哪怕 npx 突然挂了,已经注册成功的服务仍然还能正常互相调用。这也是为什么很多现象事物里面, npx 挂了半天,业务居然一点感觉都没有。看到这里,很多人开始兴奋了,卧槽,那 npx 是 不是也没有那么重要?别急,真正危险的东西现在才开始。 nacos 挂了以后,可怕的不是现在不能调用,而是系统状态开始慢慢失真。什么意思?比如某台机器已经挂了,但因为 nacos 挂了,消费者收不到最新的服务列表,于是系统还在疯狂的调用那个已经死掉的实力,结果就是超时越来越多,从事越来越频繁,限程时越来越满,最后雪崩开始了。 这就像什么你手机通讯录里面还存在一个已经注销的号码,偶尔打一两次没事,但如果整个系统每天几十万次调用,全打在这个注销电话上,那系统早晚被拖死。 而且还有一个很多忽略的问题,配置中心。如果你用 nux 动态配置,系统池限流灰度开关, nux 一 挂,新配置就推不了了。虽然老配置一般还在本地快照里,但系统已经失去了动态调整能力,这才是真正危险的地方。 所以真正成熟的系统都会有很多保护,本地缓存配置、快照熔断降级。因为大家都知道,注册中心绝对不能成为单点。真正高级的系统设计,从来不是主键永远不挂,而是主键挂了之后,系统还能撑多久?最后总结一句,很多人都认为 nux 挂了等于系统立刻崩 在真实线上,往往是短时间还能跑,但系统已经开始慢性死亡,就赶紧将 nikos 恢复才行。最后留个问题,你觉得微服务系统里,真正最怕单点的组建是 nikos ready 还是数据库?

不用写任何代码,也能开发出属于自己的 app 应用或网站,这个神仙 ai 工具让产品经理、设计师和程序员差点当场失业。不管是手机 app、 桌面开发、外部网站还是平板端应用,也都只需一句话就能让它实现。在 这里输入你的任何想法,都能快速生成交互原型设计和前端代码。比如让他参考微信的功能和页面,设计出一个外部端聊天应用, 它会先生成 workflow 工作流。你可以在这里调整大框架流程以及自定义修改每个模块的需求,并且多个页面之间还能进行关联,清晰地展示了页面与页面之间的跳转、返回或层级关系等逻辑。接下来就可以开始生成产品页面的操作。 该说不说,这设计水平比我们公司的 ui 设计好多了。如果遇到不满意的内容,可以在 ai 助手内输入需求来修改,又或者是利用编辑器来调整页面元素样式。如果你是前端选手,那它的代码导出功能你一定会用得上。不管是 html 还是 vivo 项目代码 一秒快速导出,直接使用,整个流程下来也就几分钟的事,但在真实开发中却可以大大增加墨鱼的时间。

ai 前端动画短板终于补上了,就是这个开源项目,在 tiktok 上已经斩获五 k 星,是 greensoft 官方亲自开源的 ai 技能,所有插件均可通过公共 gsa p n p m 包安装, 完全免费。 curses cloud code codex windsor 等四十多个主流智能体配合使用,直接生成这种堪比电影级别的专业的网页动效,不再是呆板的 ppt 拼接了,使用 ai 代理进行代码生成的开发者来说,可以显著提高开发效率。

兄弟们,新的时代开始了! warp 终端开源了,在 gitpop 上已经拿下了五十六点五 k 的 新标,它还被探秘评委二零二五年最佳发明之一。 openai 则是开源 warp 仓库的创始人项目是一个用 rasgo 键 gpu 加速渲染的现代终端。它和 item 二 microsoft 的 区别 不只是快这么简单。 warp 重新定义了终端的交互模式,每次命令的输入加输出是一个独立的滚动日制, 支持光标定位。多行编辑代码高亮,就像在编辑器里写命令,内置 ai 助手,自然语言转 c l i 命令报错解释、代码生成、团队协助功能分享工作流、 notebook 环境配置云端 agent 编排平台,可以并行启动多个 ai agent 执行任务,项目已覆盖 macos、 linux、 windows 三平台。以后开发者再也不用忍受老旧终端了,就非常 nice!

今天面了个四年前端,我问你们项目里前端是怎么做权限控制的,完整流程和方案说说。 他只简单提了隐藏按钮控制菜单追问权限流程力度划分路由按钮接口多级管控动态路由就答的支支吾吾,逻辑混乱。权限控制是中后台系统核心必备能力, 也是高阶前端面试高频大题,只会表面用法,根本算不上自身开发。下面把全流程多方案落地细节一次性讲透。一、 整体流程,一、用户登录后端返回当前用户身份角色权限列表。二、前端存储权限数据。三、依据权限数据逐层控制路由菜单页面按钮接口请求。 四、无权限时做拦截隐藏跳转四零三页面。二、四大权限力度一、路由权限静态路由提前写死路由表, 登录后根据权限过滤路由移除无全线路由,动态路由前端只保留基础公共路由,登录后由后端返回可访问路由前端动态添加拦截首位局路由位判断权限,非法访问直接重定向四零三、首页。二、 菜单权限根据权限列表渲染侧边栏菜单,直接隐藏无权限菜单,做到菜单与路由一一对应,从入口隔绝访问。三、按钮元素权限最常用的细力度控制分为两种,实线 指令方式,自定义权限指令 v permission 判断当前元素是否在权限列表,无权限则移除禁用按钮变量判断 页面内,通过 v 杠 i f 直接判断全线标识控制元素显隐。四、接口权限前端所有控制都是表层防护,可被绕过接口请求拦截,在 xus 请求拦截器校验权限,无权限直接拦截,请求 后端二次校电,所有接口必须后端再次健全,这是最终安全防线。三、主流全线模型一、 rbc 角色全线模型 用户分配角色,角色绑定权限,一人可多角色配置,简单易维护,绝大多数后台系统都在用。二、细力度 a、 c、 l 权限直接给用户分配独立权限, 不经过角色,适合复杂个性化权限场景。四、常见问题与优化方案一、刷新页面权限丢失解决方案,权限数据持久化到本地存储 路由首位出省话时重新加载权限,动态追加路由。二、月权访问只靠前端隐藏,没用路由加接口,双层拦截加后端强制健全多层兜底。三、权限更新实时生效, 角色变更后清空旧权限,重新请求权限列表,刷新路由与菜单。四、权限标识规范, 统一使用唯一权限标识,前后端约定一致,方便维护。五、面试满分精简话术 前端权限控制基于 r、 b、 a、 c 角色模型实现,分为四层管控,首先登录后获取角色与权限数据, 通过动态路由加路由首位控制页面访问权限。其次,根据权限渲染侧边菜单,再通过自定义指令或变量判断 控制页面按钮显隐。最后再请求拦截器做接口权限拦截,前端仅做展示层控制,所有接口必须由后端二次健全,保障系统安全。很多开发只停留在按钮显隐,搞不懂动态路由和整体权限架构,面试很容易失分。我整理了动态路由完整代码,自定义权限指令, 陆游守卫封装全线系统踩坑总结,后台项目直接套用,需要全套实战代码和面试笔记的朋友,评论区扣六六六,直接打包发给你。

昨天面了个五年的前端,简历上写,精通实时通信,熟练 sse 开发。我问 sse 断线了怎么实现自动重连?他想都没想就说断了,就 new one source 重新连背。我笑了笑,接着追问,怎么判断是真断还是抖动频繁?重连怎么防雪崩?重连后怎么保证数据不丢? 他当场愣住,半天憋不出一句话,直接沉默了。讲真的, sse 断线重连绝对是限阶段大场的必考题, 我给你三层追问,能达到第二层算合格,全讲明白,面试官都得给你打满分。如果这题你答不上,没有关系,我整理了这份前端面试大厂必考题目,包含最新 ai 前端面试题、性能优化题、工程话题等。点赞评论留个六六六,全部打包带走啊!这个就叫专业, 那么是哪三层呢?接下来带大家挨个拆解。第一层,新手无脑写法全是坑,只监听 aero 事件就立即重连,网络轻微抖动,临时超时也疯狂重试,短时间发起几十次请求,直接打崩后端线上事故常客。 第二层,基础合格做法稳得住,同时监听 aero 和 close 双事件,区分异常断联和正常关闭。断线后加三秒固定延迟再重连,避免高频请求,基础稳定性有了。 第三层,高阶工程化够专业,核心是指数退币加断点续传,重试间隔三秒、六秒、十二秒递增设三十秒上限,超过次数停止,并提示用户 从联时携带 lester vinty 服务端从断点补发,不丢一条数据,适配弱网和复杂场景,这就是差距。普通开发只会简单重连,高手懂异常区分退币策略,断点续传全链路。最后我问他,你现在觉得自己真的精通 sse 开发了吗?

前端动画神库 g a c 现在被 ai 直接接管了,官方发布 subscales cursor 用, log code 用,括拍了也用,几乎所有主流 a 剪都支持,还能自动识别。 以后写动画不用查文档了,直接让 ai 帮你调前端这块,最后一片手工活也快消失了。

面试官问大文件上传崩溃与断点续传该如何实现?刚面完一个三年前端,我问他项目中文件上传功能怎么实现?他脱口而出,用 input type 等于 file 获取文件,封装成 form data 对 象,提交给后端接口,就能完成文件上传。 我点点头,笑着问了他一个真实发生的线上事故,假设项目支持用户上传视频压缩包等大文件小文件上传,一切正常。一旦上传超过一百米币的文件,就会出现页面卡顿、浏览器无响应甚至直接崩溃的情况。 网络中断或页面刷新后,已经上传的部分全部丢失,用户必须从头重新上传。上传过程中也无法暂停和继续多个文件同时上传时还会出现请求超时、服务器拒绝连接的问题,用户体验极差。问题出在哪?他想了想,说是文件体积过大导致请求超时。 我追问,对,那你如何解决大文件上传的稳定性问题,实现断点续传?难道直接限制用户只能上传小文件?他开始吱吱呜呜,面试到这就结束了。 这正是前端文件上传的幽灵陷阱。你以为简单提交 form data 就 能搞定所有上传场景,却没想到大文件网络异常并发上传,会带来一系列致命问题。如果这道题你也不会回答的话,我整理了让大厂 hr 沉默的必考题库, 包含 v o l 灵魂拷问、 react 高频陷阱、 j s 十连问等等,只要是我粉丝留下,九九九打包带走。 nice, 为什么这个问题能筛出高手?因为他考察的不是会不会写基础上传代码,而是有没有分片上传、断点续传、异常处理的工程化思维。一名能搞定大文件上传的前端,必须建立三层防御。第一层,业务分级,区分小文件与大文件上传。 小于十 mb 的 图片、文档等小文件直接使用 from data 一 次性上传,简化开发流程。 大于十 mb 的 视频压缩包等大文件强制采用分片上传模式,将大文件切割成多个小块,分别提交,从源头避免单次请求体积过大导致的超时和崩溃。第二层,核心方案落地与异常兜底处理, 将大文件按固定大小切割成多个分片,每个分片携带唯一标识和序号,后端按序号合并文件, 实现断点续传功能。上传前先查询后端已上传的分片列表,跳过已上传部分,只上传剩余分片,控制并发上传数量,同时上传三到五个分片,避免同时发起过多请求导致服务器压力过大。 上传失败的分片自动重试,超过重试次数则提示用户手动重试。第三层,架构层优化,统一规范上传体系, 项目内封装通用大文件上传,组建统一分片大小并发送重试策略。全项目附用标准组件,实时显示上传进度、上传速度和剩余时间,给用户清晰的反馈,支持暂停继续取消上传操作,提升用户体验。 上传完成后校验文件完整性,通过 md 五比对,确保上传文件与原文件一致。针对超大文件支持秒传功能,后端已存在相同文件时,直接返回上传成功。 所以,这道题考的是什么?它考的是你有没有从单纯实现基础,上传功能升级为分片上传、断点续传、异常处理的全流程工程思维。普通前端只会简单提交 form data, 而高级前端清楚在大文件弱网并发上传的复杂场景下基础,上传方案是一把双刃剑。

面试官问你,前端跨域请求失败,该如何全面解决?刚面了一个三年前端,我问他浏览器跨域问题怎么处理?他脱口而出,后端配置 c o r s 允许跨域或者本地启动代理服务,就能正常发起请求。我点点头,笑着问了他一个真实发生的线上事故, 假设项目本地开发时,依靠代理完美解决跨域功能调试一切正常,项目打包上线部署后,代理规则失效,所有接口全部请求失败,页面数据空白,单纯配置 c o r s 又会出现复杂请求,触发预检报错。部分老旧浏览器还存在 c o r s。 兼容问题, 切换不同运行环境,跨域问题反复出现,始终无法彻底根治。问题出在哪儿?他想了想,说是跨域方案没有区分运行环境。 我追问,那你如何根据不同场景搭建完整的跨域解决方案?难道全程只依赖后端配置,前端不做任何适配处理?他开始吱吱呜呜,面试到这基本就结束了。这正是前端跨域处理的幽灵陷阱。 你以为配好代理或者开启 c o r s 就 能搞定跨域,却忽略了环境差异、请求类型、浏览器兼容带来的各类隐患。如果这道题你也不会回答的话,我整理了让大厂 hr 沉默的必考题库, 包含 v o l 灵魂拷问、 react 高频陷阱、 g s 十连问等等,只要是我粉丝留下,九九九打包带走。 nice! 为什么这个问题能筛出高手?因为他考察的不是会不会使用单一跨域方案,而是能不能结合开发测试线上多环境搭配不同请求场景,制定完整策略。一名能彻底解决跨域问题的前端,必须建立三层防御。第一层,业务分级, 区分开发环境与线上生产环境。本地开发调试阶段优先使用工程代理转发请求,快速规避跨越限制, 提升开发效率。测试和线上正式环境,放弃本地代理,依靠后端 coos、 n g s 反向代理等服务端方案,保证线上环境稳定运行。 同时区分简单请求与带自定义请求头请求方法的复杂请求,针对性规避预检请求报错。第二层, 多方案落地与兼容,兜底处理本地环境,借助 webpack white 内置代理,统一配置接口转发规则,拦截前端跨域报错。 线上环境优先使用 n gins 反向代理统一域名和端口,从根源消除跨域条件。 配合后端合理配置 c o s 规则,精准设置允许的域名请求头请求方式,并配置合适的预检缓存时长。面对老旧浏览器不支持 c o s 的 场景兼容,使用 g s p 方案处理纯 git 类查询接口, 规避兼容性问题。第三层,架构层优化,统一规范跨域整体体系,项目内封装统一接口请求函数,根据运行环境自动切换跨域策略,开发线上环境无缝适配。 梳理全项目接口域名,统一域名规范,减少多域名请求引发的跨域场景。前后端提前约定跨域配置标准,上线前连调验证 qs 反向代理有效期,提前排查问题。 遇到高并发接口、第三方接口等特殊场景,单独做路由转发隔离,避免跨域配置相互干扰。 所以,这道题考的是什么?它考的是你有没有从单纯套用某一种跨域写法升级为多环境、多场景兼顾兼容的整套跨域架构设计思维。 普通前端以为能调通接口就算解决跨域,而高级前端知道在多环境部署复杂请求场景面前,单一的跨域方案是一把双刃剑。

周五晚上八点,线上有个开关需要紧急关掉,你改了配置文件,然后开始一台一台重启服务,两百台机器重启完最后一台已经凌晨两点了,中间有台机器重启失败,线上事故了,你盯着告警面板,突然想,为什么改个配置要重启, 不能改了就生效。配置中心怎么设计才不踩坑?这是字节三面高频体,大部分人只知道用脑 qs, 但问到底层机制就哑了。如果这题你也不会答,点赞收藏视频,为你准备了 java 配套面试题和回答模板, 粉丝评论区打学习掉落,同时还原两个面试场景,看看你是哪个水平。配置中心怎么设计?用一个 now cos 配置写进去,服务启动的时候拉取就行了。配置变更了怎么通知服务? 服务定时去拉吧。定时拉取的延迟怎么解决?一万台实力同时拉取怎么扛?这个?那用推送。嗯,推送怎么保证所有实力都收到了?呃,这个我没想过。 配置中心怎么设计?配置中心核心要解决三个问题,怎么存?怎么推?怎么刷新存储用麦 cq 持久化加内存,缓存读取快。推送用长轮询客户端发起请求,服务端 hold 住连接, 配置变更了立即返回,没变更三十秒超时返回再发起下一次。那你说说长轮询和 webbase 比有什么优势?长轮询实现简单,兼容性好,不需要维护长连接状态, websites 实时性更好,但复杂度高。配置变更场景,长轮询够用。嗯,辉度发布怎么做? 先推给指定 ip 的 实力观察没问题,再全量推送。 alex 的 beta 配置就是这个机制,看到差距了吗?新人只会说,用 nlex 拉取老炮从存储到推送到刷新到灰度,层层递进。差距的本质不是知识量,是方法论。想知道老炮是怎么做到的?我把这道题拆开给你讲清楚。 你有没有想过,为什么配置中心不能用简单的数据库存配置?因为数据库只能拉,不能推。你改了配置服务,不知道得等下一次定时拉取怎么解决?三个核心机制,第一个,长轮询, 客户端发起请求,服务端不立即返回,而是 hold 住。如果配置变更了,立刻返回新配置。如果没变更,三十秒超时后返回客户端,再发起下一次请求。 这就好比你不每天去翻邮箱了,而是站在邮箱旁边等邮递员一来,你就拿到了长轮询比定时拉取实时性好比 webbedband 简单,是配置中心的标配方案。第二个配置,隔离, knuckles 用 nexus 隔离环境 group 隔离项目 data id 标识,具体配置文件、开发环境、测试环境、生产环境的配置互不影响。 这就像一栋楼里不同的房间,每个房间有自己的钥匙,串不了门。第三个,辉度发布不是一改配置,所有实力都生效,而是先推给一部分实力观察 knox 的 beta 配置,只推给指定 ip 的 实力,没问题了再全量推送。 这就好比你做饭,先尝一口好吃再端上桌,不好吃赶紧改,不至于整桌客人吃坏肚子。一句话总结配置中心三件事,常轮询解决实时性,三级隔离解决多环境。辉度发布解决安全发布。

今天面试了一位五年 java 后端,看他简历上写了分布式配置用 knox, 然后我就问了 knox 作为一个配置中心,怎样去实现配置同步的,他说就是客户端会定期拉取配置,然后我又追问定期定期多久?后期的话,如果配置延迟了,那怎么办? 他就傻眼了,支支吾吾说不太清楚啊。这其实也是面试官经常问的一个问题啊,你回答的时候可以稍微扩展一点,可以从服务首次拉取、配置变更以及监听器触发这几个方面去展开。如果你担心简历上的东西讲不出来, 我已经把面试经常问到的一些技术站场景题都整理在两百万次的面试文档了,里面针对每个知识点都有很详细的解析思路,只要你是我的粉丝,留言六六六就可以打包带走。那么首先,服务首次启动的时候如何去获取配置的?当我们的应用服务启动的时候,会通过一个简短的 h t p 请求,向 nasa s 服务端拉取对应的配置。 拿到配置后,客户端会做两件事情,第一,把配置缓存到本地内存里面,方便后续业务代码快速去读取。第二,持久化到本地磁盘文件,这样即使应用重启了,也能从本地文件去恢复,避免每次启动都依赖网络。此后,业务代码提取配置时候,优先走本地的缓存,大大减少了网络开销,提升了性能。 接下来,如果 nasx 配置发生了变更,那么客户端如何及时地感知并更新呢?这里就用到了长轮询机制。客户端在首次拉取配置以后,并不是就此结束,而是会持续向 nasx 服务端发起检查更新的请求。这个请求它是一个长轮询,服务端收到以后不会立即返回,而是把链接挂起,默认等待三十秒, 在三十秒之内,如果配置有变化,那么服务端就会立即返回最新的配置,告诉客户端也会返回一个空的响应,然后避免客户端就一直在挂起。 然后当服务端返回空的响应以后,客户端也会发起一个新的长轮询请求。这种长轮询的方式既保证了配置变更能够被实时地感知到,它的延迟非常非常低,又避免了频繁的短轮询给服务端造成压力。那么我们的应用服务器就是通过长轮询得到配置变化以后会做什么呢? 它会再次发起请求,拉取之前的配置。刚刚我们已经讲了更新本地的内存和磁盘文件,同时呢还会触发注册好的监听机制,然后执行我们的自定义逻辑, 比如说刷新被歪流注解,然后注入的一些属性值,或者说重新促使化某些弊案,这样业务代码就能立即使用最新的配置实现动态的生效。总结一下, nasos 就是 通过首次拉取加上本地缓存,保证了高效的读取,然后再通过长轮询的机制保证了配置变更以后的实时通知, 再配合我们的监听器机制,然后应用能够动态的响应变化。这套设计既轻量又可靠,也让它成为主流配置中心的一个最重要的原因。

ok, 同学们,然后前面的话呢,这种基本的教验啊,以及为了啊发布一些事件存储的数据啊之类的,咱们都已经搞定了,那往下 重新复制一次,粘到咱们的笔记,这好,我把前面这部分就删掉了。好吧,省略部分代码。 好,然后咱们直接开始从下面开始看。好,首先第一个 client id, 咦,还记得这个东西不是由时间戳还有客户端的 ip 以及客户端的端口儿封装成的一个 id 标识,而这个 id 标识的话呢,它传过来之前叫做肯定是 id, 我 记得看这啊,肯定是 id, 对 吧?然后传到了咱们当前的这个位置,然后呢,这块搞了一个可 let manage 点 get, 可 let, 这是什么鬼呀? 好啊,咱们这块用的请求方式是 glp c, 而 glp c 他 们都知道这玩意有个长连接的概念啊,对吧?就这块很明显就是啊, 我的服务端要给你的客户端建立一个连接,而这个连接我要存储到哪呢?存储到这个 client manager 里面,那我这个连接的唯一标识是什么呢?好,就是时间戳加 ip 加端口,我要利用它拿到连接的那个或那个长连接的 client, 比较好理解吧。同学们,好,所以说这一步也就大概知道是个什么鬼了。所以说啊, 基于啊,这个之前传递过来的克奈克神 id 啊,括弧又是他的这个时间戳啊加这个 ip 啊,啥玩意连击的?我忘了哎,好像是下划线啊,时间戳 下划线 ip, 下划线端口,记住,我说的 ip 和端口是客户端的好吧。啊,然后呢,组成的一个,可那个是 id, 然后来获取 获取客户端的这个对象,而这个对象很明显,他应该是在我的客户端。有时看这个图,我在这发起请求之后,我就和你一直建立起了一个连接,这个连接员一直搁这连着, 那我这边就获取一波这个连接的意思。好吧,那如果说超时了,这个连接可能就断了啊,所以说呢,呃,咱们也可以测试一下。好吧,加个断点,然后正常的让我的 client 发一个请求过来。 好,肯定过来了,这是我的神戳,但是我稍等一会,哎,看这同学们,我的 nicholas client 报错了,说明我的 nicholas client 已经结束了。那如果说我的 nicholas client 结束了,长链接肯定没了,所以这样的方式去获取,他应该拿到是个 n, 能看到吧?是个 no。 那 如果说我把断点打在这个位置,我再让他走一次,因为我断点到这,我的可 let 肯定没有结束,那我就拿到了对应的某一个可 let 连接了 啊, ip 是 本地,端口是幺零九六九,就算是我的 id 发出来的吗?对吧?好,行了,那其实你看这块,哎,这个奈克斯可 let 又凉了。那其实这块已经断开了,但是毕竟我拿到这个对象,所以这块呢,注意看 take 可 let is 什么 lego 能不能用,对吧?那很明显,这会会判断你可 let 是 不是孬啊? 你可 let 这边是不是要搞什么临时的?谁?看来这玩意也有一个所谓的临时啊,原因是什么?就是当你要注册一些持久服务的时候,看来他也不需要搞这种所谓的长链接,因为不, sorry, 是 搞那个持久服务是不需要这种长链接的,因为持久服务咱们前面说过,人工上线和下线 就这个位置。很明显啊,你这个肯定是临时的好吧,一个临时的链接,你那边凉了也就凉了啊。这个无所谓了。好吧,不用去关注了。行,反正总之啊,到了。咦,我跑哪去了? 好,搁这那这块会做一个判断,正常往下走了。那就当然,我这块注册其实可能会出问题,但是无需关注。好吧,那咱们知道了这块在干什么也就可以了。 好吧,这是咱们的一个关键点,拿到你客户端的那个连接对象。那当然,什么时候存的?不知道,你也可以看一下。 client manager 有 get client 对 吧?往里走看谁呢?依然是有一个 delegate 委托。那委托的话呢,大概率咱们是走临时的这个东西,对吧?那应该是他 临时的。好看,有个可览词点儿 get。 可览词是什么?哎,又是一个 concurrent hash map, 那 string 很 明显就是你的时间戳 ip 加端口,而后面这个 ip port base client 应该就是你那个连接对象了。 好吧, very easy 了吧,同学们。行,那甚至啊,为了方便大家看的更清楚,我可以在这个里面给它再加上一个断点,让它获取的时候我可以直观的看到 class 里面有什么东西。好吧,正常放行,我再走一次,断点肯定会到这,对吧, 行啊啊啊。 呃,断点卡哪了?我还真不知道断点卡哪了哎。断点没进来啊,同学们,没进来啊。那那这这有有一点小尴尬,但是没关系啊,我把他先强制停止一下,然后我还是把断点放这。哎,难道他走的是默认的这个啊?可能走的是这个, 可那个神这个好吧,走的是这。哎呀啊,他没有走那个临时好吧,不一样不一样不一样,他没有走那个临时的,应该走的这个好,让他往里走。好,到这了,看一下克拉斯里面啥玩意, 哎,这不是咱们说的那个吗?对吧,连接过来就有了,然后展开。大哥,大哥,好,展开它的 value, 就 这玩意儿。 好吧, value 就 这玩意啊,你的一个肯定个神 id 啊。然后后面有很多这样的信息,还有什么 last time, 还有什么 reverse reversion 啊,干嘛都不知道。好吧,反正连着呢。呃,我也想看一下里面还有点啥玩意啊。 attribute 连接方式, g r p c 原数据,可那个 type 看可 let 的 id, 这个是我 windows 的 ip 地址好吧,还有 remote id 啊,本地 ip, 然后呢?还有本地的多少号?很明显是 idea 搞的这个对吧,然后还有一些其他的信息看, 行啊,知道是啥就行了。好正常的放行。哎,大哥,走开好了,那这边就正常的通过他拿到了,他依然是一个肯开拿下西麦,好吧,所以说回到笔记这,然后呢,这个 这个可 let 应当是 rpc 啊, grpc 请求 过来时啊,直接将咱们的客户端信息啊信息存储到了这个实体里,这个实体里的 concur 阿奇麦克里 对象中。好了,反正呢,最终一句话啊,我在这能够咦咦嗯哦, 内部里的这个东西得了好了,反正这里面呢存,然后呢,我正常在基于这个 id 把它取出来,然后取完之后呢,在这啊,针对可让他做一波叫验 好吧,针对你的可烂,你可烂,他不能为空对吧?可烂他不能为空。然后呢?呃,不能是这个什么呢?咱们刚才看的这波娇艳回头就是这一步,第一步是可烂他不能为空第二个呢是可烂,他得是这种临时的。 好吧临时的。然后呢其实咱们刚才也加过段点去看了,如果想看细节的话呢。哎当时手欠给他关了是吧。可以再来一次可以再来一次嘛。看咱们这个获取到的实力里面 伊兹伊兹。哎呀,这还得看他的方法。伊兹,看来这个方法是他的子类里面啊。 哎他没有实现。那没有实现这个方法就很尴尬。就是咱们现在想看什么呢?就是他的这一步他拿 clone 执行了这个方法,但我现在在这个 clone 里面并没有看到这个方法。呃这个方法是谁提供的呢?我按住 ctrl 进去看一下吧 好吗。负接口了,他有实线啊,搁这呢。好了,知道了,同学们固定就返回处。好吧。固定就返回处他既然返回处这能进来吗?啊这进不来。好吧,看就是你连接方式的一个不同啊。 ok, 拿过来不能空。不能是这个非临时客户端啊。行, 反正 client 没有问题。之后往下来这边做了一个事儿叫做 get publish 音符把 instance 传去了。这一步在干嘛呢?其实很简单啊,它把时域里的信息又封装成了一个 另外的这个实力的对象,这个说白就是我作为注册到我 nex 的 服务的信息。哎,我要用它去存。那这里面的话呢应该就是构建了一些小小的东西给它找回来。返回返回返回返回。呃。断点先去掉得了。我这么挑过来吧 明白吗。挑多了有点恶心啊,就这好看, ins 给人去了,在里面干嘛了? 创建这个实力,因为它本身就要返回它嘛,第一步就是创建,然后这边的话呢,又构建 map, 往里面放各种什么原数据啊,什么这个这个 instance id 啊,还有权重啊,是否开启啊,再往下还有你的集群名啊,是否健康啊,这怎么又设置一次集群名啊?啊, 好吧啊,反正啊,就各种设置啊,最终就生成了你的 instance publish, 而你的 instance 对 象肯定也是正常放在里面的。 好了,反正就是封装一堆信息啊,所以说来到这,就是将你的 instance 实立封装为一个叫做 instance publish in fall 的 对象。那这个就是咱们最终注册的位置了,应该是剔除一些无关的数据,它只保存了最核心的, 搞定之后干嘛呢?好,同学们,这一行就是注册了,这行就是注册服务 的核心点,哈哈哈哈,那到底咋注册的呢?可 let 咱们前面已经看过了,这哥们是谁呢?是咱们最开始看到的这个 connection base client。 那 我这边发起注册就是用可 let 对 象点 a, d, d service instance 好, singleton 是 你之前的 service, 而 instance 音符是我在这封装的一个实力,就是你之前的 instance 封装成它了。好,那这里面干嘛了呢?摁住 ctrl 进去。好,创建方法,那我得看它的实现,实现是谁呢? 你一共就两个,看它吧, ip pod base client, 你 为啥看它呀?因为之前咱们的那个 client manager 是不是看的这个 client manager 里面放的是一个叫做 connection base client? 好 吧,这是咱们具体的一个 client 的 对象,而回到咱们的这个位置, 它 a d d 的 时候,你发现有那个吗?没有那个实力。好吧,那我就正常的只能去看这个对象了,因为咱们之前加断点的话应该看过,其实就是咱们要看的下面一个 ip port base client。 我断点加的有点多啊,同学们,我得把别的断点删一下啊。 sorry, 之前的断点还没放行呢。好吧,还没放行呢,那我就给它放了吧。好,那这次到这不行,我得再重新走一次啊。 再来一波断点,看一下这个 client 的 类型。好,依然是 clientbase client。 那 这回就有问题,那我这点 a d d, 它这得能进到哪啊?好吧,看到第一个了吧。 abose tract 有 一个抽象类,那看来它下面的实线有很多包含了 这个东西,所以说既然它里面没有,那必然走这份负累的方法了。能懂我什么意思吧。啊,就是我正常想看到的是它这边的这个类型叫做 connection base client, 但是它没有啊,那很明显子类没有的方法,找谁找负累呗。 好了,那最终走的是 abstract client, 看来并不是下面这个。好吧,得回搂一眼。那走的是它,那这块就是它的一个具体的注册流程了。那这块咱们要给它捋顺一下 啊。走的是啊,负类的 abstract 中的 a d d service instance。 原因很简单,它当前类也就是 connection base。 哎, sorry, 是是是是是是,哎呀,奶奶个腿,是他这个 connection base client 这个里面它是没有实现的好吧,它没有重写这个方法,所以说正常的走复列就可以了。 没有提供此方法,那走的是副类的。行了,那看一下吧,这是咱们最核心的一个点了,那在副类里面什么流程啊?就这么点代码来简单看一下。首先第一个复制过来吧。啊,我还是不太喜欢用那个看 啊,注册服务最最核心的点好吧。然后呢,首先第一个看一下,哎,你这边的这个,呃, instance public 它是不是批量的呀?如果批量走这个逻辑,那很明显咱们现在没有批量,对吧?所以第一个判断啊,如果是批量 注册走 eve 逻辑,那很明显我不是批量。好,那到 else 咱们当前走的单个服务 注册过程这个逻辑。好了,有个 publish 啊, publish, 这是什么鬼啊?嘿,其实两个都用它了,对吧?过去好了,写个这玩意复制一下粘过来。 又是一个肯 car 拿息 app, key 是 service 啊, value 是 你封装好的 instance publish 音放好了,只要我把我的服务信息甩到这个肯 car 拿息 app 里面了。好了,完成注册。 添加完毕,那就完成了注册,而这个 publish put 然后放进去之后,如果返回 none 代表之前没有这个 service, 说明是第一次注册,那第一次注册的话,这块还有一个计数,而看名字猜意思大概就知道这个东西的目的应该是为了做一些这种。呃,类似于监控相关的事。这个监控相关的事, 好吧,应该就是咱们当前的这个 instance count 就是 实力个数加一好吧,就应该是代表当前 nichols server 中注册的实力个数啊,加一 好吧,你看前面可能就是加的更多一些好了,那紧着往下干嘛了呢?又发布了一个事件,这个事件叫啥?可 let 的 疑问客户端 事件,哎,客户端趁之疑问的同学们猜一下。首先第一个我服务端增加一个,那得是我的 server 端的事件,现在是可 let 的。 很明显这里发布的事件 大概率应当是让咱们的服务订阅者。 记住咱们现在是注册服务,那我注册上去的服务可以让其他的服务去使用,那使用咱们注册这个服务的就可以叫他服务订阅者,那说白让他干嘛。哎哥们我这边有了什么?有了新服务了,那你这边是不是要同步一下呀, 对吧。所以说可能包含了集群的同步,也可能包含了其他服务订阅者。你的这个服务情况可能要再加一个了。等等等等。好吧,就这里呢。呃像服务订阅者或者是其他 nicholas 节点 同步这个新的服务啊。反正我发布了一个新事件可能是干了一个这样的事。最后呢啊有个日制啊, client change for service 反正就是多了一个服务。哪个 client id 好。 最终 return true 代表注册成功完事了。所以说最终的注册代码就这一行。 把你的服务往这里一扔,而扔的是最开始的 service 加上我急于 instance 封装的一个新对象没了,而后面 last update time 修改客户端的最后修改时间啊。然后这个呢叫什么瑞卡?这个不太认识啊哈哈哈。啊,不太认识。好,就这这个啊,按住卡上键来。这是个什么属性? 嗯,不到。那咱们看一下它的实线吧。它的实线干了点什么事?那很明显了,是不是有这个可那个神贝斯卡拉特。那我就看它啊。 reason a, d, d and get 好 了,加了个一。看来这个东西可能是一些这种变化次数类似于版本啊,不认识。好,那就哈哈哈,翻译点百度啊。我也不认识。 修改啊,修改版本大概率是这意思吧。反正就是版本号加一吧啊哈哈哈哈。 ok 啊,修改最后时间,然后呢?貌似啊是版本号加一,哈哈 就是连接的版本号。好吧,连接有变化啊,那再看一下,反正正常的话呢,咱们已经确认过 colant 对 象是这个 congen base colant 了,那这边必然走的也 闭眼走的就是他了啊,闭眼走的就是他了啊。行,那也没啥了。最后还有俩事件,你猜吧。我也不知道这俩事件是干嘛的 啊。第一个啊,可懒的 operation 事件,客户端注册服务事件啊,说白了就是客户端 成功的注册了一个服务,发布一个事件,而且这个事件里面带了什么,哪个服务注册进去了以及哪个客户端。 好吧,哪块用不知道不知道,后面涉及到再说好吧。然后紧接着再往下又发布了一个事件原数据,对,他疑问呢,这个咱们之前看过,同学们还记得吧。这个看过,在哪看的来着?来, mateta data event, 这是 service。 mateta data event 就是 服务原数据时间,就是获取那个单立 service 的 过程。好吧,而咱们这边是什么呢?实力 原数据事件跟他不一样,同学们一个是 service, 一个是实力,之前是我确认把我的 service 放到了这样的一个 mac 里。好,我发布了一个事件,而这次是我的实力真正的注册到了我的 nexus, 哎,又发布了一个关于他的原数据的事件,好吧,发布 实力完成注册的一个事件,好吧,还是一样的,干嘛的?不知道。好吧,咱们暂时先不要去扩展每一个事件是哪个位置,通过这个呃呃 application 的 那个 listener 去监听的。干了什么事?先不用去关注,要不然太多了。 好了,那这样的话,咱们整个注册流程也就搞定了。其实到最后的本质应该能猜个差不多了,或者说都不用猜了,已经知道了本质最终点就是服务会注册到这, 利用 service 啊,这东西是可以获取到的,而至于订阅者到底怎么拿到的先不管,反正到这就代表服务做得成功。好,到这 还是一样的,先把咱们具体代码放这一份,说一下咱们在这边的整个过程。首先第一步呢,是基于咱们的 connection id 获取到客户端的连接对象,这是第一个事啊,拿到连接对象之后呢,会对连接对象做一些基本的教验,这就不说了。第二步呢,会将咱们的 instance 实力再次封装, 搞成一个什么呢?叫做 instance publish 音符啊,这样搞对之后呢?第三步,将 service 作为 key, 将封装好的这个实力作为 value, 扔到 client 对 象里的一个 publish 的 concur 的 哈普,这个 concur 的 哈西麦普中。好,到这儿完成注册了。好, 完成注册之后再修改可 let 的 这的一些这个最后修改时间啊,最后修改修改时间以及版本。然后第五步,发布俩实践啊,啥实践啊,猜的具体干嘛的,不知道后面谁到再说。 ok 了,那这样,咱们针对这个逻辑,我这发起请求以及到我这接收请求完成注册也就搞的差不多了。好,那为了让大家一会更清晰这个流程啊,咱们一会给他画一张流程图,然后呢?咱们后面 看到流程图大概就能知道整个过程是如何搞定的了。 ok, 行,那咱们先到这,下一刻咱们画张图。