AOP-AspectJ原理

AspectJ实际上是对AOP编程思想的一个实践。AspectJ提供了一套全新的语法实现,完全兼容Java(其实跟Java之间的区别,只是多了一些关键词而已)。同时,还提供了纯Java语言的实现,通过注解的方式,完成代码编织的功能。因此我们在使用AspectJ的时候有以下两种方式:

  • 使用AspectJ的语言进行开发
  • 通过AspectJ提供的注解在Java语言上开发

因为最终的目的其实都是需要在字节码文件中织入我们自己定义的切面代码,不管使用哪种方式接入AspectJ,都需要使用AspectJ提供的代码编译工具ajc进行编译

JoinPoints
JoinPoints 说明 示例
method call 函数调用 比如调用Log.e(),这是一处Joint point
method execution 函数执行 比如Log.e()的执行内部,是一处Joint Point
constructor call 构造函数调用 与方法的调用类型
constructor executor 构造函数执行 与方法的执行执行
field get 获取某个变量
field set 设置某个变量
static initialization 类初始化
initialization object在构造函数中做的一些工作
handler 异常处理 对应try-catch()中,对应的catch块内的执行

Pointcut使用语法

Pointcut其实是加了筛选条件限制的JoinPoints,而每种类型的JoinPoint都会对应有自己的筛选条件的匹配格式,Pointcut的定义就是要根据不同的JoinPoint声明合适的筛选条件表达式

直接对JoinPoint的选择
JoinPoint类型 Pointcut语法
Method Execution(方法执行) execution(MethodSignature)
Method Call(方法调用) call(MethodSignature)
Constructor Execution(构造器执行) execution(ConstructorSignature)
Construtor Call(构造器调用) call(ConstructorSignature)
Class Initialization(类初始化) staticinitialization(TypeSignature)
Field Read(属性读) get(FieldSignature)
Field Set(属性写) set(FieldSignature)
Exception Handler(异常处理) handler(TypeSignature)
Object Initialization(对象初始化) initialization(ConstructorSignature)
Object Pre-initialization(对象预初始化) preinitialization(ConstructorSignature)
Advice Execution(advice执行) adviceexecution()
  • 在上面表格中所提及到的MethodSignature、ConstructorSignature、TypeSignature、FieldSignature,它们的表达式都可以使用通配符进行匹配。
  • 表格当中的execution、call、set、get、initialization、preinitialization、adviceexecution、staticinitialization这些都是属于AspectJ当中的关键词
  • 表格当中的handler只能与advice中的before(advice的相应关键词及使用参考后文)一起使用
通配符 意义 示例
* 表示除”.”以外的任意字符串 java.*.Date:可以表示java.sql. Date,java.util. Date
.. 表示任意子package或者任意参数参数列表 java..*:表示java任意子包;void getName(..):表示方法参数为任意类型任意个数
+ 表示子类 java..*Model+:表示java任意包中以Model结尾的子类
MethodSignature

定义MethodSignature的条件表达式与定义一个方法类型,其结构如下:

  • 表达式:
    [@注解] [访问权限] 返回值的类型 类全路径名(包名+类名).函数名(参数)
  • 说明:
    1. []当中的内容表示可选项。当没有设定的时候,表示全匹配
    2. 返回值类型、类全路径、函数名、参数都可以使用上面的通配符进行描述。
  • 例子:
    public (..) :表示任意参数任意包下的任意函数名任意返回值的public方法
    @com.example.TestAnnotation com.example..(int) :表示com.example下被TestAnnotation注解了的带一个int类型参数的任意名称任意返回值的方法
ConstructorSignature

Constructorsignature和Method Signature类似,只不过构造函数没有返回值,而且函数名必须叫new.

  • 表达式:
    [@注解] [访问权限] 类全路径名(包名+类名).new(参数)

  • 例子:
    public *..People.new(..) :表示任意包名下面People这个类的public构造器,参数列表任意

FieldSignature

与在类中定一个一个成员变量的格式相类似。

  • 表达式:
    [@注解] [访问权限] 类型 类全路径名.成员变量名

  • 例子:
    String com.example..People.lastName :表示com.example包下面的People这个类中名为lastName的String类型的成员变量

TypeSignature

TypeSignature其实就是用来指定一个类的。因此我们只需要给出一个类的全路径的表达式即可

间接对JoinPoint进行选择

除了上面表格当中提及到的直接对Join Point选择之外,还有一些Pointcut关键字是间接的对Join Point进行选择的。如下表所示:

Pointcut语法 说明 示例
within(TypeSignature) 表示在某个类中所有的Join Point within(com.example.Test):表示在com.example.Test类当中的全部Join Point
withincode(ConstructorSignature/MethodSignature) 表示在某个函数/构造函数当中的Join Point withincode( ..Test(..)):表示在任意包下面的Test函数的所有Join Point
args(TypeSignature) 对Join Point的参数进行条件筛选 args(int,..):表示第一个参数是int,后面参数不限的Join Point

组合Pointcut进行选择

Pointcut之间可以使用“&& | !”这些逻辑符号进行拼接,将两个Pointcut进行拼接,完成一个最终的对JoinPoint的选择操作。(其实就是将上面的间接选择JoinPoint表中关键字定义的Pointcut与直接选择JoinPoint表关键字定义的Pointcut进行拼接)

Advice语法使用

Advice语法 说明
before 在选择的JoinPoint的前面插入切片代码
after 在选择的JoinPoint的后面插入切片代码
around around会替代原来的JoinPoint(我们可以完全修改一个方法的实现),如果需要调用原来的JoinPoint的话,可以调用proceed()方法
AfterThrowing 在选择的JoinPoint异常抛出的时候插入切片的代码
AfterReturning 在选择的JoinPoint返回之前插入切片的代码
©著作权归作者所有,转载或内容合作请联系作者
平台声明:文章内容(如有图片或视频亦包括在内)由作者上传并发布,文章内容仅代表作者本人观点,简书系信息发布平台,仅提供信息存储服务。

推荐阅读更多精彩内容