news 2026/8/18 20:44:31

用大白话从宏观的角度聊一聊asm技术和class字节码文件和动态代理的关系,绝对通俗易懂

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
用大白话从宏观的角度聊一聊asm技术和class字节码文件和动态代理的关系,绝对通俗易懂

今天用绝对通俗易懂的大白话来聊一聊asm技术和class字节码文件和动态代理的关系。我之前有几篇文章,写的是动态代理和AOP的具体落地的实现,感兴趣的可以看一下

Java中的代理模式——静态代理以及分析静态代理的缺点

Java中动态代理的两种方式JDK动态代理和cglib动态代理以及区别

Spring中的AOP以及切入点表达式和各种通知

SpringAOP的注解形式

今天这一篇是从宏观的角度来对asm,动态代理,aop这些技术有个整体上的把握。请放心,和我以前的文章一样,整篇文章下来都是通俗易懂的大白话,不会有华丽难懂的辞藻。

我最近开通了几个专栏,里边有更多用大白话讲的干货,全部都是我自己对一些知识点的理解,绝对干货,不拖泥带水,感兴趣的小伙伴可以去看看,专栏持续更新中,后期会持续更新更多的大白话干货

通俗易懂的大白话干货系列

带你玩转实际工作中的Jenkins系列

ok进入今天的正题吧

一、class字节码的生成有哪些途径?

大家都知道,在Java中,你想调用一个实例方法,首先必须得有对象,有对象的前提是必须有对应的class字节码文件,并且得通过类加载器把它加载到内存里(jdk1.7之前对应的是加载到永久代,jdk1.8之后是加载到元空间)

所以大家发现了没有,这个class字节码是一切一切的基础,只有有了它,后续的工作才能进行下去

那ok,咱们想想,怎么才能把这个class字节码搞出来呢?

其中有一种途径大家肯定都知道,而且天天在用,那就是咱们平常新建一个Java类,然后通过编译就能得到class字节码了。

刚才说了,这种方法只是其中的一种,那还有没有其他的方法能得到class字节码呢?

答案就是咱们接下来要说的asm。

首先大家来想个问题啊,咱们最终目的是不是 就是为了把class字节码搞出来就行了,不管你用什么办法,只要按照jvm规范里对class字节码的格式要求,你只要能搞出来就行了。

那对class字节码有稍微了解的都应该知道,class字节码里无非就是魔数(CAFEBABE)、主版本、次版本、常量池容量、常量池、访问修饰符、接口、字段、方法等等等等这些东西组成的,而且jvm对class字节码的每一部分的数据格式都有非常非常严格的要求(字节码文件里的内容是非常紧凑的,没有一点浪费的空间,每一部分的数据都是严格按要求来的)。

所以,只要你对class的字节码的各个部分有足够的了解,理论上你甚至可以手动拼接组装出来一个class字节码。到这里,是不是对上边说的通过写java文件编译得到字节码只是得到class字节码 其中的一种办法,不难理解了吧。更直白的大白话就是条条大路通罗马,通过常规的手段,规规矩矩,按部就班的通过写 java类,然后通过编译来生成class字节码,这种只是搞到class字节码文件最普通最常见的一种办法而已。

不过话又说回来啊,虽然理论上来说你是可以手动组装出class字节码的,但这难度非常非常大,刚才说了,如果非得这么做的话,你得对class字节码的各个组成部分都了如指掌,你还得对二进制的一些知识非常熟练,总之非常难也非常麻烦。其实,意思就是说咱这些菜逼们,想打class字节码的主意,基本上没戏

咱不行,但是有大佬行啊。这些大佬们可没闲着,比如,java团队的大佬们就在JDK里提供了一套在运行时动态去操作生成class字节的功能,这就是咱们平时经常说的jdk的动态代理。

除了jdk内部提供的之外,还有第三方的jar包也提供了运行时动态去操作生成class字节码的功能,比如咱们经常聊到的cglib这个jar包,这就是咱们经常说的cglib的动态代理,它里边也提供了一套操作生成class字节码的API,这个API就是经常提到的ASM。

不管是jdk里提供的操作字节码的API,还是第三方cglib提供的操作字节码的API,你直接调用它封装好的一些方法就可以让你很方便的来组装或者嫁接并生成一个新的class字节码。比如ASM它里边有classWriter、classVisitor等等这些东西,可以让你很方便的去在运行时操作拼接生成class字节码。

二、关于动态代理的一些东西

动态代理的底层原理就是上边说的jdk内部或者cglib提供的操作字节码的API

大家都知道spring里的aop就是用动态代理做的,它底层靠的就是asm这玩意。

其实除了spring,其他的很多框架也都用了动态拼接生成字节码的这种技术,比如mybatis,你有没有发现,你用mybatis从来都只是写个mapper接口,写个xml文件,你从来没写过它的实现类,那为什么能完美的跑起来呢?你不觉得很神奇吗?或者很迷茫吗?

如果理解了我上边讲的这些,也就不觉得神奇和迷茫了

通过刚才讲的,你仔细想想啊,你通过asm都能随心所欲的去控制、去拼装任意你想要的class字节码了,那里边的内容还不是你想怎么玩就怎么玩啊。

有了asm这玩意后,那框架用它来在运行期间动态的拼出一个代理类的字节码,那不是分分钟的事吗?而且你可以随意控制这个代理类的class字节码里的内容。

所以,你猜,动态代理用asm来动态生成字节码的时候,它都做了啥?

它在手动拼接字节码的时候,肯定是在字节码里,把切面增强的动作和目标动作做了结合啊,而且具体的想怎么结合不是你说了算吗?你可以把增强的动作放在目标动作之前,这就是aop里的前置通知。你可以把增强的动作放在目标方法之后,这就是aop里的后置通知,等等等等。aop里还有很多通知,你都可以随心所欲的去实现。有了字节码后,再利用反射就能生成对象。

当然,今天这里只是从宏观上,大体的来把握一下asm、动态代理、aop这些东西,今天不会去说具体的源码,还有实现,今天着重讲的是它的思想。动态代理,aop具体的代码实现和实操,在我之前的文章里已经讲过了,感兴趣的可以去看看

三、关于方法区的一些东西

知道了这些后,再来看一些关于方法区的一些东西。

关于jvm方法区的一些理解,我之前的一篇文章写过了,也是通俗易懂的大白话写的,感兴趣也可以翻看一下 :大白话讲清楚JVM里的方法区、永久代以及元空间

之前虽然写过,但是我觉得有些东西还是有必要补充一下,所以这里就再来简单的聊一聊。

为什么jdk1.8之后完全去除了永久代,把方法区的实现换成了元空间?而且元空间使用的内存不再是jvm里和堆内存连续的那一块内存了,而是改成使用操作系统的直接内存。

我理解的其中一个原因就是,改成元空间并且使用直接内存,可以一定程度上避免方法区内存溢出。大家知道方法区(1.7之前的实现是永久代,1.8之后的实现是元空间)里放的基本上都是加载到内存里的各个类的class字节码内容,那有人肯定会问,我项目里用到的java类,生成的class字节码文件,在我写完项目后,不都确定了吗,能有多少个啊,怎么会多到把我的方法区的内存撑爆呢???

是,你写的java类是没多少,但是你别忘了,你的项目里肯定用了各种框架啊,刚才上边已经说了,这种框架它们都是会在运行期间动态的去给你拼接生成各种代理类的class字节码,你说动态拼接生成的这些class字节码,它不还是放在你方法区的内存里吗?所以你在用这些框架时,使用的不当的话,很可能会导致方法区溢出。

还有另外一种情况就是,某些场景下你可能会需要自己用动态代理来处理一些业务上的东西,如果你自己使用动态代理不当的时候,也会导致产生大量的字节码,这些大量在运行期间动态生成的class字节码都被放进了方法区,从而导致你的方法区内存溢出。

所以,jdk1.8之后方法区的实现改成了元空间,并且规定元空间使用的内存,不再是和堆空间连续的内存了,而换成了操作系统的直接内存。能用的空间大了,就意味着能往里放的东西变多了。所以在一定程度上避免了某些场景下class字节码太多放不下,而导致的的内存溢出

好了,今天大概就先聊这么多

欢迎关注,后续我会用大白话记录更多自己对一些技术的理解

我最近开通了几个专栏,里边有更多用大白话讲的干货,全部都是我自己对一些知识点的理解,绝对干货,不拖泥带水,感兴趣的小伙伴可以去看看,专栏持续更新中,后期会持续更新更多的大白话干货

通俗易懂的大白话干货系列

带你玩转实际工作中的Jenkins系列

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/7/14 16:20:21

wow-countdown倒计时操作说明

wow-countdown文件说明 项目地址:https://github.com/wow-iot3/wow_linux_eval本文件的功能主要用于处理定时器操作,主要涉及申请、释放、复位与置数、查询剩余时间、查询是否超时; 申请倒计时 CountDown_T* wow_cdown_new(void) {CountDown_…

作者头像 李华
网站建设 2026/7/14 16:20:25

【C++BFS算法】886. 可能的二分法

本文涉及的点 CBFS算法 LeetCod886. 可能的二分法 给定一组 n 人(编号为 1, 2, …, n), 我们想把每个人分进任意大小的两组。每个人都可能不喜欢其他人,那么他们不应该属于同一组。 给定整数 n 和数组 dislikes ,其…

作者头像 李华
网站建设 2026/7/14 16:20:24

mergerfs常见问题解答:解决90%用户遇到的存储难题

mergerfs常见问题解答:解决90%用户遇到的存储难题 【免费下载链接】mergerfs a featureful union filesystem 项目地址: https://gitcode.com/gh_mirrors/me/mergerfs mergerfs作为一款功能丰富的联合文件系统,能够帮助用户将多个存储设备整合为统…

作者头像 李华
网站建设 2026/7/14 16:20:23

AI Agent Skills:让 AI 助手拥有专业技能的开放生态系统

玄同 765 大语言模型 (LLM) 开发工程师 | 中国传媒大学 数字媒体技术(智能交互与游戏设计) CSDN 个人主页 | GitHub Follow 关于作者 深耕领域:大语言模型开发 / RAG 知识库 / AI Agent 落地 / 模型微调技术栈:Python | R…

作者头像 李华
网站建设 2026/7/14 16:20:22

终极WinBox主题定制指南:5分钟创建个性化Web窗口界面

终极WinBox主题定制指南:5分钟创建个性化Web窗口界面 【免费下载链接】winbox WinBox is a modern HTML5 window manager for the web: lightweight, outstanding performance, no dependencies, fully customizable, open source! 项目地址: https://gitcode.com…

作者头像 李华