0.AspectJ简介

        在上篇文章【Spring——AOP(1)之Spring1中的配置】中,简要介绍了AOP(Aspect-Oriented Programming,面向切面编程)的概念,并介绍了AOP中的一些术语,最后通过使用Spring1中编写切面、配置切面的方式讲解了一个案例。本节我们介绍AspectJ框架,学习AspectJ框架是因为Spring2以后的AOP开发中引入了很多AspectJ的概念和配置方式。

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

要知道的是,AspectJ框架和Spring框架实现AOP的方式是不一样的,AspectJ是在编译时进行增强,所以它有一个专门的编译器来生成遵守Java字节码编码规范的Class文件。而Spring采用的是动态代理的方式,它并不需要有一个专门的编译器。故也称AspectJ为静态AOP实现,而Spring AOP为动态AOP实现。

AspectJ主要包含两个部分:第一个部分定义了如何表达、定义AOP编程中的语法规范;第二个部分是工具部分,包括编译器、调试工具等。

1.安装AspectJ

安装AspectJ首先要到AspectJ官网下载一个可执行的Jar包,然后双击该Jar包即可打开进行安装。

java aspect 处理接口入参 java aspectj原理_java aspect 处理接口入参

多次点击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

2.IntelliJ IDEA下配置AspectJ

虽然AspectJ是Eclipse基金组织的开源项目,而且提供了Eclipse的AJDT插件(AspectJ Development Tools)来开发AspectJ应用,但AspectJ并不是只能在Eclipse中开发。由于我使用IntelliJ IDEA,所以这里介绍IDEA中如何开发AspectJ。

 只有专业版的IntelliJ IDEA才支持AspectJ的开发,而且IDEA也提供了官方文档

 2.1.激活AspectJ支持插件

在专业版IDEA中开发AspectJ,需要确保下述插件被激活:

  • Spring AOP/@AspectJ
  • AspectJ Support

打开Settings(Ctrl+Alt+S)对话框,做如下配置:

java aspect 处理接口入参 java aspectj原理_AOP_02

 2.2.添加aspectjrt.jar依赖

在项目中添加aspectjrt.jar依赖,aspectjrt.jar即AspectJ安装目录中lib目录下的jar包。我的习惯是在项目中新建一个lib目录,然后将该jar包拷贝过来。

java aspect 处理接口入参 java aspectj原理_java aspect 处理接口入参_03

接着进行如下操作,将该Jar包添加进项目依赖中: 

  1. 打开Project Structure对话框(Ctrl+Shift+Alt+S)。
  2. 对应于创建项目级别的或者IDE级别的库,分别选择Libraries或者Global Libraries
  3. 点击+号并选择java
  4. 在弹出的对话框中,选择刚才我们添加进项目的lib目录下的aspectjrt.jar文件。
  5. 最后点击OK按钮即可。

java aspect 处理接口入参 java aspectj原理_jar_04

 2.3.使用AspectJ编译器(ajc)

IDEA默认使用javac编译器,如果要使用AspectJ的编译器ajc,需要在IDEA中进行相应的配置。

打开settings对话框,然后做如下配置:

java aspect 处理接口入参 java aspectj原理_intellij-idea_05

3.一个简单的案例 

1.首先编写一个简答的Java类,该Java类用于模拟一个业务组件。

public class Hello {
    public void sayHello() {
        System.out.println("Hello, AspectJ!");
    }

    public static void main(String[] args) {
        Hello hello = new Hello();
        hello.sayHello();
    }
}

该类中有一个sayHello()方法,该方法打印出了一句话!

假设现在我们需要在sayHello()方法之前启动事务,当该方法结束时关闭事务,那么在传统的编程模式下,我们必须手动修改sayHello()方法。而如果使用AspectJ,我们则不需要修改上面的方法,只需要添加一个切面即可。

下面我们来开发一个切面Aspect

如下图示,IDEA中可以直接支持开发Aspect

java aspect 处理接口入参 java aspectj原理_jar_06

我们创建TxAspect切面,如下代码: 

public aspect TxAspect {
    void around():call(void Hello.sayHello()){
        System.out.println("开始事务...");
        proceed();
        System.out.println("事务结束...");
    }
}

此时发现TxAspect的类型是aspect,并不是一个类class,这就是AspectJ提供的一个特殊的模块——切面。其后缀为.aj,该文件的完整文件名为TxAspect.aj。切面的语法只有AspectJ可以识别,并使用其特殊的编译器ajc来编译。

这段代码拦截Hello.sayHello()方法,并在其执行之前开始事务,proceed()方法代表回调原来的sayHello()方法,执行结束后结束事务。

因为我们已经配置过了编译器,所以这里我们直接运行Hello.java代码,可以看到运行结果:

java aspect 处理接口入参 java aspectj原理_java_07

运行结果完全符合我们的预期。我们并没有对Hello类做任何修改,就给它插入了事务管理的功能,这正是面向切面编程的意义所在。从这个例子中我们也可以体会到AspectJ的易学易用、无侵入(不需要继承任何类和接口)的特性。