背景是自从学习spring之后,AOP这个词几乎每天都在说,仿佛一切都是天经地义的。
特别是在springboot中,常见的@Before @After等内容,一般很少被说明,大多被认为是“这是aop的用法”。
要是有人能特别说明以下信息就好了。
@Before @After等这些实现,底边是aspectj。 官网地址: aspectJ官网aspectJ不是天然的而是spring framework的一部分,人们原本是独立的项目,通过优秀的方式实现了aop; 其他aop实现包括Jboss Aop。 spring framework虽然有自己的aop实现,但使用起来很难,很麻烦; 之后,spring官方将优秀的aspectj集成到spring framework源代码中。 从那以后,现在我们看到的spring framework的aop天然就像aspectj一样。
但我总是觉得不对劲,似乎脱离了彻底的理解,总是有点远。
所以今天一定要追究清楚,追求到底。
要引出具体问题,首先,要弄清基本事实。
aspectj不是spring框架的一部分。 这是一个独立的项目,用自己的方法实现了aop。
我不仅必须把它用于spring项目。比如说,我想把它用于我的简单控制台项目,我该怎么办?
很明显,网上的文章如果抄得很大,基本上都会告诉你什么是pointcut,什么是joinpoint等,然后搜索如何在springboot项目中使用。
这太简单了,太程序化了,已经麻木了,不值一提。
实施步骤经过了一些搜索、尝试,最初我的项目没有按预期执行,输出了指定的before after等内容。
经过更多的搜索和思考,想了解原理后,一切都化为泡影。
其中,通过网络找到了一些有用的文章,给了我很多启发。
howtocreateahelloworldwithintellijandaspectj
里面的步骤也很详细。
正式进入实施步骤1。 安装编译器并尝试使用aspectj将自己编写的pointcut等内容组织到相应的class文件中。 这是一个类似编译的过程。 正如编译c语言需要gcc编译器,而编译java需要javac编译器一样(当然也可能是其他编译器)。 需要下载aspectj并安装在电脑上。
下载和安装的步骤如下图所示。
下载地址:
33559 www.eclipse.org/AspectJ/downloads.PHP
到此为止,我们已经下载并在本地安装了aspectj。
2 .设置环境变量同样,虽然您在本地安装了jdk,但是不能在cmd命令行中直接使用javac xxx.java命令。 这是因为没有将javac可执行文件设置为path环境变量。
此aspect编译器也同样需要设置环境变量。
下图:
我只配置了CLASSPATH,只配置了c :AspectJ 1.9libAspectJ rt.jar,最终成功了。
3 .验证一下随便试了一下。 ajc xxx,不管是否报告那个是错误的,只要有反应就可以了。 表示此ajc编译器已成功配置并可用。
系统级环境配置到此结束。
现在将aspectj用于普通项目。
在IDEA中新建最简单的项目1 .新建空的maven项目
添加aspectj依赖关系
自由编写cxdxhd方法
添加AspectJ文件
我推测之所以能在这里添加这么多,是因为IDEA安装了aspectj插件。 让我们来看看。
上图的两个插件之一,应该不进行验证。
5 .在5. aspectj文件中添加pointcut等内容,此时可以自由地抄写在其他页面上。 例如
很明显,在这里我试图在调用cxdxhdn方法之前拦截。
如果可以监听,控制台将输出绿色文字的内容。
直接启动cxdxhdn方法,看看效果。
但事实并非如此。
不管怎么说clean、clean install、rebuild等,都是一样的。 不需要重试。
开始思考和解决aspectj为什么不生效的代码,居然有aspectj关键词,编译没有错误,已经很惊讶了。
jdk在编译时知道那个吗?
还是因为插件,他显示为蓝色?
编译为什么没有错呢?
既然报告没错,为什么又不生效呢?
在网上搜索资料查阅和思考,我恍然大悟。
原因也很简单,因为这个代码不应该由jdk编译。 因为jdk不知道遇到aspect该怎么办。 aspectj提供的编译功能,也就是ajc需要编译。
(但是,我不知道为什么会有aspect字,但jdk编译没有报告错误。)
1. 下面开始给IDEA配置ajc编译器
给Path to aspectjtools.jar配置路径,测试一下,如下图。
如果配置正确的话,现在我们就是用ajc编译的了。
3. 然后运行:
立竿见影。
至此完整演示成功。
基本原理,总结起来就是
几行 的demo,地址如下:
aspectj-demo.zip
如果此文真的给你解惑了,或者起到了帮助,可考虑打赏。
后记补充写完之后,我以为就完了,但是后来马上又发现了问题。
就是在前面引入的两个maven依赖,
它为什么要是两个依赖呢?
我偶然地发现,一个依赖也能正常执行。
更奇怪的是,这两个依赖,只依赖任何一个就可以正常执行了。
已经亲测@2021年8月23日23点04分。
那么,这里又引出了下一个问题
aspectjrt和aspectjweaver是什么关系,各自有什么作用现在来看一下
由图可知,这是很明显的,aspectjweaver 包含了aspectjrt全部的内容。
另外主要多出来的内容,以我的经验,我一眼就看出了重点:(以下是猜测,但我感觉是对的)
后者比前者多出的内容,主要是 asm 和 weaver。
那么,
ASM 是一个 Java 字节码操控框架。
它能被用来动态生成类或者增强既有类的功能。ASM 可以直接产生二进制 class 文件,也可以在类被加载入 Java 虚拟机之前动态改变类行为。Java class 被存储在严格格式定义的 .class 文件里,这些类文件拥有足够的元数据来解析类中的所有元素:类名称、方法、属性以及 Java 字节码(指令)。ASM 从类文件中读入信息后,能够改变类行为,分析类信息,甚至能够根据用户要求生成新类。
weaver是什么weaver这个词,就是“织入”的意思啊,字面意思不解释了。
所以,很明显,weaver + asm,实现了可以动态织入 pointcut等内容到字节码中去的。
那么,下一步再可以得出推论。
推论aspectjrt 功能单纯一些,应该是提供一个编译过后的已经织入了pointcut等内容的java字节码的程序的运行环境。
关键词:rt,也就是 runtime。这个概念我们已经比较熟悉了。
aspectjweaver 包含了aspectjrt全部内容,另外多出了 动态织入的能力,主要是asm + weaver部分的代码。
上面的示例中,之所以需要配置ajc编译器,要编译之后才能正常执行,正是因为推论1的原因。
而推论2
我猜测多出来的这部分能力,就是让java项目可以不用再专门指定ajc编译器,而是使用asm + weaver可以对java代码进行动态编译和织入内容,这样的话直接使用通用的javac编译器就可以了。
当然,还看得出来,也支持了注解的用法。
顺便多数一句,这个情况我已经用代码验证了,符合猜想,大概是对的无疑了。
ps: spring项目应用三步曲: aspect(需要标记为@Component) --> pointcut --> advice
看似不起眼,其实ps:这句话很精髓,懂的自然懂。
所以,项目里,想要使用aspectj注解的写法,需要引入 aspectjweaver 而不是aspectjrt ,比如spring里的aop相关的用法。
如果愿意自己指定ajc编译器,则可只引入体积较小的aspectjrt。
我忽然觉得自己理解得更通透了。