做者:Java架构的傲慢与偏见 原文地址:www.toutiao.com/a6695345484485100044java
众所周知,一旦提到AOP,相信你们都是条件反射的想到JDK代理和CGLib代理,没错,这两个代理都是在运行时内存中临时生成代理类,故而又称做运行时加强——动态代理。世间万物都不是绝对的,既然有动态代理,那么,是否有想过:是否是存在静态代理呢?面试
其实,除了运行时织入切面的方式外,咱们还有一种途径进行切面织入,它能够在类加载期经过字节码转换,进而将目标织入切入点(目标类),这种方式就是LTW,即静态代理(静待代理也被称做编译时加强,后面会有相关代码样例)。后端
LTW在Java5的时候就被引入了,想要了解其原理,先要了解一个知识——Instrument包。缓存
JDK5.0时引入了此包,目的就是为了能对JVM底层组建进行访问。如何访问?其实说来我的以为还挺麻烦的,就是须要经过JVM的启动参数**-javaagent**在启动时获取JVM内部组件的引用。参数格式以下:微信
-javaagent:[=options]网络
此处先卖个关子,不急着解释参数中的jarpath和options,后面的运行代码及结果的样例中会进行针对使用红框标记说明,效果更好。多线程
那么,它和AOP有和关系呢?架构
由于它在JVM启动时会装配并应用ClassTransformer,对类字节码进行转换,进而实现AOP的功能。eclipse
下面说一下instrument包下的两个重要接口:分布式
它是Class文件转换器接口,这个接口有且仅有一个方法,如图所示:
注意:transform方法会有一个返回值,类型是byte[],表示转换后的字节码,可是若是返回为空,则表示不进行节码转换处理,千万不要看成是把原先类的字节码清空。
这个接口提供了不少方法,咱们主要注意一个方法便可,即:addTransformer方法,它的做用就是把一些ClassFileTransformer注册到JVM内部,接口如图所示:
具体工做原理是这样的:
① ClassFileTransformer实例注册到JVM以后,JVM在加载Class文件时,就会先调用ClassFileTransformer的transform()方法进行字节码转换;
② 若注册了多个ClassFileTransformer实例,则按照注册时的顺序进行一次调用。
这样也就实现了从JVM层面截获字节码,进而织入操做者本身但愿添加的逻辑,即实现AOP效果。
说了这么多,来点干货,下面用代码给你们演示一下如何向JVM中注册转换器实现AOP的。为了方便你们阅读,重要的说明笔者已经写在代码的注释上或者图片空白处,你们注意查看。
注意,这里再强调下,代码中的return null;并非将加载类的字节码置空。
为何要实现代理类内,由于不是动态代理呀。。。
到此为止,咱们的Demo算是完成了,先来看一下运行的结果:
你们看到执行结果的截图中,cmd界面下运行javaagent参数时指定了一个myTransformer.jar,这个jar是咱们本身须要打出来的,能够直接使用eclipse具体步骤以下图所示,注意图中说明:
你们能够看到,其实使用此类代理并无动态代理方便,甚至转换器可能会对JVM全部类都产生影响,操做起来更新相对麻烦,实际生产部署时会有不少不便。
可是,写这些是为了让你们更好、更多的去了解AOP,咱们所熟知的AOP其实还有不少东西有待咱们自身去学习和发现,其实Spring在"操做麻烦"这方面仍是作了很多事的,提供了一些xml的配置化管理(此处就再也不说了,由于感受一说又是一大长篇,有兴趣的你们能够本身去看看,多了解写东西总没有坏处),不少状况下已经不须要再配置javaagent参数了。
最后提一句,若是在面试中提到了这些,相信面试官也会有加分吧。
热门内容:
六、开源的13个Spring Boot 优秀学习项目!超53K星,一网打尽!