agent方式实现动态类修改和增强字节码

该博客介绍了如何使用Java字节码库javassist实现动态代理,通过改造`GdBusiness`类的`deposit()`方法,在方法执行前后插入自定义日志输出。`MyClassFileTransformer`实现了`ClassFileTransformer`接口,用于在类加载到JVM前进行字节码转换。`Test`类用于测试代理效果,成功展示了存款业务的增强处理。整个流程包括创建代理类、打包成jar、设置MANIFEST.MF文件以及使用javaagent启动。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

一:实际代码

1.1 GdBusiness.java的内容

package com.aop.transform;

public class GdBusiness {
    public boolean deposit(){
        System.out.println("存款业务执行");
        return true;
    }

    public void withdrawals(){
        System.out.println("取款业务执行");
    }
}

1.2 MyClassFileTransformer.java的内容

package com.aop.transform;

import javassist.*;
import java.io.IOException;
import java.lang.instrument.ClassFileTransformer;
import java.lang.instrument.IllegalClassFormatException;
import java.lang.instrument.Instrumentation;
import java.security.ProtectionDomain;

/**
 * 字节码转换器
 */
public class MyClassFileTransformer implements ClassFileTransformer {
    /**
     * 字节码加载到jvm前会进入这个方法
     * @param loader
     * @param className
     * @param classBeingRedefined
     * @param protectionDomain
     * @param classfileBuffer
     * @return
     * @throws IllegalClassFormatException
     */
    @Override
    public byte[] transform(ClassLoader loader, String className, Class<?> classBeingRedefined, ProtectionDomain protectionDomain, byte[] classfileBuffer) throws IllegalClassFormatException {
        //如果加载GdBusiness类才拦jue
        if(!"com/aop/transform/GdBusiness".equals(className)){
            return null;
        }
        if(className!=null&&className.indexOf("/")!=-1){
            className=className.replaceAll("/",".");
        }
        try{
            //通过包名获取类文件
            CtClass cc=ClassPool.getDefault().get(className);
            //获得指定方法名的方法
            CtMethod m=cc.getDeclaredMethod("deposit");
            //在方法执行前插入代码
            m.insertBefore("System.out.println(\"存款业务执行前:1.欢迎您来存款...\");");
            //在方法执行后插入代码
            m.insertAfter("System.out.println(\"存款业务执行后:2.您存款结束...\");");
            return cc.toBytecode();
        }catch(NotFoundException e){
            e.printStackTrace();
        }catch(CannotCompileException e){
            e.printStackTrace();
        }catch(IOException e){
            e.printStackTrace();
        }
        return null;
    }

    /**
     * 在main 函数执行前,执行的函数
     * @param options
     * @param ins
     */
    public static void premain(String options, Instrumentation ins){
        //注册我自己的字节码转换器
        ins.addTransformer(new MyClassFileTransformer());
    }
}

1.3Test.java的内容

package com.aop.transform;

public class Test {
    public static void main(String[] args){
        new GdBusiness().deposit();
        new GdBusiness().withdrawals();
    }
}

1.4 MANIFEST.MF的内容

Manifest-Version: 1.0
Premain-Class: com.aop.transform.MyClassFileTransformer
Can-Redefine-Classes: true
Can-Retransform-Classes: true
Can-Set-Native-Method-Prefix: true

META-INF/MANIFEST.MF内容:
说明:Premain-Class用来允许jar文件作为一个java代理运行

1.5 通过pom.xml 下载 javassist-3.25.0-GA.jar

 <!-- asm start-->
 <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>
 <!-- asm end-->

下载到了 /Users/lichunmei/.m2/repository/org/javassist/javassist/3.25.0-GA/javassist-3.25.0-GA.jar
而后把它copy到/Users/lichunmei/Documents/workspace/study/jar-test/

二:运行测试步骤

/**
 *agent的方式挂载
1.生成class可以运行一个带main的方法。
 把 生成的class  全部放到  /Users/lichunmei/Documents/workspace/study/jar-test/target/com/aop/transform/下
2.各文件放置的位置请看下面tree查出来的结构。
3.打包成aop.jar
--> 到target里打jar包
 把class放到这里来了 /Users/lichunmei/Documents/workspace/study/jar-test/target/
 jar -cvfm agent-aop.jar META-INF/MANIFEST.MF com
 
打完后copy到jar-test/目录下
 /Users/lichunmei/Documents/workspace/study/jar-test/tree 的目录结构
 ├── agent-aop.jar
 ├── javassist-3.25.0-GA.jar
 └── target
    ├── META-INF
    │   └── MANIFEST.MF
    └── com
        └── aop
            └── transform
                ├── GdBusiness.class
                ├── MyClassFileTransformer.class
                ├── Test.class
 4.运行
jar-test> java -javaagent:agent-aop.jar -cp javassist-3.25.0-GA.jar com.aop.transform.Test
 objc[8798]: Class JavaLaunchHelper is implemented in both /Library/Java/JavaVirtualMachines/jdk1.8.0_111.jdk/Contents/Home/bin/java (0x10e9154c0) and /Library/Java/JavaVirtualMachines/jdk1.8.0_111.jdk/Contents/Home/jre/lib/libinstrument.dylib (0x10e9da4e0). One of the two will be used. Which one is undefined.
 存款业务执行前:1.欢迎您来存款...
 存款业务执行
 存款业务执行后:2.您存款结束...
 取款业务执行
 */

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值