字节码编程,Javassist篇一《基于javassist的第一个案例helloworld》

做者:小傅哥
博客:bugstack.cnjava

沉淀、分享、成长,让本身和他人都能有所收获!web

目录

1、前言

在字节码编程方面有三个比较常见的框架;ASMbyte-buddyJavassist,他们均可以对这字节码进行操做,只是操做方式和控制粒度不一样。编程

其中 ASM 更偏向于底层,须要了解 JVM 虚拟机中指定规范以及对局部变量以及操做数栈的知识。虽然在编写起来比较麻烦,可是它也是性能最好功能最强的字节码操做框架。常见的会用在 CGLIB 动态代理类中,以及一些非入侵的探针监控场景中。框架

另外两个框架都是有强大的 API,操做使用上更加容易控制。虽然对对比上会比 ASM 性能差一些,但不是说性能彻底很差。一样在一些监控场景中也用的很是多。若是你细心能够在你的工程 jar 包搜索一下。编辑器

在这以前我已经编写了 Javaagent全链路监控ASM 的部分文章,虽然这部分技术内容在 CRUD 开发中并不经常使用,但随着自动化测试、非入侵监控的大量使用,仍是蛮多人须要这样的技能学习的。同时我也是这样一个技能的学习者,为此后面会陆续编写和完善关于 字节码编程 这个专栏。也但愿这个专栏在提高本身技术栈的同时也帮助他人成长。函数

那么,小傅哥计划从 JavassistASM 陆续完成整套专栏学习的文章编写。从简单入门到应用操做,一步步来完成成体系的技术知识栈学习。性能

好!,如今开始第一个Helloworld案例。相关源码能够经过关注 公众号:bugstack虫洞栈 获取学习

2、开发环境

  1. JDK 1.8.0
  2. javassist 3.12.1.GA
<dependency>
    <groupId>javassist</groupId>
    <artifactId>javassist</artifactId>
    <version>3.12.1.GA</version>
    <type>jar</type>
</dependency>
复制代码

3、案例目标

不看实现过程的话,咱们的案例目标其实很简单,就是使用 javassist 输出一行 Helloworld 。这话像不像产品说的测试

public class HelloWorld {
    public static void main(String[] args) {
        System.out.println("javassist hi helloworld by 小傅哥(bugstack.cn)");
    }

    public HelloWorld() {
    }
}
复制代码

以上的这段代码就是咱们接下来须要使用字节码编程技术来实现的内容。flex

4、技术实现

其实输出一个 Helloworld 仍是蛮简单的,主要是从这里面去学习一下 Javassist 的基本语法结构,也能为后续的学习有一个基础的概念。

javassist Helloworld

/**
 * 公众号:bugstack虫洞栈
 * 博客栈:https://bugstack.cn - 沉淀、分享、成长,让本身和他人都能有所收获!
 * 本专栏是小傅哥多年从事一线互联网Java开发的学习历程技术汇总,旨在为你们提供一个清晰详细的学习教程。若是能为您提供帮助,请给予支持(关注、点赞、分享)!
 */

public class GenerateClazzMethod {


    public static void main(String[] args) throws IOException, CannotCompileException, NotFoundException, IllegalAccessException, InstantiationException, NoSuchMethodException, InvocationTargetException {

        ClassPool pool = ClassPool.getDefault();

        // 建立类 classname:建立类路径和名称
        CtClass ctClass = pool.makeClass("org.itstack.demo.javassist.HelloWorld");

        // 添加方法
        CtMethod mainMethod = new CtMethod(CtClass.voidType, "main"new CtClass[]{pool.get(String[].class.getName())}, ctClass);
        mainMethod.setModifiers(Modifier.PUBLIC + Modifier.STATIC);
        mainMethod.setBody("{System.out.println(\"javassist hi helloworld by 小傅哥(bugstack.cn)\");}");
        ctClass.addMethod(mainMethod);

        // 建立无参数构造方法
        CtConstructor ctConstructor = new CtConstructor(new CtClass[]{}, ctClass);
        ctConstructor.setBody("{}");
        ctClass.addConstructor(ctConstructor);

        // 输出类内容
        ctClass.writeFile();

        // 测试调用
        Class clazz = ctClass.toClass();
        Object obj = clazz.newInstance();

        Method main = clazz.getDeclaredMethod("main", String[].class);
        main.invoke(obj, (Object)new String[1]);

    }

}
复制代码

这段代码分为几块内容来实现功能,分别包括;

  1. 建立 ClassPool,它是一个基于HashMap实现的 CtClass 对象容器。
  2. 使用 CtClass,建立咱们的类信息,也就是类的路径和名称。
  3. 接下来就是给类添加方法。包括;方法的属性、类型、名称、入参、出参和方法体的内容。
  4. 在方法建立好后还须要建立一个空的构造函数,每个类都会在编译后生成这样一个构造函数。
  5. 当方法建立完成后,咱们使用 ctClass.writeFile() 进行输出方法的内容信息。也就能够看到经过咱们使用 Javassist 生成类的样子。
  6. 最后就是咱们的反射调用 main 方法,测试输出结果。

5、测试结果

当咱们执行测试的时候会输出类信息到工程文件夹下,同时会输出咱们的测试结果;

1. 使用Javassist生成的类

使用Javassist生成的类,在工程文件夹下
使用Javassist生成的类,在工程文件夹下

2. 输出的测试结果

javassist hi helloworld by 小傅哥(bugstack.cn)

Process finished with exit code 0
复制代码

6、总结

  • 关于 Javassist 的使用在完整的且强大的 API 下,确实仍是蛮容易使用的。而且代码的使用上并非很难理解。
  • 后续会陆续推出字节码编程的案例文章,逐步完善这部分技术知识栈的内容。最终尝试使用这样的技术知识完成一个案例级别的质量检测系统。也欢迎喜欢此类内容的小伙伴跟进学习。
  • 后续的文章可能在专栏类的文章里,文章内容上会短一点。尽量在一篇文章中描述清楚一个详尽的知识点,也方便后续整理成 PDF 书籍,方便学习使用。

bugstack虫洞栈
沉淀、分享、成长,让本身和他人都能有所收获!
做者小傅哥多年从事一线互联网Java开发,从19年开始编写工做和学习历程的技术汇总,旨在为你们提供一个较清晰详细的核心技能学习文档。若是本文能为您提供帮助,请给予支持(关注、点赞、分享)!
相关文章
相关标签/搜索