关山难越,谁悲失路之人;萍水相逢,尽是他乡之客。
百度360必应搜狗淘宝本站头条
当前位置:网站首页 > 编程教程 > 技术文章 > 正文

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

guanshanw 2023-09-17 17:03 38 浏览 0 评论

作者:小傅哥
博客: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
    <dependency>
    <groupId>javassist</groupId>
    <artifactId>javassist</artifactId>
    <version>3.12.1.GA</version>
    <type>jar</type>
    </dependency>

三、案例目标

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

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

    public HelloWorld() {
    }
}

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

四、技术实现

其实输出一个 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 方法,测试输出结果。

五、测试结果

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

1. 使用Javassist生成的类

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

2. 输出的测试结果

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

Process finished with exit code 0

六、总结

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

相关推荐

七条简单命令让您玩转Git
七条简单命令让您玩转Git

凭借着出色的协作能力、快速部署效果与代码构建辅助作用,Git已经得到越来越多企业用户的青睐。除了用于开发商业及消费级应用之外,众多科学及政府机构也开始尝试使用这...

2023-10-07 12:14 guanshanw

基本完整的关于Git分支branch的操作
基本完整的关于Git分支branch的操作

Git使用背景项目中要用到dev或者其他分支开发完代码,需要将该分支合并到master的需求操作步骤下面以dev名称为lex为分支名为例来操作一遍客户端操作:...

2023-10-07 12:14 guanshanw

Git 进阶(合并与变基)
Git 进阶(合并与变基)

在Git中整合来自不同分支的修改主要有两种方法:合并(merge)以及变基(rebase)合并(merge)merge流程图merge的原理是找到这两个分...

2023-10-07 12:13 guanshanw

Git学习笔记 003 Git进阶功能 part5 合并(第一部分)

合并(merge)是很常用的操作。尤其是一个庞大的很多人参与开发的企业级应用。一般会设定一个主分支,和多个副分支。在副分支开发完成后,合并到主分支中。始终保持主分支是一个完整的,稳定的最新状态的分支。...

非标题党,三张图帮你理解git merge和git rebase的区别
非标题党,三张图帮你理解git merge和git rebase的区别

初始场景:基于正常的开发分支修改几个小bug,然后在合并到开发分支上。gitmergegitcheckoutfeaturegitmergeho...

2023-10-07 12:13 guanshanw

git 初次使用(01)
git 初次使用(01)

先从github上克隆代码下来:使用vscode克隆代码如下图,填写上github仓库地址:vscode有时候克隆代码速度比较慢,可以用命令行方式克隆gitc...

2023-10-07 12:12 guanshanw

Git 远程操作

4.Git远程操作命令说明gitremote远程版本库操作gitfetch从远程获取版本库gitpull下载远程代码并合并gitpush上传远程代码并合并4.1远程版本库操作gitre...

Git常用命令-总结
Git常用命令-总结

创建git用户$gitconfig--globaluser.name"YourName"$gitconfig--globaluser.em...

2023-10-07 12:12 guanshanw

git中删除从别人clone下来项目的git信息,并修改为自己的分支

如果你从别人的Git存储库中克隆了一个项目,并想要删除与该存储库相关的Git信息,并将其修改为你自己的分支,则可以执行以下步骤:使用gitclone命令克隆存储库:gitclone<u...

git系列-回滚和放弃本地修改

回滚历史提交就是reset的功能。这种情况是已经提交远程仓库,需要回滚到之前的提交。gitreset--hardcommitId//注:强制提交后,当前版本后面的提交版本将会删掉!gi...

GIT使用小技巧大全
GIT使用小技巧大全

在大型软件工程的开发过程中,版本控制是无法绕过去的;目前来说,最火的版本控制软件就是GIT了。早两年SVN比较火,不过被大神linus喷了几次后,就日落西山了,...

2023-10-07 12:11 guanshanw

git相关命令-上
git相关命令-上

这些命令都是看了文档后,个人觉得比较有用的一些,展示给大家。回到远程仓库的状态抛弃本地所有的修改,回到远程仓库的状态。gitfetch--all&...

2023-10-07 12:10 guanshanw

Git命令行接口:掌握Git的必备技能
Git命令行接口:掌握Git的必备技能

Git是一款强大的分布式版本控制工具,它支持命令行界面操作。熟练掌握Git命令行接口,是开发者使用Git的必备技能之一。在这篇文章中,我们将介绍Git命令行接口...

2023-10-07 12:10 guanshanw

Git命令详解
Git命令详解

相信各位小伙伴们应该都对git有一些了解,毕竟作为代码管理的神器,就算不是IT行业的小伙伴肯定也或多或少的听说过一些。今天就来和小伙伴们分享一下自己总结的常用命...

2023-10-07 12:10 guanshanw

工作7年收集到的git命令
工作7年收集到的git命令

概念git中的术语解释:仓库也叫版本库(repository)stage:暂存区,add后会存到暂存区,commit后提交到版本库git安装linux...

2023-10-07 12:10 guanshanw

取消回复欢迎 发表评论: