# AspectJ 概述

AspectJ 它是一个基于 Java 语言的 AOP 框架,提供了强大的 AOP 功能。

AspectJJava 语言的一个 AOP 实现,其主要包括两个部分:第一个部分定义了如何表达、定义 AOP 编程中的语法规范,通过这套语言规范,我们可以方便地使用 AOP 来解决 Java 中存在的交叉关注点问题,另一个部分是工具部分,包括编译器、调试工具等。

AspectJ 是最早功能比较强大的 AOP 实现之一,对整套 AOP 机制都有较好地实现,很多其它语言的 AOP 实现,也借鉴或采纳了 AspectJ 中的很多设计。在 Java 领域, AspectJ 中的很多语法结构基本上已成为 AOP 领域的标准。

# 安装 AspectJ

想要安装 AspectJ 需要到 AspectJ 官网 AspectJ-Github 来下载可执行的 jar 包。

pivEFLF.png
pivVCtA.png

1.9.7 版本开始, AspectJ 才可以从 GitHub 上来获取,从官网下载需要捐赠所以就在 GitHub 上下载了 1.9.21 的可执行 jar 包。

在下载完成后使用 win+r 并输入 cmd 来打开命令行窗口,使用 java -jar aspectj-1.9.21.jar 命令来执行,可以找到下载位置并将 jar 包拖入到命令行窗口中来执行。

pivVdhR.png

安装路径默认不需要修改,一直点击 Next 即可完成 AspectJ 的安装。

pivVh9I.png

在安装了 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 命令来查看是否可以成功执行。

pivZYxP.png

# 添加 AspectJ 插件

注意:只有专业版的 IntelliJ IDEA 才支持 AspectJ 的开发,并且 IntelliJ IDEA 提供了官方文档

IntelliJ IDEA 中打开 settings(设置) 找到 Plugins(插件)Marketplace 中搜索 AspectJ 并安装插件。

pivZha4.png

# 添加 Maven 依赖

pom.xml 文件中添加相关依赖。

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 编译器,如果要使用 AspectJajc 编译器,需要进行相应的配置,首先打开 settings(设置) 找到 Build,Execution,Deployment(构建、执行、部署) 下的 Compiler(编译器) 下的 Java Compiler(Java编译器) ,然后配置如下图:

pivelLT.png

这样就可以在项目中右键选择 Aspect 来创建 .aj 文件来实现 Aop 的织入了。

# AspectJ 使用示例

AspectJ 的用法非常简单,就跟我们使用 JDK 编译运行 Java 程序一样,示例代码如下:

HelloJava.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 则我们不需要修改上面的方法,只需要添加一个新的切面即可实现相同效果。

pivmKtH.png

HelloJavaAspect.aj
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() 方法,执行结束后将结束对该方法的事务操作。

pivu8w8.png

从运行结果可以看出,在我们完全不对 HelloJava 类进行任何的修改也可以实现其想要的结果,没有进行任何修改就给它插入了事务管理功能,这正是面向切面编程的意义。因此 AspectJ 通常被称为编译时增强的 AOP 框架。

# SpringAop&AspectJ 的关系

SpringBoot 中经常见到 @Before@After@AroundAOP 相关的注解,一般没有多少解释,通常被告知这是 AOP 的用法, @Before@After@AroundAOP 相关的注解实现的底层都是 AspectJ ,AspectJ 官网 &AspectJ-Github。 关于 AspectJ 并不是 spring framework 的一部分, AspectJ 是一个独立项目,它以优秀的方式实现了 AOP 编程。 spring framework 起初是有自己实现的 AOP , 但是非常的难用,后来 Spring 官方索性将优秀的 AspectJ 集成到了 spring framework 的源码中。

# 关于依赖问题

为什么需要在 pom.xml 中引入两个依赖坐标呢?不应该只需要引入 aspectjrt 坐标就可以么,关于 aspectjrtaspectjweaver 是什么关系请看下图。

pivMTRH.png

从上图可以看出 aspectjweaver 包含了 aspectjrt 全部的内容,其中 aspectjweaveraspectjrt 多出的内容主要是 asmweaver

# 关于 asm

asm 是一个 Java 字节码操控框架,它能用来动态生成类或者增强既有类的功能。 asm 可以直接生成二进制 class 文件,也可以在类被加载到 Java 虚拟机之前动态改变类行为。 Java class 被存储在严格定义的 .class 文件中,这些类文件拥有足够的元数据来解析类中的所有元素:类名称、方法、属性以及 Java 字节码 (指令), asm 从类文件中读取信息后,能够改变类行为,分析类信息,甚至能够根据用户需求来生成新的类。

# 关于 weaver

至于 weaver 则是织入的意思,所以很明显 weaver+asm 就实现了可以动态织入 pointcut 等内容到字节码中去了。

# 总结

  1. aspectjrt 功能毕竟单一,只是提供一个编译后的已经织入了 pointcut 等内容的 java 字节码程序的运行环境。
  2. aspectjweaver 中包含了 aspectjrt 全部内容,另外多出了 动态织入的能力,其主要是 asm+weaver 的代码,就是为了让 java 项目可以不用再专门指定 ajc 编译器,而是使用 asm+weaver 可以对 java 代码进行动态编译和织入内容,这样的话直接使用通用的 javac 编译器就可以。
  3. 想要使用 aspectj 注解的写法,需要引入 aspectjweaver 而不是 aspectjrt ,比如 spring 里的 aop 相关的用法。