作者:小傅哥

博客:https://bugstack.cn

沉淀、分享、成长,让自己和他人都能有所收获!

目录

@

一、前言

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

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

另外两个框架都是有强大的 API,操作使用上更加容易控制。虽然对对比上会比 ASM 性能差一些,但不是说性能完全不好。同样在一些监控场景中也用的非常多。如果你细心可以在你的工程 jar 包搜索一下。

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

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

好!,现在开始第一个Helloworld案例。相关源码可以通过关注 公众号:bugstack虫洞栈 获取

二、开发环境

  1. JDK 1.8.0
  2. javassist 3.12.1.GA
  1. <dependency>
  2. <groupId>javassist</groupId>
  3. <artifactId>javassist</artifactId>
  4. <version>3.12.1.GA</version>
  5. <type>jar</type>
  6. </dependency>

三、案例目标

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

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

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

四、技术实现

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

javassist Helloworld

  1. /**
  2. * 公众号:bugstack虫洞栈
  3. * 博客栈:https://bugstack.cn - 沉淀、分享、成长,让自己和他人都能有所收获!
  4. * 本专栏是小傅哥多年从事一线互联网Java开发的学习历程技术汇总,旨在为大家提供一个清晰详细的学习教程。如果能为您提供帮助,请给予支持(关注、点赞、分享)!
  5. */
  6. public class GenerateClazzMethod {
  7. public static void main(String[] args) throws IOException, CannotCompileException, NotFoundException, IllegalAccessException, InstantiationException, NoSuchMethodException, InvocationTargetException {
  8. ClassPool pool = ClassPool.getDefault();
  9. // 创建类 classname:创建类路径和名称
  10. CtClass ctClass = pool.makeClass("org.itstack.demo.javassist.HelloWorld");
  11. // 添加方法
  12. CtMethod mainMethod = new CtMethod(CtClass.voidType, "main", new CtClass[]{pool.get(String[].class.getName())}, ctClass);
  13. mainMethod.setModifiers(Modifier.PUBLIC + Modifier.STATIC);
  14. mainMethod.setBody("{System.out.println(\"javassist hi helloworld by 小傅哥(bugstack.cn)\");}");
  15. ctClass.addMethod(mainMethod);
  16. // 创建无参数构造方法
  17. CtConstructor ctConstructor = new CtConstructor(new CtClass[]{}, ctClass);
  18. ctConstructor.setBody("{}");
  19. ctClass.addConstructor(ctConstructor);
  20. // 输出类内容
  21. ctClass.writeFile();
  22. // 测试调用
  23. Class clazz = ctClass.toClass();
  24. Object obj = clazz.newInstance();
  25. Method main = clazz.getDeclaredMethod("main", String[].class);
  26. main.invoke(obj, (Object)new String[1]);
  27. }
  28. }

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

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

五、测试结果

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

1. 使用Javassist生成的类

2. 输出的测试结果

  1. javassist hi helloworld by 小傅哥(bugstack.cn)
  2. Process finished with exit code 0

六、总结

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

字节码编程,Javassist篇一《基于javassist的第一个案例helloworld》的更多相关文章

  1. 字节码编程,Javassist篇三《使用Javassist在运行时重新加载类「替换原方法输出不一样的结果」》

    作者:小傅哥 博客:https://bugstack.cn 沉淀.分享.成长,让自己和他人都能有所收获! 一.前言 通过前面两篇 javassist 的基本内容,大体介绍了:类池(ClassPool) ...

  2. 字节码编程,Javassist篇二《定义属性以及创建方法时多种入参和出参类型的使用》

    作者:小傅哥 博客:https://bugstack.cn 沉淀.分享.成长,让自己和他人都能有所收获! 一.前言 在上一篇 Helloworld 中,我们初步尝试使用了 Javassist字节编程的 ...

  3. 字节码编程,Byte-buddy篇一《基于Byte Buddy语法创建的第一个HelloWorld》

    作者:小傅哥 博客:https://bugstack.cn 沉淀.分享.成长,让自己和他人都能有所收获! 一.前言 相对于小傅哥之前编写的字节码编程: ASM.Javassist 系列,Byte Bu ...

  4. 开发 IDEA Plugin 引入探针,基于字节码插桩获取执行SQL

    作者:小傅哥 博客:https://bugstack.cn 沉淀.分享.成长,让自己和他人都能有所收获! 一.前言 片面了! 一月三舟,托尔斯泰说:"多么伟大的作家,也不过就是在书写自己的片 ...

  5. 方案设计:基于IDEA插件开发和字节码插桩技术,实现研发交付质量自动分析

    作者:小傅哥 博客:https://bugstack.cn 沉淀.分享.成长,让自己和他人都能有所收获! 一.前言 如何保证代码质量? 业务提需求,产品定方案,研发做实现,测试验流程.四种角色的相互配 ...

  6. Java基础篇(JVM)——字节码详解

    这是Java基础篇(JVM)的第一篇文章,本来想先说说Java类加载机制的,后来想想,JVM的作用是加载编译器编译好的字节码,并解释成机器码,那么首先应该了解字节码,然后再谈加载字节码的类加载机制似乎 ...

  7. 第32篇-解析interfacevirtual字节码指令

    在前面介绍invokevirtual指令时,如果判断出ConstantPoolCacheEntry中的_indices字段的_f2属性的值为空,则认为调用的目标方法没有连接,也就是没有向Constan ...

  8. 第34篇-解析invokeinterface字节码指令

    与invokevirtual指令类似,当没有对目标方法进行解析时,需要调用LinkResolver::resolve_invoke()函数进行解析,这个函数会调用其它一些函数完成方法的解析,如下图所示 ...

  9. 谁还没遇上过NoClassDefFoundError咋地——浅谈字节码生成与热部署

    谁还没遇上过NoClassDefFoundError咋地--浅谈字节码生成与热部署 前言 在Java程序员的世界里,NoClassDefFoundError是一类相当令人厌恶的错误,因为这类错误通常非 ...

随机推荐

  1. Threejs从入门到入门

    前言threejs官网:https://threejs.org/ github各个版本:https://github.com/mrdoob/three.js/tags 版本更迭很快,我用的时候还是r9 ...

  2. 计算机视觉中的对象检测,Python用几段代码就能实现

    目前计算机视觉(CV)与自然语言处理(NLP)及语音识别并列为人工智能三大热点方向,而计算机视觉中的对象检测(objectdetection)应用非常广泛,比如自动驾驶.视频监控.工业质检.医疗诊断等 ...

  3. Unity 游戏框架搭建 2019 (二十九) 方法所在类命名问题诞生的原因

    我们在整理阶段解决了一些意外的问题.但是这些问题仅仅只是被解决而已,我们并没有去思考过这些问题是为什么产生的?以及在以后我们如何去避免这些问题的产生? 方法所在类的命名问题,最后我们通过方法分类解决了 ...

  4. [Abp vNext 入坑分享] - 3.简单的用户模块功能开发

    一.简要说明 本篇文章开始进行业务模块的开发模拟,借助user模块来进行业务开发,主要是用户相关的基础操作.主要是先使用Users来体验整个开发的流程.主要是先把一个基础流程跑顺利,在这里我并不会过于 ...

  5. 01、Hibernate安装配置

    1.查看你的Eclipse的版本:Help | About Eclipse       Version: 2018-12 (4.10.0) 2.HibernateTools的下载地址为:http:// ...

  6. tensorflow1.0 lstm学习曲线

    import tensorflow as tf import numpy as np import matplotlib.pyplot as plt BATCH_START = 0 TIME_STEP ...

  7. .NET Core下的开源分布式任务调度系统ScheduleMaster-v2.0低调发布

    从1月份首次公开介绍这个项目到现在也快4个月了,期间做了一些修修补补整体没什么大的改动.2.0算是发布之后第一个大的版本更新,带来了许多新功能新特性,也修复了一些已知的bug,在此感谢在博客.Issu ...

  8. ambarella H2平台fpga捕捉卡驱动案例

    公司最近开发的一款产品用到了ambarella H2平台的一款Soc,众所周知ambarella的H2系列的Soc编码能力很强,最高可达4kp60,捕捉上没有用ambarella开发板推荐的几个捕捉卡 ...

  9. 当git上只做文件大小写重命名的修改时,如何躲坑

    一. 提交时 假设修改ABC.java为Abc.java. 1.1 如果使用git命令进行仅涉及大小写的重命名 1.1.1 设置git库为大小写敏感(不建议) $ git config core.ig ...

  10. [Qt] QProcess::startDetached() 避免弹窗,或者窗口一闪而过

    主动宣告setProcessState(QProcess::NotRunning)   或者在堆上new一个QProcess.     出处:  https://stackoverflow.com/q ...