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

本文详细介绍了ASM库的项目结构,包括核心项目和相关包的用途。讲解了如何在Maven中配置ASM依赖,不推荐使用asm-all。还推荐了IDEA中的ASM Bytecode Outline和hexview插件辅助开发。并提供了ASM库的多个使用示例,如添加字段、新增方法、修改方法、删除字段和方法等,涉及core API和tree API的使用。最后提到了bytebuddy作为ASM的工具库,建议先学习ASM。
摘要由CSDN通过智能技术生成

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-allasm-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
<project>
  <modelVersion>4.0.0</modelVersion>

  <parent>
    <groupId>org.ow2.asm</groupId>
    <artifactId>asm-parent</artifactId>
    <version>5.2</version>
  </parent>

  <name>ASM All</name>
  <groupId>org.ow2.asm</groupId>
  <artifactId>asm-all</artifactId>
  <packaging>jar</packaging>
  
</project>
  • asm-parent的pom
    parent包含了子项目的依赖

  <dependencyManagement>
    <dependencies>

      <dependency>
        <artifactId>asm</artifactId>
        <groupId>${project.groupId}</groupId>
        <version>${project.version}</version>
      </dependency>

      <dependency>
        <artifactId>asm-tree</artifactId>
        <groupId>${project.groupId}</groupId>
        <version>${project.version}</version>
      </dependency>

      <dependency>
        <artifactId>asm-analysis</artifactId>
        <groupId>${project.groupId}</groupId>
        <version>${project.version}</version>
      </dependency>

      <dependency>
        <artifactId>asm-commons</artifactId>
        <groupId>${project.groupId}</groupId>
        <version>${project.version}</version>
      </dependency>

      <dependency>
        <artifactId>asm-util</artifactId>
        <groupId>${project.groupId}</groupId>
        <version>${project.version}</version>
      </dependency>

      <dependency>
        <artifactId>asm-xml</artifactId>
        <groupId>${project.groupId}</groupId>
        <version>${project.version}</version>
      </dependency>

    </dependencies>
  </dependencyManagement>

      

1.4 maven依赖 asm的配置

并不推荐使用1.3导入全部,因为版本太老了
这里开发者需要这么引入。asm-commonsasm-util都包含了,基本的 core api ,tree api, 和analysis

   <properties>
        <asm.version>8.0.1</asm.version>
    </properties>
    <dependencyManagement>
        <dependencies>
            <dependency>
                <artifactId>asm</artifactId>
                <groupId>org.ow2.asm</groupId>
                <version>${asm.version}</version>
            </dependency>

            <dependency>
                <artifactId>asm-tree</artifactId>
                <groupId>org.ow2.asm</groupId>
                <version>${asm.version}</version>
            </dependency>

            <dependency>
                <artifactId>asm-analysis</artifactId>
                <groupId>org.ow2.asm</groupId>
                <version>${asm.version}</version>
            </dependency>

            <dependency>
                <artifactId>asm-commons</artifactId>
                <groupId>org.ow2.asm</groupId>
                <version>${asm.version}</version>
            </dependency>

            <dependency>
                <artifactId>asm-util</artifactId>
                <groupId>org.ow2.asm</groupId>
                <version>${asm.version}</version>
            </dependency>

            <dependency>
                <artifactId>asm-xml</artifactId>
                <groupId>org.ow2.asm</groupId>
                <version>${asm.version}</version>
            </dependency>
        </dependencies>
    </dependencyManagement>
    
    <dependencies>
        <dependency>
            <artifactId>asm-commons</artifactId>
            <groupId>org.ow2.asm</groupId>
            <version>${asm.version}</version>
        </dependency>

        <dependency>
            <artifactId>asm-util</artifactId>
            <groupId>org.ow2.asm</groupId>
            <version>${asm.version}</version>
        </dependency>
    </dependencies>

核心的包都具备了,是版本8.0.1
在这里插入图片描述

2. IDEA的插件

装两个插件。
ASM Bytecode outlinehexview

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
编译后的类不包含packageimport信息。

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."<init>":()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               <init>
  #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         // "<init>":()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."<init>":()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中覆盖FieldVisitorMethodVisitor方法,进行了方法和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: <init>
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<FieldNode> fields = cn.fields;

        for (int i = 0; i <fields.size() ; i++) {
   
            FieldNode fn = fields.get(i);
            System.out.println("field in visitor: " + fn.name);

        }

        List<MethodNode> methods = cn.methods;
        for (int i = 
评论 4
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值