这里有一个源码调试方法,短小精悍,简单粗暴,但足够好用。

你好呀,我是歪歪。

上周发布了《我试图通过这篇文章告诉你,这行源码有多牛逼。》这篇文章。

文章中有这样的一段描述:

然后有个读者来问我:

是怎么把 JDK 源码中的一行代码给注释掉的?

这个问题确实不错,属于一个偶尔用一下能起到奇效的源码调试技巧。所以我决定写个文章来说明一下这个问题。

但是这个技巧确实非常的简单,简单到一句话就能说明白,所以正如标题说到的“短小精悍,简单粗暴,但足够好用”,这篇文章也会非常的短。

首先,把问题换个问法,既然我能把源码注释了,那说明我能修改源码。所以,问题就变成了:我怎么去修改 JDK 的源码呢?

这个问题有很多个回答,但是我这里的回答很简单。把源码拷贝一份出来,原模原样的放一份到自己的项目中即可。

就像是这样:

然后你在使用的时候,直接用你 CV 过来的源码,就行了:

但是我一般使用这个方法的时候,CV 过来时,会把类名称重命名一下,以示区分,其他的啥都不改。

反正不管怎么样吧,这样在你的项目里面有一份“源码”了,这个“源码”和 JDK 里面的源码一模一样,这样你就能随便进行修改了。

比如,我在调用 put 方法的时候,加一点日志输出:

这样测试用例跑起来的时候,就能直接输出你添加的内容:

你都能添加代码了,注释代码,甚至是修改代码逻辑,那还不是手到擒来的事情吗?

对于一些比较复杂的场景,比如异步或者循环等等场景,当你想要在源码中加入输出语句方便进行学习和调试的时候,你就可以用到这招。

这就是我这篇文章要教你的一个关于 JDK 源码的调试技巧。

整体用处不大,但是当你能想到用它的时候,就是发挥奇效的时候。

既然话题都到这里了,那么我再给你补充一个关于第三方框架的类似的调试技巧。

还是先举个例子。

比如我在项目中使用到了 @Async 注解,然后有一个自定义线程池,发起一个请求之后可以看到确实是使用了我的自定义线程池:

然后,问题就来了。

假设,我想让 @Async 注解支持 EL 表达式,也就是这样的写法:

目前,Spring 是不支持这样的配置的,当你这样配置并发起调用,会抛出这样的一个异常:

它会把 ${thread-pool.name} 认为是一个 Bean,然后 Spring 里面并没有这样的一个 Bean,所以抛出找不到 Bean 的异常。

那么怎么才能让 @Async 注解支持 EL 表达式呢?

我之前写过《舒服,给Spring贡献一波源码。》这篇文章,里面用的就是这个案例,有兴趣的话可以去看看,我就不展开说了。

在文章里面,经过分析,我们知道只需要在 org.springframework.aop.interceptor.AsyncExecutionAspectSupport.findQualifiedExecutor(BeanFactory,String) 这个方法中,加入这几行代码就行了:

if (beanFactory instanceof ConfigurableBeanFactory) {
 EmbeddedValueResolver embeddedValueResolver = new EmbeddedValueResolver((ConfigurableBeanFactory)beanFactory);
 qualifier = embeddedValueResolver.resolveStringValue(qualifier);
}

但是我当时采取的方案是通过 idea 的 Evaluate Expression 功能:

经过评论区提醒,其实用 CV 大法,更加直接、方便。

同样的道理,直接把 AsyncExecutionAspectSupport 这个类粘到我们自己的项目中去:

这里需要注意的是,要保证包名称也一模一样,因为这个方法的底层逻辑是基于类加载机制实现的。

这样,我们就能针对我们自己项目中的 AsyncExecutionAspectSupport 类进行修改:

再次发起调用,这事儿就算成了:

这个方法,适用于任何你能拿到源码的任何第三方框架。

虽然,很多第三方框架里面都会主动留下足够多的扩展点,以便使用者进行定制化开发。

所以我提供的这个方法好像用处并不是很大,但是我当年看 Dubbo 源码的时候,就是这样的看的。

就像是这样,在源码里面加入了大量的输出语句,然后基于输出语句去做分析:

虽然现在想起来,更加正确的操作应该是基于它的 SPI 机制去做。

但是,管它呢,反正当时我就是靠这种歪门邪道,也看的明明白白的。

好了,以上就本文的全部内容。

突出的就是一个短小精悍,简单粗暴,又足够好用。

玩去吧。

本文转载于网络 如有侵权请联系删除

相关文章

  • 假如滴滴卖国。

    嗨,大家晚上好,我是南南今天不聊干货,聊聊滴滴。前几天晚上出了一件事,想必大多数人都知道了滴滴出行APP下架了。为什么要跟大家聊聊这件事呢?其实这件事跟我们这些地理信息的从业者,学生都有着很大的关系。(地理数据保密重中之重)滴滴凉凉,在前段时间国家要求奥维等平台下架谷歌地图的时候我就隐约感觉到了。再加上前段时间数据安全法的出台,毕竟地理数据实在是太敏感了不少网上言论说滴滴为了在美国上市,把地图,出行数据,个人资料给出去了。这个说法真假我是不得而知的。但国家网信办这次史无前例的发布了下架滴滴的通告。既然网信办说了,那么绝对可以肯定滴滴有确凿的证据没抓到了。首先就是我国的军事基地,军工科研所等机密单位的驻地泄露,要知道这些东西地图上可是隐藏了的。需要注意的是如今滴滴大概是国内打车的龙头老大把,国内app不要脸的权限相信大家懂得都懂。所以这绝不是危言耸听,如果我国与美国交战,这些东西虽然不敢说是致命的,但绝对是非常沉重的打击。其次,相信大家都知道poi把,在之前的文章我也详细的讲解过。本质上poi就是一个带有属性的点,简单思考一下,一个城市打车的数据越多,基本就可以断定这个城市相对来说人口和

  • 自顶向下 | 带你遨游运输层

    学习导图:一.运输层概述运输层为运行在不同主机上的应用程序之间提供逻辑通信应用报文加上运输层首部形成运输层报文段,报文段通过网络层被封装成网络层分组(数据报)向目的地发送Q1:运输层和网络层的关系运输层:运行在不同主机上的应用程序之间提供逻辑通信网络层:提供主机之间的通信举个例子来说明两者关系:有两个家庭,一家位于广州,一家位于北京,每家有3个孩子。这两个家庭的孩子们喜欢彼此通信,每封信都用单独的信封通过传统的邮政服务发送。每个家庭有一个孩子负责收发邮件,北京家庭是阿京,而广州家庭是阿州。每周阿京去她所有的兄弟姐妹那里收集邮件,并将这些邮件交到邮递员处上。当信件到达北京家庭时,阿京也负责将信件发到她的兄弟姐妹手上,广州家庭中阿州也负责类似工作网络层——邮递员运输层——阿京和阿州应用程序——兄弟姐妹主机——两个家庭通过运输层协议,两台电脑仿佛直接相连一样。应用无需知道底层内部实现的原理和细节,比如怎么把远隔世界两地电脑上的数据进行相互传输Q2:注意点运输层协议仅仅实现在网络的边缘处,例如主机,电脑,手机等。如路由器,交换机这些网络核心设备,是没有实现运输层协议的每一层协议仅仅检查分组相应

  • Go编程基础-基础篇 17

    Go语言中的nilnil是特殊的零值任何一个变量在声明之后会自动被赋予一个零值。数值类型的变量零值为0,字符串为"",而指针、切片、map、通道、函数和接口的零值就是nil。packagemain import"fmt" funcmain(){ varmmap[int]string varp\*int varcchanint vars[]int varffunc() variinterface{} fmt.Printf("map:%#v\n",m) fmt.Printf("指针:%#v\n",p) fmt.Printf("通道:%#v\n",c) fmt.Printf("切片:%#v\n",s) fmt.Printf("函数:%#v\n",f) fmt.Printf("接口:%#v\n",i) }复制map:map[int]string(nil) 指针:(\*int)(nil) 通道:(chan

  • kali安装webdav服务

    1.安装apacheapt-getinstall-yapache2复制2.启动apahesystemctlstartapache2复制lsof-i:80查看80端口是否被占用,即验证apache2服务是否开启成功 3.启用共享模块a2enmoddav//启用模块 a2enmoddav_fs//启用共享复制4.创建共享文件mkdir-p/var/www/html/webdav//创建共享目录 cd/var/www/html/webdav//进入共享目录 touchshell.php//创建文件 echo"<phpphpinfo();?>">shell.php//在新建的文件里输入内容复制5.查看服务是否有效http://172.16.11.83/ http://172.16.11.83/webdav/shell.php复制6.修改配置文件7.远程连接

  • Julia机器学习核心编程.6

    一些常规语言都有的东西提一嘴类型转换,指更改变量的类型,但是维持值不变的操作数组是对象的可索引集合,例如整数、浮点数和布尔值,它们被存储在多维网格中。Julia中的数组可以包含任意类型的值。在Julia中本身就存在数组这个概念。在大多数编程语言中,数组的下标都是从0开始的。但是在Julia中,数组的下标是从1开始的。这个特性我觉得在某些时候更符合直觉.日常说256级色域,你问ta,这么个数,大概率会说,1-256.but这个东西不对,应该是0-255,其实是一种反直觉的东西,至于设计背后的终极理念,如果我可以和语言的设计者聊天,可能会知道吧.MIT哦......我可以去吗?代码使用rand函数创建了一个数组,该函数接收两个值,其中第一个值是范围,用“:”表示;第二个值是一个数。本例创建了一个具有6个元素的数组。前面我们讨论的数组元素的类型是相同的。创建具有不同类型元素的数组如下代码创建了一个具有不同类型元素的数组,但是一些元素会自动提升它的类型。在这段代码中,我们使用Float和Int数据来创建一个数组。在Julia中创建数组时会将Int类型转换为Float类型。一般来说,Julia会

  • 美团命名服务的挑战与演进

    总第392篇2020年第15篇命名服务主要解决微服务拆分后带来的服务发现、路由隔离等需求,是服务治理的基石。美团命名服务(以下简称MNS)作为服务治理体系OCTO的核心模块,目前承载美团上万项服务,日均调用达到万亿级别。为了更好地支撑美团各项飞速发展的业务,MNS开始从1.0向2.0演进。本文将围绕本次演进的初衷、实现方案以及落地的效果等方面进行展开,同时本文还介绍了命名服务作为一个技术中台组件,对业务的重要价值以及推动业务升级的一些成果。希望本文对大家能有所帮助或启发。|本文根据美团基础架构部技术专家舒超在2019ArchSummit(全球架构师峰会)上的演讲内容整理而成。一、MNS1.0简介图1MNS1.0架构从架构上看,MNS1.0主要分为三层:首先是嵌入业务内部的SDK,用作业务自定义调用;然后是驻守在每个机器上的SgAgent,以代理的方式将一些易变的、消耗性能的计算逻辑与业务进程分离开来,从而降低SDK对业务的侵入,减少策略变动对业务的干扰;远端是集中式的组件,包括健康检查模块Scanner,鉴权缓存模块MNSC,以及基于ZooKeeper(以下简称ZK)打造的一致性组件M

  • 多任务版udp聊天器

    importsocket importthreading defsend_msg(udp_socket): """获取键盘数据,并将其发送给对方""" whileTrue: #1.从键盘输入数据 msg=input("\n请输入要发送的数据:") #2.输入对方的ip地址 dest_ip=input("\n请输入对方的ip地址:") #3.输入对方的port dest_port=int(input("\n请输入对方的port:")) #4.发送数据 udp_socket.sendto(msg.encode("utf-8"),(dest_ip,dest_port)) defrecv_msg(udp_socket): """接收数据并显示""" whileTrue: #1.接收数据 recv_msg=udp_socket.recvfrom(1024) #2.解码 recv_ip=rec

  • 技术 | 我国自主研发航空新材料,实现铝中“自生”陶瓷

    上交大研究团队研发新型材料,并与多家企业合作搭建生产应用平台,极大推进我国航空航天材料的发展和落地。近日,上海交通大学材料科学与工程学院王浩伟教授团队研究出超强纳米陶瓷铝合金,其强度和比刚度甚至超过“太空金属”钛合金,有助于将航空航天、高铁等领域带入更轻、更节能的新材料时代。如表所示,伴随着实际应用的需求,航天航空的材料发展逐步向轻质、高强度逼近。目前,航空航天结构材料主要有铝合金、钛合金、纤维复合材料和高温结构材料。在航空航天器机体结构材料的应用上,近100年来,铝合金都一直长盛不衰。特别是20世纪80年代末以来,随着飞行器损伤容限和耐久性设计准则逐渐形成,对材料的强度、断裂韧性、耐蚀性、抗疲劳等综合性能提出了更高要求。铝合金因其具有质量轻、易加工、抗腐蚀等优点,且比强度高于很多合金钢,故而成为理想的结构材料。钛也是20世纪50年代发展起来的一种重要的结构金属,相较于铝合金,钛合金的强度、耐蚀性和耐热性都要更好。20世纪50~60年代,主要是发展航空发动机用的高温钛合金和机体用的结构钛合金。现在,钛合金的多功能研究与应用也是目前航空航天领域的研究重点。相对于铝、钢等金属结构材料,碳纤

  • 学界 | UC伯克利提出新型视觉描述系统,物体描述无需大量样本

    选自BAIR作者:SubhashiniVenugopalan、LisaAnneHendricks机器之心经授权编译参与:路雪现在的视觉描述只能描述现有的训练数据集中出现过的图像,且需要大量训练样本。近日,UC伯克利提出一种新型视觉描述系统,无需成对的新物体图像和语句数据就可描述该物体。给出一个图像,人类可以轻松推断出其中最明显的实体,并有效描述该场景,比如,物体所处地点(在森林里还是在厨房?)、物体具备什么属性(棕色还是白色?),以及更重要的一点:一个物体如何与其他物体互动(在地上跑,还是被一个人抓着等等)。视觉描述的任务旨在开发为图像中的物体生成语境描述的视觉系统。视觉描述正面临挑战,因为它不仅需要识别物体(熊),还要识别其他元素,如动作(站立)和属性(棕色),并构建一个流畅的句子来描述物体、动作和属性在图像中的关系(如一头棕熊站在森林里的一块岩石上)。 视觉描述的现状LRCN[Donahueetal.'15]:一头棕熊站在绿色的地面上。 MSCaptionBot[Tranetal.'16]:一头大棕熊穿行在森林中。 LRCN[Donahueetal.'

  • 资源 |“从蒙圈到入坑”,推荐新一波ML、DL、RL以及数学基础等干货资源

    编译|AI科技大本营(rgznai100)参与|suiling此前营长曾发过一篇高阅读量、高转发率,高收藏量的文章《爆款|Medium上6900个赞的AI学习路线图,让你快速上手机器学习》,本文共分为五个部分:Part1:为什么机器学习重要。人工智能与机器学习概述——过去,现在,将来。Part2.1:监督学习。线性回归,损失函数,过拟合,梯度下降。Part2.2:监督学习II。两种分类方法:逻辑回归和SVMs。Part2.3:监督学习III.。非参数学习:k最近邻,决策树,随机森林。并介绍交叉验证,如何调参和模型融合。Part3:无监督学习。聚类:k-means,层次聚类。降维:主成份分析法(PCA),奇异值分解(SVD)。Part4:神经网络。深度学习的工作原理,以及卷积神经网络(CNN),循环神经网络(RNNs)和实际应用。Part5:增强学习。介绍马尔可夫决策过程。Q-learning,策略学习,深层增强学习。价值学习问题。附录:最好的机器学习资源、机器学习课程资源列表。现在把最后一个附录部分——“机器学习课程资源列表”进行了整理,该节主要包含一些关于AI、机器学习以及深度学习的

  • Flutter Android ERROR: ensureInitializationComplete must be called after startInitialization

    今天在flutter的开发中出现这么一个错误: java.lang.RuntimeException:UnabletostartactivityComponentInfo{com.example.testappandroid/io.flutter.embedding.android.FlutterActivity}:java.lang.IllegalStateException:ensureInitializationCompletemustbecalledafterstartInitialization atandroid.app.ActivityThread.performLaunchActivity(ActivityThread.java:2913) atandroid.app.ActivityThread.handleLaunchActivity(ActivityThread.java:3048) atandroid.app.servertransaction.LaunchActivityItem.execute(LaunchActivityItem.java:78) ata

  • PTA 1162 Postfix Expression (25 分)

    1162PostfixExpression(25分) Givenasyntaxtree(binary),youaresupposedtooutputthecorrespondingpostfixexpression,withparenthesesreflectingtheprecedencesoftheoperators. InputSpecification: Eachinputfilecontainsonetestcase.Foreachcase,thefirstlinegivesapositiveintegerN(≤20)whichisthetotalnumberofnodesinthesyntaxtree.ThenNlinesfollow,eachgivestheinformationofanode(thei-thlinecorrespondstothei-thnode)intheformat: dataleft_childright_child wheredataisastringofnomorethan10characters,left_childandright_chil

  • AjaxUploader使用

    一、简单上传(SimpleUploadwithProgress) <CuteWebUI:UploaderID="ajaxUploader"runat="server"InsertText="上传文件"OnFileUploaded="Uploader_FileUploaded"> </CuteWebUI:Uploader>复制 protectedvoidUploader_FileUploaded(objectsender,UploaderEventArgsargs){  args.MoveTo(args.FileName);} 二、多文件上传(Selectingmultiplefilesforuploading) <CuteWebUI:UploaderID="ajaxUploader"runat="server"MultipleFilesUpload="true"InsertText="上传多个文件"OnFileUploaded="Uploader_FileUploaded"> </CuteWebUI:Uploader> prote

  • CS APP ex2 bomb——二进制炸弹

    CSAPP的实验2,拆解bomb 目录CSAPP的实验2,拆解bomb进入gdb调试模式查看主函数phase_1函数phase_2函数phase_3函数phase_4函数phase_5phase_6 这里是在linux环境下通过gdb来进行的调试 进入gdb调试模式 终端中输入$gdbbomb 查看主函数 输入(gdb)listmain 发现其中初始化函数initialize_bomb()后,有两个print输出提示,然后紧接着一个input=read_line(),将我们的输入作为参数调用了phase_1函数。 所以这个phase_1应该就是对输入进行检查的函数,查看该函数的汇编。 phase_1函数 输入(gdb)disassemblephase_1 输出如下 Dumpofassemblercodeforfunctionphase_1: 0x08048b80<+0>:push%ebp 0x08048b81<+1>:mov%esp,%ebp 0x08048b83<+3>:sub$0x8,%esp 0x08048b86<+6>

  • android架构图示

     Android系统架构和一些普遍的操作系统差不多,都是采用了分层的架构,从他们之间的架构图看,Android系统架构分为四个层,从高层到低层分别是应用程序层、应用程序框架层、系统运行库层和linux核心层。 一、应用程序    Android会同一系列核心应用程序包一起发布,该应用程序包包括email客户端,SMS短消息程序,日历,地图,浏览器,联系人管理程序等。所有的应用程序都是使用JAVA语言编写的。   二、应用程序框架    开发人员也可以完全访问核心应用程序所使用的API框架。该应用程序的架构设计简化了组件的重用;任何一个应用程序都可以发布它的功能块并且任何其它的应用程序都可以使用其所发布的功能块(不过得遵循框架的安全性限制)。同样,该应用程序重用机制也使用户可以方便的替换程序组件。    隐藏在每个应用后面的是一系列的服务和系统, 其中包括;   丰富而又可扩展的视图(Views),可

  • python生成随机日期字符串

    生成随机的日期字符串,用于插入数据库。 通过时间元组设定一个时间段,开始和结尾时间转换成时间戳。 时间戳中随机取一个,再生成时间元组,再把时间元组格式化输出为字符串 importtime importrandom a1=(1976,1,1,0,0,0,0,0,0)#设置开始日期时间元组(1976-01-0100:00:00) a2=(1990,12,31,23,59,59,0,0,0)#设置结束日期时间元组(1990-12-3123:59:59) start=time.mktime(a1)#生成开始时间戳 end=time.mktime(a2)#生成结束时间戳 #随机生成10个日期字符串 foriinrange(10): t=random.randint(start,end)#在开始和结束时间戳中随机取出一个 date_touple=time.localtime(t)#将时间戳生成时间元组 date=time.strftime("%Y-%m-%d",date_touple)#将时间元组转成格式化字符串(1976-05-21) print(date)复制 结果为: 1985-

  • Docker私有仓库

    Docker私有仓库 私有仓库搭建与配置 (1)拉取私有仓库镜像(此步省略) dockerpullregistry 复制 (2)启动私有仓库容器 dockerrun-di--name=registry-p5000:5000registry 复制 (3)打开浏览器输入地址http://ip地址:5000/v2/catalog看到{"repositories":[]}表示私有仓库搭建成功并且内容为空 (4)配置私有仓库,修改daemon.json vi/etc/docker/daemon.json 复制 输入如下参数,注意修改为自己的ip地址: {"insecure-registries":["IP地址:5000"]} 复制 (5)重启docker服务 systemctlrestartdocker 复制 (6)创建容器 dockerrun-d-p5000:5000--nameregistrydocker.io/registry 复制 部分参数说明: -d:让容器在后台运行 -p:指定容器内部使用的网络端口映射到我们使用的主机上 --name:指定容器创建的名称 (7)访问第三步地址,如果访

  • sort属性

    学习文章---链接   总结笔记 ①sort是Array.prototype的属性, ②如果不写入参数,则按照转换为的字符串的每个字符的unicode位点进行排序, ③如果传入一个比较函数sort(function(a,b){}),    如果比较函数返回负值,则a排在b之前;    如果比较函数返回正值,则a排在b之后;    如果比较函数返回0,则a和b相对位置不变;   降序排序 vararr=[2,10,6,9,7,8]; vararr1=arr.sort(function(a,b){ if(a>b){ return-1; }elseif(a<b){ return1 }return0; }); alert(arr1);//10,9,8,7,6,2 alert(arr);//10,9,8,7,6,2 复制   升序排序 vararr=[2,10,6,9,7,8]; vararr1=arr.sort(function(a,b){ if(a<

  • HTMLVideoElement.srcObject MediaStream MediaSource Blob File

    MediaSource <!DOCTYPEhtml> <htmllang="zh"> <head> <metacharset="UTF-8"> <metahttp-equiv="X-UA-Compatible"content="IE=edge"> <metaname="viewport"content="width=device-width,initial-scale=1.0"> <title>Document</title> <style> video{ background:black; position:relative; left:50%; transform:translate(-50%,0); } </style> </head> <body> <videowidth="854"height="480"muted></video> <script> varvideo=document.get

  • word2vec 论文讲解 - b站深度之眼

    https://www.bilibili.com/video/BV1A7411u7zh?p=4&vd_source=db1f7cb82e86cfc9050cdc20ec10c8ab 前置知识 one-hot SVD(SingularValueDecomposition)奇异值分解 DistributedRepresentation分布式表示/稠密表示 WordEmbedding词向量/词嵌入 意义: 衡量词相似程度,词类比(中国-北京) 作为预训练任务提升其他任务效果 N-gram模型,https://zhuanlan.zhihu.com/p/32829048 前置知识 语言模型概念: 衡量一个句子是句子的概率,的模型。 基于专家语法规则的语言模型: 不够通用 统计语言模型: 2个问题: 没有出现过的语料; 句子太长 平滑操作:laplace加一平滑 平滑之后的问题: 参数空间过大,解决方案:马尔可夫假设 数据稀疏严重 评价指标: 困惑度:句子概率越大,困惑度越小 对比方法 NNLM(neuralnetwork

  • R: 导入 csv 文件,导出到csv文件,;绘图后导出为图片、pdf等

    ################################################### 问题:导入csv文件         如何从csv文件中导入数据,?参数怎么设置?常用参数模板是啥? 解决方案:         yuan<-read.csv(file="C:/Users/Administrator/Desktop/test1.csv",header=TRUE,sep=",",dec=".",stringsAsFactors=FALSE,na.strings="NA",strip.white=TRUE)         yuan1=yuan1_copy<-read.csv("C:/Users/Administrator/Desktop/test1.csv",header=TRUE,sep=",",dec=".",na.

相关推荐

推荐阅读