【为什么要写这本书】
大约四五年前,秉承“代码未动、监控先行”的理念,我开始在公司的平台部门做服务质量监控平台。开始是使用人工埋点的方式来进行监控信息的上报,业务方的接入成本非常高,上线前需要花半天到的时间来进行埋点,苦不堪言。
后来公司大力推行 DevOps、容器化、微服务,提高了开发和运维效率,但分布式部署架构带来的问题也迅速显现出来,如服务拓扑不清、服务依赖关系复杂、日志散落在各个微服务中,等等。在出现问题时,开发人员不知道如何排查,无法快速定位问题。后来我了解到 javaagent ASM 这样的技术能够自动注入埋点的代码,于是花了大概一个月的时间苦学字节码、ASM 相关的知识。ASM官方的英文手册读了不下 5 遍,深知其中的难点。另外,APM 这一套性能监控工具需要极高的可靠性和极低的性能损耗,倒逼着我对字节码的执行原理、高性能 Java等有了更深入的研究。
我花了大概 3 个月的时间从零到一实现了整套无侵入字节码注入 APM 系统,对整个后端微服务调用栈进行监控,实现了业务方零埋点、跨进程异构系统的调用链路追踪、性能问题代码级别定位、业务拓扑实时发现、SLA 实时统计等功能。该系统上线运行了几年,至今未出现问题。
我平时喜欢破解一些软件,一开始都是通过直接修改类文件的方式来进行的,比较烦琐。掌握了 javaagent、ASM、JVMTI 这些工具以后,对软件破解有了更深入的研究。
后来从平台部门去业务部门带领更大的团队,很早期的时候就引入了 Kotlin 来进行后端开发。为了避免基础较差的同事误解语法糖的意思,我对 Kotlin 中很多语法背后的实现做了详细的分析,让他们在使用的时候更加清楚语法糖的实现原理。
一路走来,觉得越底层的知识越有价值,所以想写一本这样的书,让更多的人能够对 JVM 字节码底层的细节多一些了解,在遇到问题时能自己分析、独立判断。
【读者对象】
希望你可以通过阅读本书知其然并知其所以然,理解炫酷语法和框架背后的实现原理,实现各种 JVM“黑科技”,真正搞懂反射、Lambda 表达式、AOP、热加载、软件破解等的实现细节。
【本书适合以下读者阅读】
对 Java 有初步了解,想深入学习其内部运行细节的读者;
通过学习字节码改写技术实现高性能框架的读者;
对 APM 感兴趣,想了解 APM 实现原理的读者,以及准备搭建 APM 系统用来做分布式系统调用链跟踪的读者;
想学习 Java 软件常见的破解和防破解方法,提高软件逆向和破解水平的读者。
【如何阅读这本书】
本书一共 12 章,从逻辑上主要分为字节码原理篇和应用篇两大部分。
第 1 章详细剖析了 class 文件的内部结构,帮助读者理解本书后面介绍的字节码原理。
第 2 章首先介绍了什么是字节码,接下来介绍了 Java 虚拟机栈和栈帧的相关内容,然后通过 for 循环、switch-case、try-catch-finally 等语法讲解了字节码指令的用法。
第 3 章介绍了字节码的进阶知识,主要目的是让读者掌握方法调用指令、泛型擦除、synchronized 关键字、反射的底层实现原理。
第 4 章介绍了javac 编译器的原理。编译原理是计算机科学皇冠上的明珠,只有弄懂了 javac 才能更好地理解字节码的生成原理。本章一开始介绍了 javac 源码的调试方法,随后详细介绍了 javac 编译的七大阶段和各阶段的作用。
第 5 章从字节码角度看 Kotlin 语言,介绍了常见语法糖和协程等的原理,希望读者在学习其他 JVM 系语言时可以举一反三,使用类似的思路。
第 6 章介绍了 ASM 和 Javassist 两个字节码操作工具。这两个工具非常重要,被广泛用于中间件框架中,后面关于APM、软件破解的章节都涉及这两个工具的使用。
第 7 章介绍了 Java Instrumentation 的原理,分两种方式讲解了如何使用 Instrumentation,后介绍了 Attach API 的底层 UNIX 域套接字的通信原理。
第 8 章介绍了 JSR 269 插件化注解处理的原理,希望读者可以通过本章掌握编译期间生成、修改代码的方法,理解 Lombok、ButterKnife 工具的实现原理。
第 9 章主要介绍了字节码在 cglib、Fastjson、Dubbo、JaCoCo、Mock 这些框架上的应用,可以让读者接触到更多字节码的使用场景。
第 10 章主要介绍了反编译、破解、防破解和逆向工程的相关内容。了解常见的破解和逆向方法能更好地保护自己的软件产品。
第 11 章介绍了 APM 的概况、分布式跟踪的基本原理、OpenTracing 的基本概念和无埋点字节码插桩的代码实现。如果对 APM 有兴趣,可以将本章作为入门指导,实现自己的 APM 产品。
第 12 章详细介绍了Android dex 文件的组成结构,以及Android字节码指令与 Java 字节码指令的区别,后介绍了 Gradle 字节码改写实现无侵入插桩的方法。