See More

PK –~!Q meta.xmlˆwþsunnyXMindR3.7.8.201807240049122410#FFFFFFPKÌà²$ ˆ PK –~!Q content.xml”_k Java Bytecode1CLASS文件字节码字节码结构操作数栈字节码增强ASMJavassist运行时类的重载工具javapjclasslib如果每次查看反编译后的字节码都使用javap命令的话,好非常繁琐。这里推荐一个Idea插件:jclasslib美团技术团队 - 字节码增强技术探索Java Bytecode字节码之所以被称之为字节码,是因为字节码文件由十六进制值组成而JVM以两个十六进制值为一组,即以字节为单位进行读取。在Java中一般是用javac命令编译源代码为字节码文件对于开发人员,了解字节码可以更准确、直观地理解Java语言中更深层次的东西,比如通过字节码,可以很直观地看到Volatile关键字如何在字节码上生效。另外,字节码增强技术在Spring AOP、各种ORM框架、热部署中的应用屡见不鲜,深入理解其原理对于我们来说大有裨益。除此之外,由于JVM规范的存在,只要最终可以生成符合规范的字节码就可以在JVM上运行因此这就给了各种运行在JVM上的语言(如Scala、Groovy、Kotlin)一种契机可以扩展Java所没有的特性或者实现各种语法糖。1字节码操作数栈和字节码1JVM的指令集是基于栈而不是寄存器,基于栈可以具备很好的跨平台性(因为寄存器指令集往往和硬件挂钩)但缺点在于,要完成同样的操作,基于栈的实现需要更多指令才能完成(因为栈只是一个FILO结构,需要频繁压栈出栈)。另外,由于栈是在内存实现的,而寄存器是在CPU的高速缓存区,相较而言,基于栈的速度要慢很多,这也是为了跨平台性而做出的牺牲。控制操作数栈示意图操作数栈jclasslib代码编译后在菜单栏”View”中选择”Show Bytecode With jclasslib”,可以很直观地看到当前字节码文件的类信息、常量池、方法区等信息。jclasslib字节码增强是一类对现有字节码进行修改或者动态生成全新字节码文件的技术。字节码增强技术相当于是一把打开运行时JVM的钥匙利用它可以动态地对运行中的程序做修改,也可以跟踪JVM运行中程序的状态。此外,我们平时使用的动态代理、AOP也与字节码增强密切相关,它们实质上还是利用各种手段生成符合规范的字节码文件。掌握字节码增强后可以高效地定位并快速修复一些棘手的问题(如线上性能问题、方法出现不可控的出入参需要紧急加日志等问题),也可以在开发中减少冗余代码,大大提高开发效率。应用热部署不部署服务而对线上服务做修改,可以做打点、增加日志等操作。Mock测试时候对某些服务做Mock。性能诊断工具比如bTrace就是利用Instrument,实现无侵入地跟踪一个正在运行的JVM,监控到类和方法级别的状态信息。1字节码增强Javassist1强调源代码层次操作字节码的框架Javassist。利用Javassist实现字节码增强时,可以无须关注字节码刻板的结构,其优点就在于编程简单。直接使用java编码的形式,而不需要了解虚拟机指令,就能动态改变类的结构或者动态生成类。其中最重要的是ClassPool、CtClass、CtMethod、CtField这四个类CtClass(compile-time class):编译时类信息,它是一个class文件在代码中的抽象表现形式,可以通过一个类的全限定名来获取一个CtClass对象,用来表示这个类文件。ClassPool:从开发视角来看,ClassPool是一张保存CtClass信息的HashTable,key为类名,value为类名对应的CtClass对象。当我们需要对某个类进行修改时,就是通过pool.getCtClass(“className”)方法从pool中获取到相应的CtClass。CtMethod、CtField:这两个比较好理解,对应的是类中的方法和属性。示例依然是对Base中的process()方法做增强,在方法调用前后分别输出”start”和”end”要做的就是从pool中获取到相应的CtClass对象和其中的方法,然后执行method.insertBeforeå’ŒinsertAfter方法,参数为要插入的Java代码,再以字符串的形式传入即可,实现起来也极为简单。Javassist运行时类的重载如果我们在一个JVM中,先加载了一个类,然后又对其进行字节码增强并重新加载会发生什么呢?会发现它是在最后调用了ClassLoaderçš„native方法defineClass()时报错。也就是说,JVM是不允许在运行时动态重载一个类的。如何在一个持续运行并已经加载了所有类的JVM中,还能利用字节码增强技术对其中的类行为做替换并重新加载?Instrumentinstrument是JVM提供的一个可以修改已加载类的类库,专门为Java语言编写的插桩服务提供支持。它需要依赖JVMTIçš„Attach API机制实现在JDK 1.6以前,instrument只能在JVM刚启动开始加载类时生效,而在JDK 1.6之后,instrument支持了在运行时对类定义的修改。要使用instrument的类修改功能,我们需要实现它提供的ClassFileTransformer接口,定义一个类文件转换器。接口中的transform()方法会在类文件被加载时调用,而在transform方法里,我们可以利用上文中的ASM或Javassist对传入的字节码进行改写或替换,生成新的字节码数组后返回。JVMTI & Agent & Attach API1运行时类的重载PK˜Ýâ™_ ”_ PK –~!Q styles.xml¶|IƒPK{µh»| ¶| PK –~!Q 2 Revisions/72ocfq4g2n51cbrrthvu0tbpv3/revisions.xmln‘þPKK#òs n PK –~!Q 2 Revisions/7ge10j9ce0u89mprc23e9rnt4b/revisions.xmlqŽþPK€CêDv q PK –~!Q 2 Revisions/72vvjf7252vrflm0gtte4btvq6/revisions.xmln‘þPKþÑ}³s n PK –~!Q 2 Revisions/4faasqtopgmlj067smhh33qca9/revisions.xmln‘þPK@ s n PK –~!Q 2 Revisions/25j6sl9gi96fiscso5b7hmko1v/revisions.xmln‘þPKñÒ8&s n PK –~!Q 2 Revisions/5nof79j780bng9tci79ut47ckf/revisions.xmln‘þPKdÇWs n PK –~!Q 2 Revisions/14eu1esm1mp7trko3k0efkpdoh/revisions.xmln‘þPK§¾»ys n PK –~!Q 2 Revisions/116t7iiv84ji46v57lr508fg11/revisions.xmlqŽþPKÉ¢Xtv q PK –~!Q * attachments/04rd9vuh7il0b9scfbgo3hh0pc.png €ÿ‰PNG IHDR È ÜuÎ EIDATxœìÝ xL×ÿÇñ¡¥UZ­%U[kiKm¥µwQéOÑX+ˆ}ßSjiù7ˆ%%bß×PK„ ¶Ä’Ä– Ö ˆ5¤DBD$ˆÿ©Ët2YD$9'™÷ë¹Ï}¾™¹sï™;÷ŒÎ§gÎèž ¥†ž½gV#·Þ,,Ùl¶¸¼e÷0 µt² @j]Ž%RdÉö‹¸ÈÅ¥.»· /G° ȼÎûZ®ì#=ôaaÉ„E\êâ‚—Ýç €— X dKŽm|I³‚š:‹×‰qÙËîy @J ªK!U´tëCMmêÄÙ" TF° Pš×yßdcF™QSgðèE¾ e, Ôu924ñ¼ŠÚ/Kjêl]ÿwÁ¯ìÃo¹ @M‹ u%ñÐ*Œ&£¦ÎÜÑ‹¢#Èî‹ @ Š =e˜­èæÂ£¦Îä¹EwÝ# c‹ E%1\ÑMdÔÔ™>ß"ƒ   ‚E €ŠnEG¦**ÌyGMùµá":…ì~ $@° PQ²?­Â2jêL±ØˆŸ‡ €z *rÞ¿Ø0RQaž;jj‰s,ŠEt Ùý H€`  ¢¾^ãþ‹TT5FM-{Ä¢è²û%  Á" @E­Ö6ŒTÔ™óŽš:ókmBv¿ X ¨Èr¥Á÷@U5FM-{Ä¢è²û%  Á" @EÆ‘ŠóÜQS˝cQ,²û%  Á" @E òFQS˱؈` Š!X ¨È(OQaž;jj¹s,6"X €b *2S”5FM͈E !‚E €ŠŒòæ¹£¦fŽE ÀÁ" @E òFQS3b Hˆ`  "£