关于源码学习:Java-SPIDubbo-SPISpring-SPI-三种SPI分析

零碎整顿下Java SPI,Dubbo SPI,Spring SPI。 Java SPI简述有点相似于策略设计模式,定义好接口,在文件中写实现类的全路径名。调用ServiceLoader.load的时候返回一个迭代器,他外部是一个懒加载,当调用hasNext的时候才会依据全路径名读取文件,调用next的时候才会实例化。实质上就是,获取接口全路径名,安标准去该门路下按行读取文件,而后用同一个类加载器加载类,返回。(源码很简略,就不多说了,应用办法看图) 长处相似于模板办法,定义好接口,实现能够齐全由第三方来写,依照标准就行。 毛病人家本人也说了,一个简略的服务提供者的加载工具。人家源码开发者就没想写的多好用,就是写个demo秀操作呢。 Dubbo SPI简介官网:https://dubbo.apache.org/zh/d... 长处JDK 规范的 SPI 会一次性实例化扩大点所有实现,如果有扩大实现初始化很耗时,但如果没用上也加载,会很浪费资源。如果扩大点加载失败,连扩大点的名称都拿不到了。比方:JDK 规范的 ScriptEngine,通过 getName() 获取脚本类型的名称,但如果 RubyScriptEngine 因为所依赖的 jruby.jar 不存在,导致 RubyScriptEngine 类加载失败,这个失败起因被吃掉了,和 ruby 对应不起来,当用户执行 ruby 脚本时,会报不反对 ruby,而不是真正失败的起因。减少了对扩大点 IoC 和 AOP 的反对,一个扩大点能够间接 setter 注入其它扩大点。然而我跟了源码,不是一次性加载所有,是调用的时候创立(java 版本1.8.0_211) 剖析既然是增强,那其实实质上也是差不多的,就是获取到自定义实现类。我先看了下目录下的文件,是key,value的模式,那么猜想就是依据增强点应该就是依据key获取到指定的实现类。看了下源码,调用com.alibaba.dubbo.common.extension.ExtensionLoader#getAdaptiveExtension的时候,就会进行解析对应的文件,后果如下 adaptive然而外面没有自适应的,比方ExtensionFactory获取的时候,解析到adaptive标签,会缓存到cachedAdaptiveClass如果没有获取到他会拼接字符串+编译的形式生成一个,代码如下package com.alibaba.dubbo.rpc;import com.alibaba.dubbo.common.extension.ExtensionLoader;public class Protocol$Adpative implements com.alibaba.dubbo.rpc.Protocol {public com.alibaba.dubbo.rpc.Exporter export(com.alibaba.dubbo.rpc.Invoker arg0) throws com.alibaba.dubbo.rpc.Invoker {if (arg0 == null) throw new IllegalArgumentException("com.alibaba.dubbo.rpc.Invoker argument == null");if (arg0.getUrl() == null) throw new IllegalArgumentException("com.alibaba.dubbo.rpc.Invoker argument getUrl() == null");com.alibaba.dubbo.common.URL url = arg0.getUrl();String extName = ( url.getProtocol() == null ? "dubbo" : url.getProtocol() );if(extName == null) throw new IllegalStateException("Fail to get extension(com.alibaba.dubbo.rpc.Protocol) name from url(" + url.toString() + ") use keys([protocol])");com.alibaba.dubbo.rpc.Protocol extension = (com.alibaba.dubbo.rpc.Protocol)ExtensionLoader.getExtensionLoader(com.alibaba.dubbo.rpc.Protocol.class).getExtension(extName);return extension.export(arg0);}public com.alibaba.dubbo.rpc.Invoker refer(java.lang.Class arg0, com.alibaba.dubbo.common.URL arg1) throws java.lang.Class { if (arg1 == null) throw new IllegalArgumentException("url == null"); com.alibaba.dubbo.common.URL url = arg1; String extName = ( url.getProtocol() == null ? "dubbo" : url.getProtocol() ); if(extName == null) throw new IllegalStateException("Fail to get extension(com.alibaba.dubbo.rpc.Protocol) name from url(" + url.toString() + ") use keys([protocol])"); com.alibaba.dubbo.rpc.Protocol extension = (com.alibaba.dubbo.rpc.Protocol)ExtensionLoader.getExtensionLoader(com.alibaba.dubbo.rpc.Protocol.class).getExtension(extName); return extension.refer(arg0, arg1);}public void destroy() {throw new UnsupportedOperationException("method public abstract void com.alibaba.dubbo.rpc.Protocol.destroy() of interface com.alibaba.dubbo.rpc.Protocol is not adaptive method!");}public int getDefaultPort() {throw new UnsupportedOperationException("method public abstract int com.alibaba.dubbo.rpc.Protocol.getDefaultPort() of interface com.alibaba.dubbo.rpc.Protocol is not adaptive method!");}}而后就是依据url中的协定,去找到对应实现,对应的这一行 ...

March 19, 2022 · 1 min · jiezi

关于源码学习:源码学习思绪

源码学习思路Koa的核心文件一共有四个:application.js、context.js、request.js、response.js。所有的代码加起来不到 2000 行,十分轻便,而且大量代码集中在 request.js 和 response.js 对于请求头和响应头的处理,真正的核心代码只有几百行。 另外,为了更直观地梳理 koa 的运行原理和逻辑,还是通过调试来走一遍流程,本文将拆散调试源码进行分析。 以上面代码调试为例: const Koa = require('koa')const app = new Koa()const convert = require('koa-convert');// 日志中间件app.use(async(ctx, next) => { console.log('middleware before await'); const start = new Date() await next(); console.log('middleware after await'); const ms = new Date() - start console.log(${ctx.method} ${ctx.url} - ${ms}ms)})app.use(async(ctx, next) => { console.log('response'); ctx.body = "response"})app.listen(3000);复制代码node 的调试形式比较多,可参考 Node.js 调试大法稍做了解。 一、applicationapplication.js 是 koa 的入口文件,外面导出了 koa 的结构函数,结构函数中蕴含了 koa 的次要功能实现。 导出一个结构函数 Application,这个结构函数对外提供功能 API 方法,从次要 API 方法入手分析功能实现。 ...

January 5, 2022 · 5 min · jiezi

关于源码学习:聊聊读源码这件事

前言对于读源码这件事,每个人心中都有一个哈姆雷特,明天这篇文章聊聊我对读源码这件事的一点高见 为什么读源码读源码的时候,能够先问一下本人为什么读源码?是为了解决问题,还是单纯只是想理解源码的前因后果,更甚者仅仅只是为了面试,毕竟面试造火箭,不懂点源码,都没法去忽悠面试官 读源码首先要弄清楚本人的读源码的动机,以及通过读源码想达到什么目标 读源码的心态读源码是一件很干燥的事件,很多时候咱们会因为一时鸡血,翻下源码,而后发现跟看天书一样 如何让读源码不那么干燥,咱们能够先定一个小指标 咱们能够先把源码拆分成几个小章节,每浏览完,能够给本人处分下,比方玩把游戏,吃个大餐,或者干一下你想做却没做的事件,让大脑失去一个正向反馈,即我做完这个事件,我会失去一些益处。源码有时候干燥,是因为咱们没有失去一个踊跃的反馈,更多时候是 读源码不能抱有浮躁的心态,心急吃不了热豆腐 什么时候适宜读源码在我看来,读源码是建设在你对这个源码的编程语言曾经很相熟的状况,比方你想看k8s的源码,然而你对go语言无所不通,你就一头钻进去钻研,我想你大略前面的终局是 其次是你曾经对这个源码的基本功能有个分明的认知,晓得他的利用场景,能利用他的一些个性来做一些编码,比方你会应用spring的依赖注入,AOP等 最初你对这个源码曾经产生一点趣味,有钻研的欲望了,而不是他人强制你去读,外在的自驱力以及趣味,是做好事件的原动力 如何读源码源码分为两种状况 第一种:很多人曾经在钻研的源码像这种其实没必要一开始就钻进源码看,而是你能够针对你这个源码感兴趣的点,通过搜索引擎查找一下。你也能够通过processon搜一下相干的源码图,比方 不过这种有个不好中央,等于是他人把货色嚼碎了再喂给你,你想想那个画面。最初你还得通过源码验证一下,因为不确定他人剖析的是不是正确的,而且看源码的时候,必须得分外关注一下你看源码的版本,比方你看spring2.5和spring5的版本,会有发现会有很多区别。 间接通过搜索引擎找源码,有个益处就是你能够很快找到你感兴趣调试的源码入口,以及一些绝对比拟外围的代码块。 如果这种大家都钻研过的源码,你也不想通过搜寻找答案,就是只想速成,也有办法的,就是花钱 找个培训机构或者付费教程,基本上这些机构都会教一些支流技术的源码。如果你只想白嫖,也能够去B站搜一下 但不管怎样,你排汇这些后,最初还得本人去跟踪调试验证下,因为只有源码不会骗人 第二种:偏门或者新出的技术如果你钻研的货色,大家钻研比拟少,要么是这个技术不是支流技术,要么就是这个技术将来可能是支流,只是目前受众比拟少。 像这种源码,你也不必急着一开始就钻进源码,而是去官网溜一圈,看看这个技术的一些背景,个性,利用场景,入门案例。基本上每个技术的呈现,是要解决某些问题,而这种技术的呈现,失常会随同和竞品的比照,而这种竞品失常也是大家耳熟能详的货色。比方redisJson和mongdb的比照。对这个技术有个整体的理解后,你能够看下他们的代码仓是否有提供残缺的example或者单元测试,这些example失常提供就是这个技术的一个个性能点,你对这些性能点理解后,你就能够通过断点调试,通过调用栈查看相应的类。具体调试你就能够间接通过在单元测试或者提供的example那边打断点 总结看完源码后,最好能造成一张源码常识地图,以便后续查阅。 聊完源码后,我说一点题外话,原本这篇文章是对之前自定义spi文章的收尾总结,前面是因为有敌人说想晓得我是怎么读源码的,就罗唆写一篇文章。我很少写这种实践的货色,心愿对大家有一点帮忙。 上面贴一下我那个spi我的项目demo链接以及自定义spi相干的文章 demo链接https://github.com/lyb-geek/springboot-learning/tree/master/springboot-spi-enhance 自定义spi相干文章1、聊聊如何实现一个反对键值对的SPI 2、聊聊如何实现一个带有拦截器性能的SPI 3、聊聊自定义实现的SPI如何与spring进行整合 4、聊聊自定义SPI如何应用自定义标签注入到spring容器中 5、聊聊自定义SPI如何与sentinel整合实现熔断限流

December 21, 2021 · 1 min · jiezi

关于源码学习:如何阅读源码-以-Vetur-为例

全文近万字。。。来都来了,点个赞再走吧我很早就意识到,能纯熟、高效浏览开源前端框架源码是成为一个高级前端工程师必须具备的基本技能之一,所以在我职业生涯的最晚期,就曾经开始做了很屡次相干的尝试,但后果通常都以失败告终,起因形形色色: 不足必要的背景常识,犹如浏览天书不了解我的项目架构、设计理念,始终不得要领指标不够聚焦,浏览过程容易复杂化容易陷入细节,在不重要的问题上纠结半天容易追着分支流程跑,扩散注意力没有及时记录笔记和总结,没有把常识碾碎、重组、内化成本人的货色没有解决过特地简单问题的经验,潜在的不自信心理集体毅力、韧性有余,或者指标感不够强烈,遇到困难容易放弃等等这个列表还能够持续往下拉很长很长,总之既有我本人主观认知上的限度又有切切实实的客观原因。起初因为工作的契机硬着头皮看完 Vue 和 mxGraph 的源码,发现事件并没有本人设想中那么艰难,起初前前后后陆续看了很多框架源码,包含 Webpack、Webpack-sources、Vite、Eslint、Babel、Vue-cli、Vuex、Uniapp、Lodash、Vetur、Echarts、Emmet 等等,迟钝如我也缓缓摸索出了一些普适的形式办法,进而斗胆撰下这篇文章,不敢说授人以渔,但至多也该抛砖引玉吧。 所以这是一篇为哪些无意,或筹备,或曾经在浏览前端框架源码的同学而写的文章,我会在这里抛出一些通过我集体屡次实际总结进去的浏览技巧和准则,并联合 Vetur 源码,具体地解说我在浏览源码的各个阶段所思所想,心愿能给读者带来一些启发。 弄清楚指标在介绍具体的技巧之前,有必要先跟读者探讨一下浏览源码的动机,想分明到底需不需要通过这种形式晋升本身技能,尽管学习优良框架源码的确有十分多不言自明的益处,但每个人的教训、所处的语境、诉求、思维习惯不同,理论学习效果在不同个体或个体的不同期间必然存在极大的差别,这外面最大的变量一是教训,二是指标,教训因人而异,且很难在短时间内补齐,没有太多探讨空间;倒是指标方面值得盘道盘道。 第一层,先弄清楚为啥要浏览源码?可能的起因有很多,例如: 为了增进对框架的认知深度,晋升集体能力为了应答面试为了解决当下某个辣手的 bug 或性能问题基于某些起因,须要对框架做二次革新反正闲着,也不晓得该学点啥,试试呗。。。好奇这外面有一些很形象,例如最初一个“好奇”;有一些很具体,例如“为了做二次革新”;还有一些在具体与形象之间。依照 SMART 准则的说法,越具体、可掂量的指标越容易达成,如果读者的指标还处在比拟不置可否,不够具体具体的阶段,那执行过程大概率会翻车,毕竟这是一件特地耗费精力与耐性的活儿。 对于这种状况,我的倡议是无妨往更细节的档次再想一想,例如对于最初一点“好奇”,能够想想具体有哪些个性让你特地神奇,值得花工夫精力去粗疏地摸索,放在 Vetur 语境下能够是“我想理解 Vetur 的 template 谬误提醒与 eslint 如何联合在一起,实现模板层面的谬误提醒性能”,这就很具体很容易掂量了。 第二层,读者如果曾经有了明确、具体、可掂量的指标,无妨在开始之前先自问几个问题: 当下的确须要以浏览源码的形式增进本人对框架的认知深度吗?有没有一些更轻量级,迭代速度更快的学习形式?你所选定的框架,其复杂度、技术难度是否与你当下的能力匹配?最好的状态是你自认为踮踮脚就可能到,过高,不具备可行性;过低,ROI 不值当。如果通过这番斟酌之后,必要性、可行性、相关性都与集体指标符合,那就没啥可犹豫的。 第三层,须要辩证地去对待所谓“指标” —— 不是把整个我的项目残缺读完读通才叫胜利,如果能从一些语句、片段、部分模块中习得新的设计思维、工具办法,甚至仅仅是命名标准都能够算作集体的一点提高,千里之行;始于足下远比拔苗助长靠谱的多。所以一开始没必要把指标定的太高,能刚刚好满足本身需要是最好的,过程中如果发现问题域的复杂度在一直收缩变大,继续投入很多工夫却始终没有显著功效的话,那倡议果决放弃或者申请外援,从新评估指标与可行性之后再做决定。 总之,这是一个预期治理的问题,咱们能够多参考 SMART 准则,多从具体、可掂量、可行性、相关性几个维度思考,一直斟酌是否须要做这件事;如何拆解指标,用指标反推打算,一直推动集体胜利。 浏览技巧理解背景常识常识是造成了解的必要条件,开展学习任何一个开源我的项目之前都有必要花点工夫调研我的项目相干的基础知识,渐进构建起一套属于你本人的常识体系,这包含: 优质参考资料 —— 收集一波品质较高的学习材料,收集过程能够同步通读一遍框架是如何运行的 —— 也就是所谓的入口IO —— 框架如何与内部交互?它通常承受什么状态的运行参数?输入什么模式的后果?生态 —— 优良的框架背地通常都带有一套成熟的生态系统,例如 Vue,框架衍生品如何补齐框架自身的性能缺失?它们以何种形式,以什么样的 IO 与主框架交互?遵循怎么样的写法规定?如何断点调试 —— 这简直是最无效的分析方法,断点调试可能帮忙你粗疏地理解每一行代码的作用。留神,这里的指标是迅速构建起对于这个开源我的项目的形象 —— 甚至不太精确的常识框架,有意思地防止陷入无尽的细节中,就像在浏览一篇文章的时候,能够先看看目录构造粗略地理解文章的信息框架,理解文章大略内容。 例如,我刚开始学习 Vetur 的时候只晓得这是一个 VS Code 插件,但齐全不理解插件怎么写、怎么运行、怎么实现语言个性,所以我做的第一件事件是仔仔细细浏览 VS Code 的官网文档(所幸文档十分齐全,不像某驰名打包工具),学习对于插件开发的基本知识,包含: 进一步总结对于 VS Code 语言插件的因素: 怎么写插件:通过 package.json 文件的 contributes 、main 等属性,申明插件的性能与入口怎么运行:开发阶段应用 F5 启动调试怎么编写语言个性:应用 词法高亮、Language API、Language Server Protocol 三类技术实现VS Code 畛域的常识量还是很宏大的,学习背景常识并梳理成这种高度结构化、高度形象的脑图可能给你一个更高层、全面的视角,现实状态下,后续理论剖析源码的时候这些骨架脉络可能让你十分本能地映射到某一个切面的知识点,事倍功半。 ...

September 15, 2021 · 4 min · jiezi

关于源码学习:Nebula-Graph-源码解读系列-|-Vol00-序言

本文首发于 Nebula Graph Community 公众号 Nebula Graph 是由杭州欧若数网科技有限公司(官网:https://www.vesoft.com/cn/)开源的一款分布式图数据库,它次要用来解决随同着海量数据产生,在关联数据分析、开掘方面面临的新挑战。自 2019 年 5 月开源以来,Nebula Graph 受到了宽泛的关注,许多企业、技术团队、开发者将 Nebula Graph 利用到业务上构建常识图谱、风控、数据治理、反欺诈、实时举荐等场景。在 Nebula 社区中,越来越多用户从案例分享中把握 Nebula Graph 的应用办法,与此同时,呈现了一种声音,局部用户心愿能理解 Nebula Graph 背地的实现思路和原理。 在这样的背景下,咱们心愿通过 Nebula Graph 源码解读系列,剖析设计思路和实现原理,帮忙大家深刻理解 Nebula Graph,更好地应用 Nebula Graph,同样的,这也将有利于你和 Nebula Graph 社区一块共建更好的 Nebula Graph。 内容概述源码解读系列次要从 Nebula Graph 零碎架构和外围模块开展,此外针对社区用户关怀的架构限度带来的性能问题将在最初一个章节剖析此类问题。 源码解读系列虽名为源码解读,但并非只是对代码实现的剖析和函数解说,更侧重于从设计角度带你把握 Nebula Graph 实现原理,透过实现的代码来理解背地的设计思路。(因为 Nebula Graph 目前仍处于疾速迭代阶段,继续有新性能进入主分支,故局部一直迭代的外围模块的解说不会过多地深刻代码细节)。 目前源码解读系列章节布局如下: Nebula Graph Overview:带你理解 Nebula Graph 架构和代码仓散布、代码构造和模块布局;外围模块解说:讲述语义剖析、优化、调度等零碎模块,Java、Python 等各类客户端的运行原理;组件通信:讲述 Nebula Graph 中通信机制;2.0 新个性解说:从 Variable Length Pattern Match 和索引抉择两个点切入讲述 Match 实现的原理;架构限度和解决方案:针对社区的慢查问停止、超大点解决的问题讲述对应的解决方案;心愿大家读完本系列内容之后,对 Nebula Graph 有肯定的理解,明确 Nebula Graph 新性能的实现原理,遇到问题时能从实现角度更快定位问题解决问题。以及,在 Nebula Graph 仓库奉献代码时能更好地写出合乎 Nebula Graph 设计思路的代码。 ...

September 1, 2021 · 1 min · jiezi

关于WPF:WPF源码阅读-InkCanvas选中笔迹

本文接上一篇WPF源码浏览 -- InkCanvas抉择模式,本文介绍笔迹的抉择过程及选中后的高亮显示办法,文中若有了解谬误的中央,欢送大家斧正。抉择成果如下图所示: InkCanvas是WPF中用于墨迹书写的控件,其具备书写、抉择、擦除等模式。依据上图,能够看出笔迹的抉择性能由如下三局部组成: 抉择笔迹(Lasso Stroke)动静抉择选中后高亮显示本文将首先介绍抉择模式的激活过程,而后介绍如上三局部内容WPF是如何实现的。 抉择模式的激活从图中能够看出,切换到抉择模式后,鼠标按下挪动绘制的成果为黄色点状虚线(Lasso),依据Lasso及肯定的算法进行笔迹的选中与勾销选中。 先看InkCanvas切换到抉择模式后的动作。切换到抉择模式后,EditingMode扭转,调用OnEditingModeChanged办法,该办法调用RaiseEditingModeChanged办法。RaiseEditingModeChanged办法中,调用了_editingCoordinator.UpdateEditingState办法,并通过OnEditingModeChanged引发事件。 切换到EditingCoordinator类,能够看到顺次调用UpdateEditingState() -> ChangeEditingBehavior() -> PushEditingBehavior()。UpdateEditingState办法调用GetBehavior办法拿到新Behavior(SelectionEditor)。PushEditingBehavior办法会撤消之前的Behavior,并激活新的Behavior,即SelectionEditor会被激活。 切换到SelectionEditor类,在其OnActivate办法中监听了事件,在OnAdornerMouseButtonDownEvent办法中,调用了EditingCoordinator.ActivateDynamicBehavior办法激活了LassoSelectionBehavior。至此,抉择模式已激活,并将随着设施挪动绘制Lasso。 // InkCanvasprivate static void OnEditingModeChanged(DependencyObject d, DependencyPropertyChangedEventArgs e){ ( (InkCanvas)d ).RaiseEditingModeChanged( new RoutedEventArgs( InkCanvas.EditingModeChangedEvent, d));}private void RaiseEditingModeChanged(RoutedEventArgs e){ Debug.Assert(e != null, "EventArg can not be null"); _editingCoordinator.UpdateEditingState(false /* EditingMode */); this.OnEditingModeChanged(e);}// EditingCoordinatorinternal void UpdateEditingState(bool inverted){ // ... EditingBehavior newBehavior = GetBehavior(ActiveEditingMode); ... ChangeEditingBehavior(newBehavior); // ...}private void ChangeEditingBehavior(EditingBehavior newBehavior){ // ... PushEditingBehavior(newBehavior); // ...}private void PushEditingBehavior(EditingBehavior newEditingBehavior){ // ... behavior.Deactivate(); ... newEditingBehavior.Activate();}// SelectionEditorprivate void OnAdornerMouseButtonDownEvent(object sender, MouseButtonEventArgs args){ // ... EditingCoordinator.ActivateDynamicBehavior(EditingCoordinator.LassoSelectionBehavior, args.StylusDevice != null ? args.StylusDevice : args.Device);}抉择笔迹(Lasso Stroke)LassoSelectionBehavior继承自StylusEditingBehavior,随着设施的挪动,会调用AddStylusPoints办法。该办法会调用StylusInputBegin、StylusInputContinue办法。StylusInputBegin会调用StartLasso办法,该办法创立了LassoHelper对象,该对象将绘制Lasso。 ...

April 6, 2021 · 2 min · jiezi

关于源码学习:ioredis源码阅读0

最近因为工作须要,要去搞一个 Node.js 端的 Redis Client 组件进去,临时抉择通过 ioredis 来作为 fork 对象。 因为之前有遇到过 Redis 在应用 twemproxy 时会始终呈现无奈连贯服务器的问题,详情见 issues:https://github.com/luin/ioredis/issues/573 所以会批改源码批改这一问题,不过在批改实现之后跑单元测试发现,事件没有那么简略,并不只是 info -> ping 这样,所以只好去相熟源码,而后针对性地调整一下逻辑。<!--more--> ioredis 我的项目构造从我的项目中看,源码都在 lib 文件夹下,是一个纯正的 TS 我的项目。 lib 目录下的文件次要是一些通用能力的提供,比方 command、pipeline以及数据的传输等。 .├── DataHandler.ts # 数据处理├── ScanStream.ts├── SubscriptionSet.ts├── autoPipelining.ts├── cluster # Redis Cluster 模式的实现│   ├── ClusterOptions.ts│   ├── ClusterSubscriber.ts│   ├── ConnectionPool.ts│   ├── DelayQueue.ts│   ├── index.ts│   └── util.ts├── command.ts # 命令的具体实现├── commander.ts # command 的调度方├── connectors # 网络连接相干│   ├── AbstractConnector.ts│   ├── SentinelConnector│   ├── StandaloneConnector.ts│   └── index.ts├── errors # 异样信息相干│   ├── ClusterAllFailedError.ts│   ├── MaxRetriesPerRequestError.ts│   └── index.ts├── index.ts # 入口文件├── pipeline.ts # 管道逻辑├── promiseContainer.ts # Promise 的一个封装├── Redis # `Redis 实例的实现`│   ├── RedisOptions.ts│   ├── event_handler.ts│   └── index.ts├── script.ts├── transaction.ts├── types.ts└── utils # 一些工具函数的实现 ├── debug.ts ├── index.ts └── lodash.ts而下分的两个文件夹,redis 与 cluster 都是具体的 redis client 实现,cluster 是对应的 cluster 集群化实现。 所以在看 README 的时候咱们会发现有两种实例能够应用,https://www.npmjs.com/package/ioredis ...

December 15, 2020 · 6 min · jiezi

AtomicReference源码学习

接着前两篇的AtomicBoolean和AtomicInteger再来看看AtomicReference类上的注释说明:An object refenrence that may be updated atomically.用来原子更新对象的引用。一、AtomicRefenrence属性 private static final Unsafe unsafe = Unsafe.getUnsafe();private static final long valueOffset;private volatile V value;static{ try{ valueOffset = unsafe.objectFieldOffset (AtomicReference.class.getDeclaredField("value")); }catch(Exception e){ throw new Error(ex); }}二、构造器 /***Creates a new AtomicReference with the given initial value*/public AtomicReference(V initialValue){ value = initialValue;}/*** Creates a new AtomicReference with null initail value*/public AtomicReference(){}除了上面的属性、构造器外,AtomicReference与AtomicBoolean、AtomicInteger在方法上都差不多,这里只提一个方法: /***Atomically sets to the given value and returns the old value.*/public final V getAndSet(V newValue){ return(V)unsafe.getAndSetObject(this,valueOffset,newValue);}这个方法同AtomicInteger一样是在Unsafe类里进行自旋,与AtomicBoolean略有不同。 ...

July 5, 2020 · 1 min · jiezi