欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

APM - Javassist 入门 生成一个简单类

程序员文章站 2022-06-18 11:17:24
...

APM - Javassist 入门 生成一个简单类


官网

http://www.javassist.org/

http://www.javassist.org/tutorial/tutorial.html


概述

Javassist是一个开源的分析、编辑和创建Java字节码的类库,可以直接编辑和生成Java生成的字节码。

相对于bcel, asm等这些工具,开发者不需要了解虚拟机指令,就能动态改变类的结构,或者动态生成类。

Javassist简单易用, 快速。


Javassist作用

  • 运行时监控插桩埋点
  • AOP动态代理实现(性能上比Cglib生成的要慢)
  • 获取访问类结构信息:如获取参数名称信息

常用API

说明
ClassPool Javassist的类池,使用ClassPool 类可以跟踪和控制所操作的类, 与 JVM ClassLoader相似
CtClass CtClass提供了类的操作,如在类中动态添加新字段、方法和构造函数、以及改变类、父类和接口的方法。
CtMethod 类中的方法,通过它可以给类创建新的方法,还可以修改返回类型,访问修饰符等, 甚至还可以修改方法体内容代码
CtConstructor 构造函数
CtField 类的属性,通过它可以给类创建新的属性,还可以修改已有的属性的类型,访问修饰符等

Javassist 语法

项目 Value
$0, $1, $2, … this and actual parameters
$args An array of parameters. The type of $args is Object[].
$$ All actual parameters.For example, m($$) is equivalent to m($1,$2,…)
$cflow(…) cflow variable
$r The result type. It is used in a cast expression.
$w The wrapper type. It is used in a cast expression.
$_ The resulting value
$sig An array of java.lang.Class objects representing the formal parameter types
$type A java.lang.Class object representing the formal result type.
$class A java.lang.Class object representing the class currently edited.

Javassist使用流程

APM - Javassist 入门 生成一个简单类


Demo

依赖

 	 <dependency>
            <groupId>org.javassist</groupId>
            <artifactId>javassist</artifactId>
            <version>3.18.1-GA</version>
        </dependency>

import javassist.*;

/**
 * 使用Javassist 构建 一个新的类 并执行
 */
public class FirstJavasisit {
    public static void main(String[] args) throws CannotCompileException,
            NotFoundException, InstantiationException, IllegalAccessException {
        ClassPool pool = new ClassPool(true);
        // 插入类路径,通过类路径去搜索我们要的类
        pool.insertClassPath(new LoaderClassPath(FirstJavasisit.class.getClassLoader()));


        // 构建一个新的CtClass对象
        CtClass targetClass = pool.makeClass("com.artisan.Hello");
        // 实现一个接口
        targetClass.addInterface(pool.get(IHello.class.getName()));
        // 获取返回类型
        CtClass returnType = pool.get(void.class.getName());

        // 方法名称
        String mname = "sayHello";
        // 方法参数
        CtClass[] parameters = new CtClass[]{pool.get(String.class.getName())};
        // 实例化方法
        CtMethod method = new CtMethod(returnType, mname, parameters, targetClass);

        // 方法中的源码
        String src = "{"
                + "System.out.println($1);"
                + "}";
        // 设置src到方法中
        method.setBody(src);
        // 添加方法
        targetClass.addMethod(method);

        // 装在到当前的ClassLoader中
        Class cla = targetClass.toClass();
        // 实例化
        IHello hello = (IHello) cla.newInstance();
        // 方法调用
        hello.sayHello("artisan");
    }

    /**
     * 接口不是必须的,只是为了方便演示,少写点反射代码
     */
    public interface IHello {
        void sayHello(String name);
    }
}

APM - Javassist 入门 生成一个简单类


注意事项

  • 所引用的类型,必须通过ClassPool获取后才可以使用
  • 代码块中所用到的引用类型,使用时必须写全量类名
  • 代码块内容写错了,只有在运行时才报错
  • javassist只接受单个语句或用大括号括起来的语句块
  • 动态修改的类,必须在修改之前,jvm中不存在这个类的实例对象。修改方法的实现必须在修改的类加载之前进行

参考

https://baijiahao.baidu.com/s?id=1660843613132087355&wfr=spider&for=pc

https://www.cnblogs.com/scy251147/p/11100961.html

https://blog.csdn.net/21aspnet/article/details/81671777

https://www.cnblogs.com/rickiyang/p/11336268.html

上一篇: 反射

下一篇: JavaWeb---监听器Listener