背景
写Java的同学来写Go就特别喜欢将两者进行对比,就经常看到技术群里讨论,比如Go能不能实现Java那样的AOP啊?Go写个事务好麻烦啊,有没有Spring那样的@Transactional注解啊?
遇到这样的问题我通常会回复:没有、实现不了、再见。
直到看了《Go语言底层原理剖析》这本书,开始了一轮认真地探索。
Java是如何实现AOP的
AOP概念第一次是在若干年前学Java时看的一本书《Spring实战》中看到的,它指的是一种面向切面编程的思想。注意它只是一种思想,具体怎么实现,你看着办。
AOP能在你代码的前后织入代码,这就能做很多有意思的事情了,比如统一的日志打印、监控埋点,事务的开关,缓存等等。
可以分享一个我当年学习AOP时的笔记片段:
在Java中的实现方式可以是JDK动态代理和字节码增强技术。
JDK动态代理是在运行时动态地生成了一个代理类,JVM通过加载这个代理类再实例化来实现AOP的能力。
字节码增强技术可以多唠叨两句,当年学Java时第一章就说Java的特点是「一次编译,到处运行」。
但当我们真正在工作中这个特性用处大吗?好像并不大,生产中都使用了同一种服务器,只编译了一次,也都只在这个系统运行。做到一次编译,到处运行的技术底座是JVM,JVM可以加载字节码并运行,这个字节码是平台无关的一种二进制中间码。
似乎这个设定带来了一些其他的好处。在JVM加载字节码时,字节码有一次被修改的机会,但这个字节码的修改比较复杂,好在有现成的库可用,如ASM、Javassist等。
至于像ASM这样的库是如何修改字节码的,我还真就去问了Alibaba Dragonwell的一位朋友,他回答ASM是基于Java字节码规范所做的「硬改」,但做了一些抽象,总体来说还是比较枯燥的。
由于这不是本文重点,所以只是提一下,如果想更详细地了解可自行网上搜索。
Go能否实现AOP?
之前用「扁鹊三连」的方式回复Go不能实现AOP的基础其实就是我对Java实现AOP的思考,因为Go没有虚拟机一说,也没有中间码