【开发者成长】如果你只写CRUD,那这种技术栈你永远碰不到

转自【阿里云云栖号】

一、前言

写这篇文章的时候我在想可能大部分程序员包括你我,常常都在忙于业务开发或奔波在日常维护与修复BUG的路上,当不能从中吸取技术营养与改变现状后,就像一台恒定运行的机器,逃不出限定宇宙速度的一个圈里。可能你也会有自己的难处,平时加班太晚没有时间学习、周末家里琐事太多没有精力投入,放假计划太满没有空闲安排。总之,学习就会被搁置。而当一年年的过去后,当自己的年龄与能力不成匹配后又会后悔没有给多投入一些时间学习成长。

尤其是一线编码的技术人,除了我们所能看到的在技术框架里(SSM)开发的业务代码,你是否有遇到过学习瓶颈,而这种瓶颈又是你自己不知道自己不会什么,就像下面这些技术列表里,你有了解多少;

  1. javaagent
  2. asm
  3. jvmti
  4. javaassit
  5. netty
  6. 算法,搜索引擎
  7. cglib
  8. 混沌工程
  9. 中间件开发
  10. 高级测试;压力测试、链路测试、流量回放、流量染色
  11. 故障系列;突袭、重现、演练
  12. 分布式的数据一致性
  13. 文件操作;es、hive
  14. 注册中心;zookeeper、Eureka
  15. 互联网工程开发技术栈;spring、mybaits、网关、rpc(thrift, grpc, dubbo)、mq、缓存redis、分库分表、定时任务、分布式事物、限流、熔断、降级
  16. 数据库binlog解析
  17. 架构设计;DDD领域驱动设计、微服务、服务治理
  18. 容器;k8s, docker
  19. 分布式存储;ceph
  20. 服务istio
  21. 压测 jmter
  22. Jenkins-部署java代码项目 + ansible
  23. 全链路监控,分布式追踪
  24. 语音识别、语音合成
  25. lvs nginx haproxy iptables
  26. hadoop mapreduce hive sqoop hbase flink kylin druid

好,现在开始就搞一下其中的一个技术点 ASM,看看它的真面目。那么学习之前先看下他有什么用途;

1.类的代理,如cglib

2.混沌工程

3.反向工程

4.结合 javaagent 做到非入侵式监控,方法耗时、日志、机器性能等等

5.破解

【开发者成长】如果你只写CRUD,那这种技术栈你永远碰不到

为了更方便的学习ASM,我将《ASM4使用手册》以及一些技术点整理成在线文档,可以随时方便查阅(asm.itstack.org);

【开发者成长】如果你只写CRUD,那这种技术栈你永远碰不到

二、环境配置

1.jdk 1.8

2.idea 2019.3.1

3.asm-commons 6.2.1

三、工程信息

【开发者成长】如果你只写CRUD,那这种技术栈你永远碰不到
  • itstack-demo-asm-01:字节码编程,HelloWorld
  • itstack-demo-asm-02:字节码编程,两数之和
  • itstack-demo-asm-03:字节码增强,输出入参
  • itstack-demo-asm-04:字节码增强,调用外部方法

四、HelloWorld还可以这样写

你所熟悉的HelloWorld是不这样;

【开发者成长】如果你只写CRUD,那这种技术栈你永远碰不到

那你有尝试反解析下他的类查看下汇编指令吗,javap -c HelloWorld

【开发者成长】如果你只写CRUD,那这种技术栈你永远碰不到
【开发者成长】如果你只写CRUD,那这种技术栈你永远碰不到

如果你还感兴趣其他指令,可以参考这个字节码指令表:Go!

好! 以上呢,是我很熟悉的一段代码了,那么现在我们把这段代码用ASM方式写出来;

import org.objectweb.asm.ClassWriter;import org.objectweb.asm.MethodVisitor;import org.objectweb.asm.Opcodes;

private static byte[] generate() {

ClassWriter classWriter = new ClassWriter(0);// 定义对象头;版本号、修饰符、全类名、签名、父类、实现的接口classWriter.visit(Opcodes.V1_7, Opcodes.ACC_PUBLIC, "org/itstack/demo/asm/AsmHelloWorld", null, "java/lang/Object", null);// 添加方法;修饰符、方法名、描述符、签名、异常MethodVisitor methodVisitor = classWriter.visitMethod(Opcodes.ACC_PUBLIC + Opcodes.ACC_STATIC, "main", "([Ljava/lang/String;)V", null, null);// 执行指令;获取静态属性methodVisitor.visitFieldInsn(Opcodes.GETSTATIC, "java/lang/System", "out", "Ljava/io/PrintStream;");// 加载常量 load constantmethodVisitor.visitLdcInsn("Hello World");// 调用方法methodVisitor.visitMethodInsn(Opcodes.INVOKEVIRTUAL, "java/io/PrintStream", "println", "(Ljava/lang/String;)V", false);// 返回methodVisitor.visitInsn(Opcodes.RETURN);// 设置操作数栈的深度和局部变量的大小methodVisitor.visitMaxs(2, 1);// 方法结束methodVisitor.visitEnd();// 类完成classWriter.visitEnd();// 生成字节数组return classWriter.toByteArray();

}

以上的代码,“小朋友,你是否有很多问好???^1024”,其实以上的代码都是来自于 ASM 框架的代码,这里面所有的操作与我们使用使用 javap -c XXX 所反解析出的字节码是一样的,只不过是反过来使用指令来编写代码。

1.定义一个类的生成 ClassWriter

2.设定版本、修饰符、全类名、签名、父类、实现的接口,其实也就是那句;public class HelloWorld

3.接下来开始创建方法,方法同样需要设定;修饰符、方法名、描述符等。这里面有几个固定标识;

【开发者成长】如果你只写CRUD,那这种技术栈你永远碰不到

4.执行指令;获取静态属性。主要是获得 System.out

5.加载常量 load constant,输出我们的HelloWorld methodVisitor.visitLdcInsn("Hello World");

6.最后是调用输出方法并设置空返回,同时在结尾要设置操作数栈的深度和局部变量的大小

这样输出一个 HelloWorld 是不还是蛮有意思的,虽然你可能觉得这编码起来实在太难了吧,也非常难理解。首先如果你看过我的专栏,用《Java写一个Jvm虚拟机》,那么你可能会感受到这里面的知识点还是不那么陌生的。另外这里的编写,ASM还提供了插件,可以方便的让你开发字节码。接下来就介绍一下使用方式。

五、有插件的帮助字节码开发也不是很难

对于新人来说如果用字节码增强开发一些东西确实挺难,尤其是一些复杂的代码块使用字节码指令操作还是很有难度的。那么,其实也是有简单办法就是使用 ASM 插件。这个插件可以很轻松的让你看到一段代码的指令码以及如何用ASM去开发。

1.安装插件(ASM Bytecode Outline)

【开发者成长】如果你只写CRUD,那这种技术栈你永远碰不到

2.测试使用

【开发者成长】如果你只写CRUD,那这种技术栈你永远碰不到

是不是看到有插件的帮助下,心里有所激动了,至少写这样的东西有了抓手。这样你就可以很方便的去操作一些增强字节码的功能了。

六、用字节码写出一个两数之和计算

好!有了上面的插件,也有了一些基础知识的了解。那么我们开发一个计算两数之和的方法,之后运行计算结果。

这是我们的目标

使用字节码编程方式实现

  • 上面有两个括号 {},第一个是用于生成一个空的构造函数
  • 接下来的指令就比较简单了,首先使用 ILOAD 进行数值的两次压栈也就是弄到操作数栈里去操作,接下来开始执行 IADD,将两数相加。
  • 最后返回结果 IRETURN ,注意是返回的 I 类型。到此这段方法快就实现完成了。反编译后如下;

这段执行操作和我们在使用 java 的反射操作一样,也是比较容易的。此时我们是调用了新的字节码类,同时还将字节码输出方便我们查看生成的 class 类。

七、在原有方法上字节码增强监控耗时

到这我们基本了解到通过字节码编程,可以动态的生成一个类。但是在实际使用的过程中,我们可能有的时候是需要修改一个原有的方法,在开始和结尾添加一些代码,来监控这个方法的耗时。这也是非侵入式监控的最基本模型。

整体的代码块有点大,我们可以分为块来看,如下;

ClassReader cr = new ClassReader(MyMethod.class.getName()); 读取原有类,也是字节码增强的开始ClassVisitor cv = new ProfilingClassAdapter(cw, MyMethod.class.getSimpleName()); 开始增强字节码onMethodEnter,onMethodExit,在方法进入和方法退出时添加耗时执行的代码。

测试结果:

直接运行TestMonitor.java;

八、字节码控制打印方法的入参

那么除了可以监控方法的执行耗时,还可以将方法的入参信息进行打印出来。这样就可以在一些异常情况下,看到日志信息。

其他代码与上面相同,这里只列一下修改的地方

从这里可以看到,在方法进入时候使用指令码 GETSTATIC,获取输出对象类

  • 接下来使用 ALOAD,从局部变量1中装载引用类型值入栈
  • 最后输出入参信息
  • 测试结果:

直接运行TestMonitor.java;

九、用字节码增强调用外部方法好!那么执行到这,我们可以想到如果只是将一些信息打印到控制台还是没有办法做业务的,我们需要在这个时候将各种属性信息调用外部的类,进行发送到服务端。比如使用;mq、日志等。

定义日志信息输出类

十、总结

  • 高级编程技术的内容还不止于此,不要只为了一时的功能实现,而放弃深挖深究的机会。也许就是你不断的增强拓展个人的知识技能,才让你越来越与众不同。
  • ASM 这种字节码编程的应用是非常广的,但可能确实平时看不到的,因为他都是与其他框架结合一起作为支撑服务使用。像这样的技术还有很多,比如 javaassit、netty等等。
  • 对于真的要学习一样技术时,不要只看爽文,但爽文也确实给了你敲门砖。当你要彻底的掌握某个知识的时候,最重要的是成体系的学习!压榨自己的时间,做有意义的事,是3-7年开发人员最正确的事
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 200,045评论 5 468
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 84,114评论 2 377
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 147,120评论 0 332
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 53,902评论 1 272
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 62,828评论 5 360
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,132评论 1 277
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 37,590评论 3 390
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,258评论 0 254
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 40,408评论 1 294
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,335评论 2 317
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,385评论 1 329
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,068评论 3 315
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 38,660评论 3 303
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,747评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 30,967评论 1 255
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 42,406评论 2 346
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 41,970评论 2 341

推荐阅读更多精彩内容

  • 理解AOP 之前几篇文章我们详细介绍了AOP的几种技术方案,由于AOP技术复杂多样,实际需求也不尽相同,那么我们应...
    wanderingGuy阅读 4,996评论 0 15
  • 前言 在上篇文章中,我们以AspectJ为引子介绍了AOP及其设计思想,传送门Android AspectJ详解,...
    wanderingGuy阅读 9,028评论 4 10
  • 前言 很早之前就写过面向切面的编程思想,主要学习了AOP的思想(参考:AOP简介)以及使用 AspectJ 实现简...
    Whyn阅读 10,743评论 4 40
  • ASM介绍 ASM是一个字节码操作库,它可以直接修改已经存在的class文件或者生成class文件。ASM提供了一...
    唠嗑008阅读 8,689评论 7 38
  • 如果说非要推荐一款满足学生党和化妆小白的口红品牌,我一定会毫不犹豫的推荐wet n wild(湿又野)。先不说这个...
    仙女霸霸_cae4阅读 199评论 0 0