ASM字节码操作库---入门环境搭建

文章目录

  • 概述
  • 环境配置
  • demo尝鲜
  • 源码地址

概述

ASM是一个操作字节码的类库,提到字节码,很多人想到的首先是JAVA字节码。其实Kotlin,Groovy等语言也会生成字节码,并且和Java的字节码一样,都能被虚拟机识别执行,这就意味着ASM也可以用在这些语言上,比如Android现在的主流开发语言Kotlin。就拿JAVA语言来说,我们都知道,我们编写代码的那个文件称为.java文件,经过Java编译器(javac), .java文件会被编译成.class文件,在.class文件中就存储着字节码(bytecode)数据,ASM可以对字节码数据做修改,然后生成一份新的字节码文件,而且ASM还可以在什么都没有的情况下,直接生成一个.class文件。本文的demo就是演示这个场景,除此之外,ASM还能做分析操作,分析操作是指它可以对一份字节码做分析统计的操作,但是不生成新的字节码文件,也就是说它只是单纯分析,不做任何修改。本文使用JAVA语言作为ASM的演示demo。

环境配置

当我们想要去了解一个语言或者是开源库的时候,第一件事都是将他们需要的环境配置好,然后跑起来看下效果。ASM的环境配置比较简单,直接引入相关的库就可以了,ASM在Android中一般是集成到gradle脚本中去使用,本文为了演示,直接使用 IDEA集成开发环境+maven的方式去做演示,后面集成到Android中的时候其实方法也是一样的,引入对应的依赖就可以了。

我们在IDEA集成开发环境中新建一个maven项目,如下图所示,注意红圈中的选择。
图1建完以后,项目的结构如下所示:
在这里插入图片描述然后我们找到pom.xml文件,导入asm的依赖就可以了,如下:

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 
         http:// maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>

    <groupId>org.example</groupId>
    <artifactId>AsmDemo</artifactId>
    <version>1.0-SNAPSHOT</version>

    <properties>
        <maven.compiler.source>11</maven.compiler.source>
        <maven.compiler.target>11</maven.compiler.target>
        <project.build.sourceEncoding>UTF-8</
        project.build.sourceEncoding>
        <asm.version>9.0</asm.version>
    </properties>

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

demo尝鲜

demo会生成一个新的类,并且调用类中的toString方法打印一段日志,为了演示,定义一个ClassLoader类加载器去加载Asm生成的类。

生成的类对应的.java文件如下:

public class HelloWorldAsm {
    @Override
    public String toString() {
        return "this is a HelloAsm class obj";
    }
}

上面的类我们不用自己写,而是用Asm去生成上面的类对应的字节码文件,然后通过类加载器去加载执行我们生成的类。生成类的代码如下:

public class HelloWordAsm implements Opcodes {
    public static byte[] genHelloWorldClass(){
        ClassWriter cw = 
        new ClassWriter(ClassWriter.COMPUTE_FRAMES);
        cw.visit(V1_8,ACC_PUBLIC|ACC_SUPER,"demo/HelloWorldAsm",
                null,
                "java/lang/Object",
                null);

        {
            // 添加无参构造方法
            MethodVisitor mv1 = cw.visitMethod(
                    ACC_PUBLIC,
                    "<init>",
                    "()V",
                    null,
                    null
            );
            mv1.visitCode();
            mv1.visitVarInsn(ALOAD,0);
            // 调用父类的构造方法
            mv1.visitMethodInsn(
                    INVOKESPECIAL,
                    "java/lang/Object",
                    "<init>",
                    "()V",
                    false
            );
            mv1.visitInsn(RETURN);
            mv1.visitMaxs(1,1);
            mv1.visitEnd();
        }

        {
            // 添加一个toString 方法,返回String
            MethodVisitor mv2 = cw.visitMethod(
                    ACC_PUBLIC,
                    "toString",
                    "()Ljava/lang/String;",
                    null,
                    null
            );

            mv2.visitCode();
            mv2.visitLdcInsn("this is a HelloAsm class obj");
            mv2.visitInsn(ARETURN);
            mv2.visitMaxs(1,1);
            mv2.visitEnd();
        }
        cw.visitEnd();

        return cw.toByteArray();
    }
}

上面的代码生成一个类后,我们编写一个类加载器去加载我们生成的类

public class MyClassLoader extends ClassLoader{
    @Override
    protected Class<?> findClass(String name) throws
     ClassNotFoundException {
        System.out.println("MyClassLoader: findClass: name==>" 
        + name);
        if("demo.HelloWorldAsm".equals(name)){
            byte [] bytes = HelloWordAsm.genHelloWorldClass();
            Class<?> aClass = defineClass(name, bytes, 0,
             bytes.length);
            return aClass;
        }
        return super.findClass(name);
    }
}

最后我们编写测试代码验证下生成类的正确性:

public class TestHelloAsm {
    public static void main(String[] args) {
        MyClassLoader myClassLoader = new MyClassLoader();
        try {
            Class<?> aClass = 
            myClassLoader.loadClass("demo.HelloWorldAsm");
            Object instance = aClass.newInstance();
            System.out.println("instance: " + instance);
        } catch (Exception e) {
            throw new RuntimeException(e);
        }
    }
}

如上面代码所示,我们使用类加载器去加载我们生成的类,然后创建了一个对象,当我们打印这个对象的时候,就会调用这个对象的toString方法,打印出我们的生成类中的toString方法返回的字符串信息。运行结果如下所示:
在这里插入图片描述
运行出上面的结果就证明环境OK了

源码地址

为了让读者能更快的看到效果,在此提供上源码,后续有对应的文章也会同步到这个源码上。源码地址

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:/a/578202.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

MATLAB无法识别汉字的问题解决方案

试了100种方法&#xff0c;都是不行。 期待的结果 应该是这样式的&#xff1a; feature(‘locale’) ans 包含以下字段的 struct: ctype: zh_CN.UTF-8collate: zh_CN.UTF-8time: zh_CN.UTF-8numeric: en_US_POSIX.UTF-8monetary: zh_CN.UTF-8messages: zh_CN.UTF-8encoding…

行为学学习记忆实验和抗焦虑实验两款硬件

安徽耀坤XWX-BM八臂迷宫实验&#xff08;Eight-arm Maze Test&#xff0c;RMT&#xff09;由八个完全相同的臂组成&#xff0c;这些臂从一个中央平台放射出来&#xff0c;所以又被称为放射迷宫。其基本方式是&#xff1a;训练动物受食物的驱使对迷宫的各臂进行探究&#xff0c;…

golang反射

go反射 反射基本介绍应用场景基本使用结构体注意练习最佳实践遍历结构体的方法&#xff0c;调用接头体的方法&#xff0c;获取结构体的标签 反射 基本介绍 反射可以在运行时动态获取变量的各种信息&#xff0c;比如变量的类型(type)、类别(kind)如果是结构体变量&#xff0c;…

【学习笔记二十九】EWM较特殊的业务场景

一、供应商寄售业务相关 1.创建寄售物料、寄售信息记录以及寄售的采购订单 2.创建交货单 3.维护入库交货 行项目里存在C寄售的标识 4.创建上架的仓库任务并确定 查看仓位库存&#xff0c;发现仓位库存里存在寄售标识C以及寄售库存所有方 5.寄售转自有 ①首先MIGO里进行寄…

Linux 权限与软件包管理器 yum

一. 研究Linux默认权限 目录 &#xff0c;起始权限&#xff1a;777 普通文件&#xff0c;起始权限666 Linux系统中存在权限掩码 使用umask指令也可以改变掩码 如果将掩码改为0000 我们可以看到权限发生改变&#xff08;重新设置掩码&#xff09; 最终权限起始权限 去掉 权限…

0426_C高级4

练习1&#xff1a; 输入一个数字&#xff0c;实现数字逆置&#xff08;不使用字符串截取方式&#xff09; 1 #!/bin/bash2 read -p "输入一个数字&#xff1a;" number3 p$number4 result5 while [ $p -ne 0 ]6 do7 result$((result*10p%10))8 p$((p/10))9 …

Python基础10-使用正则表达式进行文本处理

在编程过程中&#xff0c;我们经常需要对文本进行处理&#xff0c;以提取、替换或分割特定的字符串。正则表达式&#xff08;Regular Expression&#xff09;是一种强大的文本处理工具&#xff0c;它可以帮助我们实现这些任务。以下是使用正则表达式进行文本处理的一些基本方法…

react-lib 读取本地模板创建PDF

读取本地文件和读取远程的一样&#xff0c;都使用fetch去获取 async function modifyPdf() {let url ./template.pdflet existingPdfBytes await fetch(url).then(res > res.arrayBuffer()) // 这里也有问题要转一下const d new Uint8Array(existingPdfBytes)const pdfDo…

Mysql索引规范及原理分析

1 Mysql存储引擎 MySQL中的数据用各种不同的技术存储在文件中&#xff0c;每一种技术都使用不同的存储机制、索引技巧、锁定水平并最终提供不同的功能和能力&#xff0c;这些不同的技术以及配套的功能在MySQL中称为存储引擎。 存储引擎是MySQL将数据存储在文件系统中的存储方…

235 基于matlab的时频盲源分离(TFBSS)算法

基于matlab的时频盲源分离&#xff08;TFBSS&#xff09;算法&#xff0c;TFBSS用空间频率分布来分离非平稳信号&#xff0c;可以分离具有不同时频分布的源信号&#xff0c;也能够分离具有相同谱密度但时频分布不同的高斯源。同时&#xff0c;该算法在时频域上局域化源信号能量…

39岁TVB靓仔小生自曝恋情,曾沦为洗车工如今半年赚足7位数

39岁高钧贤自从2005年参加香港先生选举夺冠后&#xff0c;之后加入TVB拍摄过多套电视剧集&#xff0c;最近更有份参与《逆天奇案2》&#xff0c;日前他回到TVB电视城一厂与冯盈盈宣传剧集&#xff0c;更随即拍摄短片纪录放在网上分享&#xff0c;意外曝光TVB餐厅餐单&#xff0…

如何使用IDEA直接连接MySQL数据库

如何使用IDEA直接连接MySQL数据库 新建一个空项目打开DataBase窗口连接数据库第一次连接 需要先下载驱动上一步驱动下载太慢怎么办&#xff1f;下载好驱动后 测试连接 新建一个空项目 打开DataBase窗口 连接数据库 第一次连接 需要先下载驱动 如果这里下载的很慢 看下一步解决…

DaVinci Fusion Studio 19 for Mac/win:影视后期特效合成的巅峰之作

在影视后期制作的广袤天地里&#xff0c;一款强大的特效合成软件如同一位技艺高超的魔法师&#xff0c;能够化腐朽为神奇&#xff0c;将普通的影像素材转变为震撼人心的视觉盛宴。而DaVinci Fusion Studio 19&#xff0c;正是这样一款备受影视从业者推崇的巅峰之作。 无论是Ma…

矩阵按列相乘运算的并行化实现方法

这两天一直在琢磨如下矩阵计算问题。 已知dm矩阵X和hq矩阵Y&#xff0c;求如下矩阵&#xff1a; 其中X(:,i), Y(:,j)分别表示矩阵X, Y的第i列和第j列&#xff0c;易知Z为dh矩阵。 如果直接串行计算矩阵Z&#xff0c;两个循环共有mq&#xff0c;则会很慢&#xff0c;能不能并行化…

【b站李同学的Lee】Part 3 服务器开发 NodeJS+Gulp基础入门+实战

课程地址&#xff1a;【NodeJSGulp基础入门实战】 https://www.bilibili.com/video/BV1aE411n737/?share_sourcecopy_web&vd_sourceb1cb921b73fe3808550eaf2224d1c155 目录 9 服务器端基础概念 9.1 网站的组成 9.2 Node网站服务器 9.3 IP地址 9.4 域名 9.5 端口 9…

SCSS全局配置 vue项目(二)

目录 1、先要查看node版本 2、安装对应的node-sass、sass-loader版本 2.1根据项目使用的node版本安装对应的node-sass版本 2.2根据node-sass版本选择兼容的sass-loader版本&#xff0c;不然项目无法正常运行 3、在 vue.config.js 中配置&#xff1a; 4、在组件中…

刷题训练之前缀和

> 作者&#xff1a;დ旧言~ > 座右铭&#xff1a;松树千年终是朽&#xff0c;槿花一日自为荣。 > 目标&#xff1a;熟练掌握前缀和算法。 > 毒鸡汤&#xff1a;学习&#xff0c;学习&#xff0c;再学习 ! 学&#xff0c;然后知不足。 > 专栏选自&#xff1a;刷题…

物联网的基本功能及五大核心技术——青创智通

工业物联网解决方案-工业IOT-青创智通 物联网基本功能 物联网的最基本功能特征是提供“无处不在的连接和在线服务”&#xff0c;其具备十大基本功能。 &#xff08;1&#xff09;在线监测&#xff1a;这是物联网最基本的功能&#xff0c;物联网业务一般以集中监测为主、控制为…

Vitis HLS 学习笔记--C/C++ static 关键字的作用

目录 1. 简介 2. c/c共有性质 3. c独有性质 4. 示例说明 5. static 对于 HLS 工具的影响 6. 总结 1. 简介 在Vitis HLS中&#xff0c;偶尔会用到 static 关键字。考虑到Vitis HLS同时兼容C和C语言&#xff0c;有必要理解这两种语言中static关键字细微差异。本文旨在梳理…

Centos7.9系统MySQL5.7.32升级为5.7.44(生成环境操作)

1.背景 由于客户进行等保漏扫和渗透&#xff0c;生成环境mysql数据库被扫描出了 高危漏洞。 如图&#xff1a;部分漏洞 查看漏洞详细信息&#xff0c;建议升级到指定版本解决&#xff1a; 说明&#xff1a; 本文仅适合使用当前数据库为 RPM 安装方式 2.升级前准备 查看环…