在悠远的希艾斯星球爪哇国塞沃城中,两名年青的程序员正在为一件作业苦恼,程序出问题了,一时看不出问题出在哪里,于是有了以下对话:

“Debug一下吧。”

“线上机器,没开Debug端口。”

“看日志,看看请求值和返回值分别是什么?”

“那段代码没打印日志。”

“改代码,加日志,从头发布一次。”

“怀疑是线程池的问题,重启会损坏现嵌套调用场。”

长达几十秒的沉默寂静之后:“听说,排查问题阿里供给链的最高地步,便是只经过Review代码来发现问题。”

比几十秒长几十倍的沉默寂静之后:“我轮询了那段代码一十七遍之后,总算得出一个定论。”

“定论是?”

“我还没抵达只经过Rev程序员需要什么学历iew代码就能发现问题的至高地步。”阿里云

Java方针行为

文章开始的问题本质上是动态改动内存中已存在方针的行为问题。

所以,得先弄清楚JVM中和方针行为有关的当地在哪里,有没有更改的可能性。

方针运用两嵌套结构种东西来描绘事物:行为和特征。

举个比如:

不重启JVM,替换掉现已加载的类,批红判白?

上面Person类中age和name是特征,speak是行为。方针是类的实例,每个方针的特征都归于方针自身,但是每个方针的行为却是公共的。举个比如,比如咱们现在根据Person类创立了两个方针嵌套分类汇总,personA和personB:

不重启JVM,替换掉现已加载的类,批红判白?

personA和personB有各自的名字和年龄,但是有一同的行为:speak。幻想一下,假定咱们是Java言语的设计者,咱们会怎样存储方针的行为和特征呢?

“很简略,特征跟着方针走,每个方针都存一份。行为是公共的东西,抽离出来,独自放阿里拍卖到一个当地。”

“咦?抽离出公共的部分,java开发跟代码复用好像啊。”

“大道至简,许多东西本来都是异曲同工。”

也便是说,第一步咱们首先得找到存储方针行javaee为的这个公共的当地。一番查找之后,咱们发现这样一段描绘:

也便是说,第一步咱们首先得java工作培训班找到存储方针行为的这个公共的当地。一番查找之后,咱们发现这样一段描绘:

Method ar程序员是做什么的ea is created o阿里n virtual machine startup, shared among all Java virtual machine threads and it is logically part of heap area. It嵌套if函数 stores per-class structures such as the run-time constant pool, field and method data二进制亡者列车, and the code for methods and constructjava工作培训班ors.

Java的方针行为(办法、函数)是存储在办法区的。

“办法区中的数据从哪来?”

程序员装逼代码办法区中的数据是类加载时从class文件中提取出来的。”

“cl二进制八进制十进制十六进制转化ass文件从哪来?”

“从Java或许其他契合JVM标准的源代码中编译而来。”

“源代码从哪来?”

“废话,当然是手写!”

“倒着推,手写没问题,编译没问题,至于加载……有没有办法加载一个现已加载过的类呢?假定有的话,咱们就能修改字节码中方针办法所在的区域,然后从头加载这个类,这样办法区中的方针行为(方阿里巴巴股票法)就被改动了,而且不改动方针的特征,也不影响现已存在方针的状况,那么就能够搞定这个问题了。但是,这岂不是违背了JVM的类加载原理?究竟咱们不想改动ClassLoader。”

“少年,能够去看看java.lang.instrument.Instrumentation。”

java.lang.i二进制nstrument.Instrumentation

看完文档之后,我程序员是学什么专业们发现这么两个接口:redefineClasses和retransformClasses。一个是从头界java工作培训班说class,一个是修改class。这两个截然不同,看redefineClasses的阐明:

This method is used to replace the definition of a class without reference to the existinjavascriptg class file bytes, as one might do when recompilijava开发ng from source for fix-and-continue debu二进制gging. Where the existing class file bytes are to be transf阿里拍卖ormed (for example in bytecode instrumentation) retransformClasses should be used.

都是替换现已存在的class文件,redefineClasses是自己供给字节码文件替换掉已存在的class文件,retransformClasses是在已存在的字节码文件上修改后再替换之。

当然,作业时直接替换类很不安全。比如新的class文件引用了一个不存在的类,或许把某个类的一个field给删除了等等,这些状阿里云况都会引发异常。所以如文档中所言,instrument存在许多的捆绑:

The redefinition may cha二进制nge method b阿里云盘odies, the const阿里巴巴股票ant pool嵌套分类汇总 a二进制怎样算nd attributes. The redefinition must not add, remove or rename fields or methods, change the signatures of metho嵌套if函数ds, or change inheritance. These res程序员那么心爱trictions maybe be lifted in future versions. The class file bytes are n嵌套结构ot checked, verified and installed u阿里供给链ntil afte二进制转化器r the transformations have been app二进制八进制十进制十六进制转化lied, if the resultant bytes are in error this method will throw程序员那么心爱 an exception.

咱们能做的根柢上也便是简略修改办法内的一些行为,这关于咱们开始的问题,打印一段日志来说,现已足够了。当然,咱们除了嵌套分类汇总的操作过程经过retransform来打印日志,还能做许多其他十分有用的作业,这个下文会进行介绍。

那怎样得到咱们需求的class文件java难学吗呢?一个最简略的办法,是把修改后的Java文件从头编阿里拍卖译一遍得到class文件,然后调用redefineClasses替换。但是关于没有(或许拿不到,或许不方便修改)源码阿里推出“吃货笔记”的文件咱们应该怎样办呢?其实关于JVM来说,不管是Java也好,Scala也好,任何一种契合JVM标准的言语的源代码,都能够编译成c嵌套查询lass文件。JVM的操阿里作方针是class文件,而不是源码。所以,从这种意义上嵌套查询来讲,咱们能够说“JVM跟言语无关”。已然如此,不管有没有源码,其实咱们只需求修改嵌套分类汇总的操作过程class文件就行了。

直接操作字节码

Java是软件开发人员能读懂的言语,class字节码是JVM能读懂的言语,class字节码毕竟会被JVM解释成机器能读懂的言语。无论哪种言语,都是人发明的。所以,理论上(实际上也确实如此)人能读懂上述任何一种言语,已然能读懂,自然能修改。只需咱们乐意,咱们完全能够越过Java编译器,直接写字节码文件,只不过这并不契合年代的打开算了,究竟高档言语设计之始便是为咱们人类所服务,其开发功率也比机器言语高java怎样读许多。

关于人类来说,字节码文件的可读性远远没有Java代嵌套循环码高。尽管如此,仍是有一些杰出的程序员们发明出了能够用来直接修改字节码的结构,供给接口能够让咱们方便地操作字节码文件,进行注入批程序员薪酬一般多少改类的办法,动态发明一个新的类等等操作。其间最著名的结构应该便是ASM了,cglib、Spring等结构中关于字节码的操作就建立在ASM之上。

咱们都知道,Spring的AOP是根据动态署理完毕的,Spring嵌套调用会在作业时动态创立署理类,署理类中引用被署理类,在被署理的办法实行前后进行一些奥秘的操作。那么,Spring是怎样在作业时创立署理java初学类的呢?动态署理的夸姣之处,就在于咱们不用手动为每个需求被署理的类写署理类代码,Spring在作业时会根据需求动态地发明出一个类嵌套查询sql句子。这儿发明的进程并非经过字符串写Java文件,然后编译成class文件,然后加载。Spring会直接“发明”一个class文件,然后加载,发明class文件的东西,便是ASM了。

到这儿,咱们知道了用ASM结构直接操作class文件,在类中加一段打印日志的代码,然二进制怎样算后retransform就能够了。

BTrace

截止到现在,咱们都是停留在理论描绘的层面。那么怎样进行完毕呢?先来看几个问题:

  1. 在咱们的工程中,谁程序员装逼代码来做这个寻觅字节码,修改字节码java怎样读,然后retransform二进制转化器的动作呢?咱们并非先知,不行能知程序员薪酬一般多少道未来有嵌套没有可能遇到文章开始的这种问题。考虑到性程序员薪酬一般多少价比,咱们也不行能在每个工程中都开发一段专门做这些修改字节码、从头加载字节码的代码。
  2. 假定JVM不在本地,在远程呢?
  3. 假定连ASM都不会阿里众包用呢?能不能更通用一些,更“傻瓜”一些。

走运的是,因为有BTr嵌套是什么意思ace的存在,咱们不用自己写一套这样的东西了。什么是BTrace呢?BTrace现已开源嵌套分类汇总,项目描绘极点简略:二进制转十进制计算器

A safe, dynamic二进制八进制十进制十六进制转化 tracing tool for the Java platform.

BTrace是根据Java言语的一个安全javascript的、可供给动嵌套循环态寻觅服务的东西。BTrace根据ASM、Java Attajava开发ch API、Instrumenjava言语t开发,为用户供给了许多注解。依托这些注解,咱们能够编写BTrace脚本(简略的Java二进制代码)抵达咱们想要的效果,而不用深陷于ASM对字节码的操作中不行Java自拔。

看BTrace二进制官方供给的一个简略比如:拦截一切java.io包中一切类二进制转化为十进制中以read开始的办法,打印类名、办法名和参数名。当程序IO负载比较高的时分,就能够嵌套从输出的信息中看到是哪些类所引起,是不是很方便?

不重启JVM,替换掉现已加载的类,批红判白?

阿里云盘来看另一个比如:每隔2秒打印截止到当时创立过的线程数。

不重启JVM,替换掉现已加载的类,批红判白?

看了上面的用法是不是有所启示?忍不住冒出来许多主意。比如查看Has阿里云hMap什么时分会触嵌套函数发rehash,以程序员是做什么的及此时容器阿里云盘中有多少元素等等。

有了BTrace,文章开始的问题能够得到完美的处理。至于BTrace详细有哪些功用,脚本怎样写,这些Git上BTrace工程中有很多的阐明和举例,网上介绍BTrace用法的文章更是不可胜数,这儿就不再赘述了。

咱们理解了原理,又有好用的东西支撑,剩下的便是发挥咱们的发明力了,只需在适合的场景下合理地进行运用即可。

已然BTrace能处理上面嵌套循环咱们提到的一切问题,那么BTrajava难学吗ce的架构是怎样的呢?

BTrace主要有程序员怎样学下面几个模块:

  1. BTrace嵌套是什么意思脚本:运用BTrace定义的注解,咱们能够很方便地javascript根据需求java怎样读进行脚本的开发。
  2. Compiler:将BTrace脚本编译成BTrace class文件。
  3. Client:将class文件发送到Agent。程序员客栈
  4. Agent:根据Java的Attach API,Agent能够动态附着到一个作业的JVM上,然后翻开一个BTrace Server,接收client发过来的BTrace脚本;解程序员是做什么的析脚本,然后根据脚本中的规矩找到要修改的类;修改字节码后,调用Java Instrument的retransform接口,完毕对方针行为的修改并使之收效。

整个BTrace的架构大致如下:

不重启JVM,替换掉现已加载的类,批红判白?

BTrace毕竟借Instrument完毕class的替换。如上文所说,出于安全考虑,Instrument阿里众包在运用上存在许多的捆绑,BTrace也不破例。BTrace对JVM来说是“只读的”,因而BTrace脚本的捆绑如下:

  1. 不允许创立方针
  2. 不允许创立数组
  3. 不允许抛异常
  4. 不允许catch异常
  5. 不允许随意调用其他方针或许类的办法,只允许调用com.sun.btrace.BTraceUtils中供给的静态办法(一些数据处理和信息输出东西)
  6. 不允许改动类的特征
  7. 不允许有成员变量和办法,只允许存在static public void 办法
  8. 不允许有内部类、嵌套类
  9. 不允许有同步办法和同步块
  10. 不允许有循环
  11. 不允许随意承继其他类(当然,java.lang.Obj阿里巴巴ect在外)
  12. 不允许完毕接口
  13. 不允许运用assert
  14. 程序员允许运用Class方针

如此多的束阿里缚,其实能够了解。BTrace要做的是,尽管修改了字节码,但是除了输出需求的信息外,对整二进制个程序的正常嵌套分类汇总作业并没有影二进制转十进制计算器响。

Arthas

BTrace脚本在运用上有必定的学习阿里供给链本钱,假定能把一些常用的功用封装起来,对外直接供嵌套循环应简略的指令即可操作的话,那就再好不过了。阿里的工程师们早已想到程序员计算器这一点,就在上一年,阿里巴巴开源了自己的Java嵌套结构确诊嵌套阿里众包西——Arthas

Arthas供给简略的指令行操作,功用强大。究其背面的技术原理,和本java开发文中提到的大致无二。

本文旨在阐明Java动态寻觅技术的来龙去脉,把握技术背面的原理之后,只需乐意,各程序员装逼代码位读者也能够开发出自己的“冰封王座”出来。

三生万物

现在,让咱们试着站在更高的当地“俯视”这些问题。

Java的Instrument给作业时的动态寻觅留下了期望,Attach API则给作业时java言语动态寻觅供给了“出入口”,ASM则大大方便了“人类”操作Java字节码的操作。

根据Instrument和Attach二进制八进制十进制十六进制转化 API老一辈们发明出了诸如JProfiler、Jvisualvm、BTrace这java工作培训班程序员计算器的东西。二进制以ASM为根阿里供给链底打开出了cglib、动态署理,继而是运阿里供给链用广泛的Spring AOP。

Java是静态言语,作业时不允许改动数据结构。但是,Java 5引进Instrument,Java 6引进Attach API之后,作业初步变得不一样了。尽管存在许多捆绑,但是,在老一辈们的极力下,仅仅是运用预留的近似于“只读”的这一点点狭小的空间,仍然发明出了各种大放异彩的技术,极大地提高了java开发软件开发人员定位问题的功率。程序员

计算机应该是人类有史以来最巨大的发明之一,从阿里推出“吃货笔记”电磁感应磁生电,到凹凸电压模仿0和1的比特,再到二进制表示出几种根柢类型,再到根柢类型表示出无量的方针,最后无量的方针组合交互模仿现实生活乃至整个世界。

两千五百年前,《道德经》有言:“道java面试题生一,终身二,二生三,三生万物。”

两千五百年后,计算机的打开进程也大概如此吧。

首发地址:不重启java怎样读JVM,替换掉现已加载的类,批红判白?

重视技术号:群众号:码农架构