maven依赖asm_maven 导入asm的依赖 、 简单入门

asm项目结构

1. 项目结构

1.1. asm的仓库

1.2 核心项目

1.2.1 org.objectweb.asm 和 org.objectweb.asm.signature

1.2.2 org.objectweb.asm.util

1.2.3 org.objectweb.asm.commons

1.2.4 org.objectweb.asm.tree

1.2.5 org.objectweb.asm.tree.analysis

1.3 其他项目

1.3.1 asm-all和asm-parent

1.4 maven依赖 asm的配置

2. IDEA的插件

2.1 ASM Bytecode outline 插件

2.1 hexview插件

3. asm的使用示例

3.1 源码 & 字节码

3.2 访问类的方法和字段

core API

tree API

3.3 添加一个字段

core API

tree API

3.4 新增方法

core API

tree API

3.5 删除字段和方法

core API

tree API

3.6 修改方法

core API

tree API

3.7 AdviceAdapter的使用

core API

tree API

3.8 try-catch

core API

4. bytebuddy的示例

1. 项目结构

1.1. asm的仓库

maven仓库

1.2 核心项目

1.2.1 org.objectweb.asm 和 org.objectweb.asm.signature

包定义了基于事件的API,并提供了类分析器和写入器组件。它们包含在 asm.jar 中。

1.2.2 org.objectweb.asm.util

包,位于asm-util.jar中,提供各种基于核心 API 的工具,可以在开发和调试 ASM 应用程序时使用。

1.2.3 org.objectweb.asm.commons

包提供了几个很有用的预定义类转换器,它们大多是基于核心 API 的。这个包包含在 asm-commons.jar中。

1.2.4 org.objectweb.asm.tree

包,位于asm-tree.jar 存档文件中,定义了基于对 象的 API,并提供了一些工具,用于在基于事件和基于对象的表示方法之间进行转换。

1.2.5 org.objectweb.asm.tree.analysis

包提供了一个类分析框架和几个预定义的 类 分析器,它们以树 API 为基础。这个包包含在 asm-analysis.jar 文件中。

1.3 其他项目

可以看出来1.2描述的几个包和1.1仓库是基本对应的。

但是除了asm-all和asm-parent,与asm-debug等。

1.3.1 asm-all和asm-parent

asm-all包含了asm-parent,asm-parent 包含了所有的依赖。

一般来讲,使用者希望导入一个总的jar,其中包含子项目的jar。但是asm-all目前只停留在version 5.2,而最新子项目版本已经是8.1,不推荐使用。

asm-all 的pom

4.0.0modelVersion>

org.ow2.asmgroupId>

asm-parentartifactId>

5.2version>

parent>

ASM Allname>

org.ow2.asmgroupId>

asm-allartifactId>

jarpackaging>

project>

asm-parent的pom

parent包含了子项目的依赖

asmartifactId>

${project.groupId}groupId>

${project.version}version>

dependency>

asm-treeartifactId>

${project.groupId}groupId>

${project.version}version>

dependency>

asm-analysisartifactId>

${project.groupId}groupId>

${project.version}version>

dependency>

asm-commonsartifactId>

${project.groupId}groupId>

${project.version}version>

dependency>

asm-utilartifactId>

${project.groupId}groupId>

${project.version}version>

dependency>

asm-xmlartifactId>

${project.groupId}groupId>

${project.version}version>

dependency>

dependencies>

dependencyManagement>

1.4 maven依赖 asm的配置

并不推荐使用1.3导入全部,因为版本太老了

这里开发者需要这么引入。asm-commons 和asm-util都包含了,基本的 core api ,tree api, 和analysis

8.0.1asm.version>

properties>

asmartifactId>

org.ow2.asmgroupId>

${asm.version}version>

dependency>

asm-treeartifactId>

org.ow2.asmgroupId>

${asm.version}version>

dependency>

asm-analysisartifactId>

org.ow2.asmgroupId>

${asm.version}version>

dependency>

asm-commonsartifactId>

org.ow2.asmgroupId>

${asm.version}version>

dependency>

asm-utilartifactId>

org.ow2.asmgroupId>

${asm.version}version>

dependency>

asm-xmlartifactId>

org.ow2.asmgroupId>

${asm.version}version>

dependency>

dependencies>

dependencyManagement>

asm-commonsartifactId>

org.ow2.asmgroupId>

${asm.version}version>

dependency>

asm-utilartifactId>

org.ow2.asmgroupId>

${asm.version}version>

dependency>

dependencies>

核心的包都具备了,是版本8.0.1

2. IDEA的插件

装两个插件。

ASM Bytecode outline 与hexview

2.1 ASM Bytecode outline 插件

源码&字节码

等价的ASM API

2.1 hexview插件

仅仅是以16进制显示.class文件

这个是真正的字节码,而asm插件中的字节码,是以人类可读的方式处理过。类似javap

3. asm的使用示例

demo源码

这一步门槛比较高,需要对java 字节码的知识。和ASM 有全面的了解。

java 字节码知识推荐 《深入理解jvm 字节码》和jvm 规范比对着看

ASM 推荐阅读官方指导手册,写的很容易懂。博客里提供了中英两版,比对者看。

《深入理解jvm 字节码》中的例子,使用基于事件的core api 和基于文档模型的tree API。如果具备字节码结构的知识、字节码指令知识、栈帧的模型的知识,去理解下面的例子非常容易,因为对类的加工,本质是增删改查字节码内容而已。

3.1 源码 & 字节码

源码

package com;

public class Application {

public int a = 0;

public int b = 1;

public void test01() {

}

public void test02() {

}

}

字节码

javap -verbose Application.class

编译后的类不包含package和import信息。

Classfile /Users/sunqiyuan/Desktop/Work/mycode/Javadetail/BYTECODE/bytecode/target/classes/com/Application.class

Last modified 2020-6-30; size 464 bytes

MD5 checksum 66668ae198d146acc35018549c757af7

Compiled from "Application.java"

public class com.Application

minor version: 0

major version: 52

flags: ACC_PUBLIC, ACC_SUPER

Constant pool:

#1 = Methodref #5.#20 // java/lang/Object."":()V

#2 = Fieldref #4.#21 // com/Application.a:I

#3 = Fieldref #4.#22 // com/Application.b:I

#4 = Class #23 // com/Application

#5 = Class #24 // java/lang/Object

#6 = Utf8 a

#7 = Utf8 I

#8 = Utf8 b

#9 = Utf8

#10 = Utf8 ()V

#11 = Utf8 Code

#12 = Utf8 LineNumberTable

#13 = Utf8 LocalVariableTable

#14 = Utf8 this

#15 = Utf8 Lcom/Application;

#16 = Utf8 test01

#17 = Utf8 test02

#18 = Utf8 SourceFile

#19 = Utf8 Application.java

#20 = NameAndType #9:#10 // "":()V

#21 = NameAndType #6:#7 // a:I

#22 = NameAndType #8:#7 // b:I

#23 = Utf8 com/Application

#24 = Utf8 java/lang/Object

{

public int a;

descriptor: I

flags: ACC_PUBLIC

public int b;

descriptor: I

flags: ACC_PUBLIC

public com.Application();

descriptor: ()V

flags: ACC_PUBLIC

Code:

stack=2, locals=1, args_size=1

0: aload_0

1: invokespecial #1 // Method java/lang/Object."":()V

4: aload_0

5: iconst_0

6: putfield #2 // Field a:I

9: aload_0

10: iconst_1

11: putfield #3 // Field b:I

14: return

LineNumberTable:

line 3: 0

line 4: 4

line 5: 9

LocalVariableTable:

Start Length Slot Name Signature

0 15 0 this Lcom/Application;

public void test01();

descriptor: ()V

flags: ACC_PUBLIC

Code:

stack=0, locals=1, args_size=1

0: return

LineNumberTable:

line 9: 0

LocalVariableTable:

Start Length Slot Name Signature

0 1 0 this Lcom/Application;

public void test02();

descriptor: ()V

flags: ACC_PUBLIC

Code:

stack=0, locals=1, args_size=1

0: return

LineNumberTable:

line 13: 0

LocalVariableTable:

Start Length Slot Name Signature

0 1 0 this Lcom/Application;

}

SourceFile: "Application.java"

3.2 访问类的方法和字段

core API

接受编译过的Application.class的byte[]。ClassVisitor中覆盖FieldVisitor和MethodVisitor方法,进行了方法和field的打印。

本类中ClassReader.SKIP_CODE | ClassReader.SKIP_DEBUG跳过对debug信息和方法Code属性的访问。

package com;

import org.objectweb.asm.*;

import static jdk.internal.org.objectweb.asm.Opcodes.ASM5;

/**

* 访问类的方法和区域

*/

public class B_visitContent extends ClassLoader {

public void visitByCoreAPI() throws Exception {

ClassReader cr = Tool.getClassReader();

// 使用 new ClassWriter(0) 时,不会自动计算任何东西。必须自行计算帧、局部变量与操作数栈的大小

ClassWriter cw = new ClassWriter(0);

ClassVisitor cv = new ClassVisitor(ASM5, cw) {

@Override

public FieldVisitor visitField(int access, String name, String descriptor, String signature, Object value) {

System.out.println("field in visitor: " + name);

return super.visitField(access, name, descriptor, signature, value);

}

@Override

public MethodVisitor visitMethod(int access, String name, String descriptor, String signature, String[] exceptions) {

System.out.println("method in visitor: " + name);

return super.visitMethod(access, name, descriptor, signature, exceptions);

}

};

/*

ClassReader.SKIP_DEBUG 跳过类文件中的调试信息,比如行号信息(LineNumberTable)

ClassReader.SKIP_CODE 跳过方法体中的Code属性,比如(方法字节码、异常表等信息)

ClassReader.SKIP_DEBUG 展开StackMapTable属性

ClassReader.SKIP_DEBUG 跳过StackMapTable属性

*/

cr.accept(cv, ClassReader.SKIP_CODE | ClassReader.SKIP_DEBUG);

}

public static void main(String[] args) throws Exception{

new B_visitContent().visitByCoreAPI();

}

}

打印结果

field in visitor: a

field in visitor: b

method in visitor: method in visitor: test01

method in visitor: test02

tree API

等同于上面的例子

package com;

import org.objectweb.asm.*;

import org.objectweb.asm.tree.ClassNode;

import org.objectweb.asm.tree.FieldNode;

import org.objectweb.asm.tree.MethodNode;

import java.util.List;

import static jdk.internal.org.objectweb.asm.Opcodes.ASM5;

/**

* 访问类的方法和区域

*/

public class B_visitContent extends ClassLoader {

public void visitByTreeAPI() throws Exception {

ClassReader cr = Tool.getClassReader();

// 使用 new ClassWriter(0) 时,不会自动计算任何东西。必须自行计算帧、局部变量与操作数栈的大小

ClassNode cn = new ClassNode();

/*

ClassReader.SKIP_DEBUG 跳过类文件中的调试信息,比如行号信息(LineNumberTable)

ClassReader.SKIP_CODE 跳过方法体中的Code属性,比如(方法字节码、异常表等信息)

ClassReader.SKIP_DEBUG 展开StackMapTable属性

ClassReader.SKIP_DEBUG 跳过StackMapTable属性

*/

cr.accept(cn, ClassReader.SKIP_CODE | ClassReader.SKIP_DEBUG);

List fields = cn.fields;

for (int i = 0; i

FieldNode fn = fields.get(i);

System.out.println("field in visitor: " + fn.name);

}

List methods = cn.methods;

for (int i = 0; i

<
  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值