You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何使用ASM配合Gradle在编译期修改javac生成的Java字节码

实现方案说明

核心逻辑

编译期修改class不需要用到agent,核心思路是在javac任务执行完成、class文件生成后,插入自定义任务读取所有class文件,通过ASM修改字节码后覆盖原文件即可在编译期完成插桩。

代码存放位置

ASM插桩逻辑需要放到独立的Gradle插件模块中,结构如下:

  • 根项目下新建独立插件模块,命名为asm-plugin
  • 该模块单独配置ASM和Gradle插件开发依赖
  • 插件开发完成后 apply 到你的业务模块,即可自动介入项目编译流程

最简实现示例

1. 插件模块配置

asm-plugin/build.gradle 配置如下:

plugins {
    id 'java-gradle-plugin'
    id 'groovy'
}

dependencies {
    implementation gradleApi()
    implementation localGroovy()
    // 引入ASM依赖
    implementation 'org.ow2.asm:asm:9.5'
    implementation 'org.ow2.asm:asm-commons:9.5'
}

gradlePlugin {
    plugins {
        asmInject {
            id = 'com.example.asm-inject'
            implementationClass = 'com.example.AsmInjectPlugin'
        }
    }
}

2. 插件入口实现

插件入口负责hook javac任务,插入插桩逻辑:

package com.example;

import org.gradle.api.Plugin;
import org.gradle.api.Project;
import org.gradle.api.tasks.compile.JavaCompile;
import java.io.*;
import org.objectweb.asm.*;

public class AsmInjectPlugin implements Plugin<Project> {
    @Override
    public void apply(Project project) {
        project.getTasks().withType(JavaCompile.class, compileTask -> {
            // javac执行完成后执行插桩
            compileTask.doLast(task -> {
                File classOutputDir = compileTask.getDestinationDir();
                // 遍历所有class文件修改
                modifyClassFiles(classOutputDir);
            });
        });
    }

    private void modifyClassFiles(File dir) {
        for (File file : dir.listFiles()) {
            if (file.isDirectory()) {
                modifyClassFiles(file);
            } else if (file.getName().endsWith(".class") 
                && !file.getName().matches("(R|BuildConfig).*class")) {
                try {
                    FileInputStream fis = new FileInputStream(file);
                    ClassReader cr = new ClassReader(fis);
                    ClassWriter cw = new ClassWriter(cr, ClassWriter.COMPUTE_FRAMES);
                    // 自定义ClassVisitor处理字节码
                    cr.accept(new CustomClassVisitor(Opcodes.ASM9, cw), 0);
                    // 写回修改后的字节码
                    FileOutputStream fos = new FileOutputStream(file);
                    fos.write(cw.toByteArray());
                    fos.close();
                    fis.close();
                } catch (Exception e) {
                    e.printStackTrace();
                }
            }
        }
    }
}

3. ASM字节码修改逻辑

示例实现给所有普通方法开头插入打印逻辑:

package com.example;

import org.objectweb.asm.ClassVisitor;
import org.objectweb.asm.MethodVisitor;
import org.objectweb.asm.Opcodes;

public class CustomClassVisitor extends ClassVisitor {
    public CustomClassVisitor(int api, ClassVisitor cv) {
        super(api, cv);
    }

    @Override
    public MethodVisitor visitMethod(int access, String name, String desc, String sign, String[] exceptions) {
        MethodVisitor mv = super.visitMethod(access, name, desc, sign, exceptions);
        // 跳过构造方法和静态代码块
        if ("<init>".equals(name) || "<clinit>".equals(name)) {
            return mv;
        }
        return new MethodVisitor(Opcodes.ASM9, mv) {
            @Override
            public void visitCode() {
                // 插入System.out.println("hello ASM")
                visitFieldInsn(Opcodes.GETSTATIC, "java/lang/System", "out", "Ljava/io/PrintStream;");
                visitLdcInsn("hello ASM");
                visitMethodInsn(Opcodes.INVOKEVIRTUAL, "java/io/PrintStream", "println", "(Ljava/lang/String;)V", false);
                super.visitCode();
            }
        };
    }
}

4. 主项目引用插件

根目录build.gradle添加插件引用:

plugins {
    id 'com.example.asm-inject' version '1.0-SNAPSHOT' apply false
}

业务模块的build.gradle应用插件:

plugins {
    id 'java'
    id 'com.example.asm-inject'
}

验证方法

执行build任务后,反编译业务模块生成的class文件,即可看到所有普通方法开头已经插入了指定的打印逻辑。

内容的提问来源于stack exchange,提问作者SecretX

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.10.03 12:18:04