工具开发,字节码技术

简介

几个对比: https://segmentfault.com/a/1190000009956534
ASM(Automated Storage Management)
javassist
动态代理
cglib(Code Generatator Library)
BCEL(Byte Code Engineering Library)
instrument
jdt-AST
类加载,探针,ASM,动态代理,instrument,agent

JavaAgent 是一种可以动态修改java字节码的技术,其实现原理
内定的方法名是premain
premain: 启动时,配置javaagent参数来启动
main
agentmain: attach方式,在运行过程中动态地设置加载代理类

public static void premian(String agentOps,Instrumentation inst){
//在JVM启动时,初始化函数loadClassAndCallPremain方法执行Premain-Class类置顶的premain方法
        inst -> 传入代理实例,操作字节码文件 类加载
} 
public static void premian(String agentOps){
} 

public static void agetmain(){
//JVM启动后,通过VirtualMachine附着 一个Instrument,如vm.loadAgent(jar),会调用sun.instrument.instrumentationImpl实现类的loadClassAndCallAgentmain方法执行Agentmain-Class指定类的agentmain方法

}

## Instrument premain、agentmain方法中两个参数agentArgs、inst代表什么,
1. agentArgs:代理程序命令行中输入参数,同“-javaagnet”一起传入,与main函数不同的是,这个参数是一个字符串而不是一个字符串数组
2. inst: java.lang.instrumentation实例,由JVM自动传入,集中了几乎所有功能方法,如:类操作,classpath操作等

javaAgent与Java字节码注入技术的Java探针工具

javaAgent实现原理
  • JVMTI
    JVMTI,是JVM暴露出来给用户扩展使用的接口集合,JVMTI是基于事件驱动JVM级别的AOP java1.6
    JVMTI可以支持第三方工具程序以代理的方式连接和访问JVM,并利用JVMTI提供的丰富编程接口,完成JVM相关功能

  • JVMTIAgent
    JVMTIAgent是一个动态库,利用JVMTI暴露出来的接口实现用户自行的逻辑(idea的调试也是通过这个实现的)
    JVMTIAgent主要有三个方法:

  1. Agent_OnLoad方法,agent在启动时加载,就执行这个方法
  2. Agent_OnAttach方法,agent不是在启动时候加载的,我们先attach到目标线程上,然后对于的目标进程load命令来加载agent
  3. Agent_OnUnload方法,agent卸载时调用
  • java.lang.instrument

java.lang.instrument中需要关注的是ClassFileTransformer和Instrumentation接口。

public interface ClassFileTransform{
 byte[] transform(ClassLoader loader,
           String className,
           Class<?> classBeingRedefined,
           ProtectionDomain protectionDomain,
           byte[] classfileBuffer)
           throws IllegalClassFormatException 
}
//如果transform方法返回null, 表示我们不对类进行处理直接返回。否则,会用我们返回的byte[]来代替原来的类。
//也不会生成新的类,也不需要原类的接口

Instrumentation接口。ClassFileTransformer必须添加进Instrumentation才能生效。
Instrumentation inst;
ClassFileTransformer classFileTransformer;
inst.addTransformer(classFileTransformer);


META-INF/MANIFEST.MF参数清单

  • instrument agent

instrument agent实现了Agent_OnLoad方法和Agent_OnAttach方法

  • JVM attach机制
    jvm attach机制上JVM提供了一种jvm进程间通信的功能,能让一个进程传命令给另一个进程

    1. 比如进行线程dump(程序运行期间,dump指令运行的底层原理,守护进程监听?-jstack -pid等参数传给dump的线程来执行)
  • ClassTransform
    加载类文件的时候发出ClassFileLoad事件,交给Instrument agent来调用 java agent里注册的ClassFileTransformer实现字节码的修改

  • Class Redefine

参考链接:https://www.cnblog.com/jackion5/p/10680343/html
最直接改造java类的方法莫过于直接改写class文件

字节码增强技术框架
ASM是一个字节码操作框架: Automated Storage Management,需要对class字节码熟悉
javaassist对字节码修改
byte buddy

ASM

https://www.jianshu.com/p/b5dc9c316f27

ASM是一个字节码操作框架
它能被用来动态生成类,或者增强既有类的功能
ASM可以直接产生二进制class文件,也可以在类被载入Java虚拟机之前动态改变类的行为
BCELSERL不同, ASM提供了更为现代的模型
类转换的负载小
生成的代码可以直接覆盖原来的类,或者是原始类的子类
案例:lambda表达式,cglib动态代理类
没有反射带来的性能开销

Core(各种Visitor):提供了ClassReader 和 ClassWriter
tree:
analysis:提供了一个静态字节码分析框架,除了树包之外,还可以使用它来实现真正复杂的类转化,这些转换需要知道每条指令的堆栈映射的状态

ASM字节码操纵的两种方式:
- CoreApi 访问者模式(Visitor):基于事件驱动
- TreeAPI 树节点模式:基于面向对象

AOP实现:
AdviceAdapter是MethodVisitor的子类,使用AdviceAdapter可以更方便的修改方法的字节码
Opcodes: JVM操作码
LocalVariablesSorter:对方法的参数&本地局部变量进行重新编号
GeneratorAdapter:封装了原始字节码操作,例如调用方法时的所有visitMethod封装为各种InvokeXXX
- OnMethodEnter
- OnMethodExit

ASM辅助工具
ASM Bytecode Viewer
Java Instrument

在整个虚拟上挂一个钩子程序,每次装入一个新类的时候,都必须执行一遍这段程序,即使这个类不要改变
更适用于监控和控制虚拟机的行为
但是agentmain,可以动态改变已载入的文件,在程序运行期间做些操作
Attach APi 后台监听进程开启attach listener(如果未开启,由另外一个线程监听操作)

动态代理 Proxy类
接口 -> 实现类 -> 前后之类增加一些额外的操作
静态代理和动态代理的区别:
  1. 代理类和实现类实现了相同的接口,方法增加,代理类的方法也需要相应增加
  2. 动态代理运用反射机制动态创建而成-> 不用为每一个方法创建代理实现类
  3. 都需要传入被代理对象



Proxy类,只面向接口,方法
反射
java.lang.reflect.InvocationHandler接口
java.lang.reflect.Proxy
interface InvocationHadler(){

    invoke(...){
}
}
反射引入性能代价
面向接口编程
只能改写method

public class dongtaidaili implement InvocationHandler{

targer = 被代理对象 
 
//只能代理接口,因为newProxyInstance方法只接受接口方法作为参数,最后调用newInstance
Proxy.newProxyInstance(target.getClass().getClassLoader(),target.getClass().getInterfaces(),this)
  invoke(Object proxy,Method method,Object[] args){ }
}


Cglib

参考链接:https://blog.csdn.net/mulinsen77/article/details/86565891
利用ASM开源包,对代理对象类的class文件加载进来,通过修改其字节码生成子类来处理
动态代理和cglib的区别:

  1. 代理对象是目标对象的子类,主要是对指定的类生成一个子类,覆盖其中的方法
  2. 拦截器必须实现MethodInterceptor接口
  3. hibernate中的session.load采用的是cglib实现的
  4. Spring如何选择用jdk还是cglib:
    当bean实现接口时,sprign就会用jdk的动态代理
    当bean没有实现接口时,Spring会使用cglib实现
    可以强制使用cglib
    https://www.cnblogs.com/clds/p/4985893.html
javasist
类依赖分析器

jdeps - java dependencies 、java8开始拥有

jdeps 命令显示java类文件的包级或类级依赖关系,输入可以是.class文件、目录、jar文件路径名

Android常见的依赖分析方案

获得模块与类的关系、类和类之间方法级

JDT - AST

https://blog.mythsman.com/post/5d2c11c767f841464434a3bf
https://segmentfault.com/a/1190000000609246
https://blog.csdn.net/lovelion/article/details/18953869 AST树描述比较好,完整抽象语法树
https://www.jianshu.com/p/68027eaf45ad AST NODE 描述
AST 节点结构 node类型
ASTNode
ASTVisitor

Messager主要是用来在编译期打log用的
JavacTrees提供了待处理的抽象语法树
TreeMaker封装了创建AST节点的一些方法
Names提供了创建标识符的方法
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 215,539评论 6 497
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 91,911评论 3 391
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 161,337评论 0 351
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 57,723评论 1 290
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 66,795评论 6 388
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 50,762评论 1 294
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 39,742评论 3 416
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 38,508评论 0 271
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 44,954评论 1 308
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 37,247评论 2 331
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 39,404评论 1 345
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 35,104评论 5 340
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 40,736评论 3 324
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 31,352评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,557评论 1 268
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 47,371评论 2 368
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 44,292评论 2 352

推荐阅读更多精彩内容