# AspectJ 概述
AspectJ
它是一个基于Java
语言的AOP
框架,提供了强大的AOP
功能。
AspectJ
是Java
语言的一个AOP
实现,其主要包括两个部分:第一个部分定义了如何表达、定义AOP
编程中的语法规范,通过这套语言规范,我们可以方便地使用AOP
来解决Java
中存在的交叉关注点问题,另一个部分是工具部分,包括编译器、调试工具等。
AspectJ
是最早功能比较强大的AOP
实现之一,对整套AOP
机制都有较好地实现,很多其它语言的AOP
实现,也借鉴或采纳了AspectJ
中的很多设计。在Java
领域,AspectJ
中的很多语法结构基本上已成为AOP
领域的标准。
# 安装 AspectJ
想要安装
AspectJ
需要到 AspectJ 官网或 AspectJ-Github 来下载可执行的jar
包。
从
1.9.7
版本开始,AspectJ
才可以从GitHub
上来获取,从官网下载需要捐赠所以就在GitHub
上下载了1.9.21
的可执行jar
包。
在下载完成后使用
win+r
并输入cmd
来打开命令行窗口,使用java -jar aspectj-1.9.21.jar
命令来执行,可以找到下载位置并将jar
包拖入到命令行窗口中来执行。
安装路径默认不需要修改,一直点击
Next
即可完成AspectJ
的安装。
在安装了
AspectJ
之后,在其安装目录下,可以看到如下的文件结构:
├─bin // 该路径下存放了 aj、aj5、ajc、ajdoc、ajbrowser 等命令。 | |
│ ├─aj.bat | |
│ ├─aj5.bat | |
│ ├─ajbrowser | |
│ ├─ajbrowser.bat | |
│ ├─ajc // 其中 ajc 命令最常用,它的作用类似于 javac,用于对普通 Java 类进行编译时增强。 | |
│ ├─ajc.bat | |
│ ├─ajdoc | |
│ ├─ajdoc.bat | |
├─doc // 该路径下存放了 AspectJ 的使用说明、参考手册、API 文档等文档。 | |
├─lib // 该路径下的 4 个 Jar 文件是 AspectJ 的核心类库 | |
│ ├─aspectjrt.jar | |
│ ├─aspectjtools.jar | |
│ ├─aspectjweaver.jar | |
│ ├─org.aspectj.matcher.jar | |
├─LICENSE-AspectJ.html // 相关授权文件 | |
└─README-AspectJ.html |
# 配置环境变量
CLASSPATH: C:\aspectj1.9\lib\aspectjrt.jar | |
Path: C:\aspectj1.9\bin |
如果已经存在一条
CLASSPATH
需要先使用;
分割后再进行新路径的添加,如:.;%JAVA_HOME%\lib;%JAVA_HOME%\lib\tools.jar;C:\aspectj1.9\lib\aspectjrt.jar
,添加环境变量后重新打开一个cmd
窗口并输入ajc
命令来查看是否可以成功执行。
# 添加 AspectJ 插件
注意:只有专业版的
IntelliJ IDEA
才支持AspectJ
的开发,并且IntelliJ IDEA
提供了官方文档
在
IntelliJ IDEA
中打开settings(设置)
找到Plugins(插件)
在Marketplace
中搜索AspectJ
并安装插件。
# 添加 Maven 依赖
在
pom.xml
文件中添加相关依赖。
<dependencies> | |
<dependency> | |
<groupId>org.aspectj</groupId> | |
<artifactId>aspectjrt</artifactId> | |
<version>1.8.14</version> | |
</dependency> | |
<dependency> | |
<groupId>org.aspectj</groupId> | |
<artifactId>aspectjtools</artifactId> | |
<version>1.8.14</version> | |
</dependency> | |
</dependencies> |
# 使用 Ajc 编译器
IntelliJ IDEA
默认使用javac
编译器,如果要使用AspectJ
的ajc
编译器,需要进行相应的配置,首先打开settings(设置)
找到Build,Execution,Deployment(构建、执行、部署)
下的Compiler(编译器)
下的Java Compiler(Java编译器)
,然后配置如下图:
这样就可以在项目中右键选择
Aspect
来创建.aj
文件来实现Aop
的织入了。
# AspectJ 使用示例
AspectJ
的用法非常简单,就跟我们使用JDK
编译运行Java
程序一样,示例代码如下:
package top.rem.rain; | |
/** | |
* @Author: LightRain | |
* @Description: 使用 Aspect 进行事务围绕 | |
* @DateTime: 2024-01-03 19:14 | |
* @Version:1.0 | |
**/ | |
public class HelloJava { | |
private void helloJava(){ | |
System.out.println("Hello Java!"); | |
} | |
public static void main(String[] args) { | |
HelloJava helloJava = new HelloJava(); | |
helloJava.helloJava(); | |
/* | |
执行结果: | |
开始事务。。。 | |
Hello Java! | |
结束事务。。。 | |
*/ | |
} | |
} |
如果我们现在需要在
helloJava()
方法之前启动事务当方法结束时关闭事务,如:日志打印等操作,在传统模式下我们必须手动修改helloJava()
方法来达到想要的效果,而如果使用AspectJ
则我们不需要修改上面的方法,只需要添加一个新的切面即可实现相同效果。
package top.rem.rain; | |
public aspect HelloJavaAspect { | |
void around():call(void HelloJava.helloJava()){ | |
System.out.println("开始事务。。。"); | |
proceed(); | |
System.out.println("结束事务。。。"); | |
} | |
} |
上面的
HelloJavaAspect
并不属于Java
类,其中aspect
关键字也不是Java
所支持的关键字,它只能由AspectJ
才能识别的关键字,其后缀为.aj
文件,该文件的完整名称为HelloJavaAspect.aj
,而切面的语法只有AspectJ
可以识别,并使用特殊的ajc
编译器进行编译。
在这段代码中拦截了
HelloJava.helloJava()
方法,并在其执行之前开始事务操作,proceed()
方法代表回调原来的helloJava()
方法,执行结束后将结束对该方法的事务操作。
从运行结果可以看出,在我们完全不对
HelloJava
类进行任何的修改也可以实现其想要的结果,没有进行任何修改就给它插入了事务管理功能,这正是面向切面编程的意义。因此AspectJ
通常被称为编译时增强的AOP
框架。
# SpringAop&AspectJ 的关系
在
SpringBoot
中经常见到@Before
、@After
、@Around
等AOP
相关的注解,一般没有多少解释,通常被告知这是AOP
的用法,@Before
、@After
、@Around
等AOP
相关的注解实现的底层都是AspectJ
,AspectJ 官网 &AspectJ-Github。 关于AspectJ
并不是spring framework
的一部分,AspectJ
是一个独立项目,它以优秀的方式实现了AOP
编程。spring framework
起初是有自己实现的AOP
, 但是非常的难用,后来Spring
官方索性将优秀的AspectJ
集成到了spring framework
的源码中。
# 关于依赖问题
为什么需要在
pom.xml
中引入两个依赖坐标呢?不应该只需要引入aspectjrt
坐标就可以么,关于aspectjrt
和aspectjweaver
是什么关系请看下图。
从上图可以看出
aspectjweaver
包含了aspectjrt
全部的内容,其中aspectjweaver
比aspectjrt
多出的内容主要是asm
和weaver
。
# 关于 asm
asm
是一个Java
字节码操控框架,它能用来动态生成类或者增强既有类的功能。asm
可以直接生成二进制class
文件,也可以在类被加载到Java
虚拟机之前动态改变类行为。Java class
被存储在严格定义的.class
文件中,这些类文件拥有足够的元数据来解析类中的所有元素:类名称、方法、属性以及Java
字节码 (指令),asm
从类文件中读取信息后,能够改变类行为,分析类信息,甚至能够根据用户需求来生成新的类。
# 关于 weaver
至于
weaver
则是织入的意思,所以很明显weaver+asm
就实现了可以动态织入pointcut
等内容到字节码中去了。
# 总结
aspectjrt
功能毕竟单一,只是提供一个编译后的已经织入了pointcut
等内容的java
字节码程序的运行环境。aspectjweaver
中包含了aspectjrt
全部内容,另外多出了 动态织入的能力,其主要是asm+weaver
的代码,就是为了让java
项目可以不用再专门指定ajc
编译器,而是使用asm+weaver
可以对java
代码进行动态编译和织入内容,这样的话直接使用通用的javac
编译器就可以。- 想要使用
aspectj
注解的写法,需要引入aspectjweaver
而不是aspectjrt
,比如spring
里的aop
相关的用法。