Spring AOP学习之aspectj

概念

  1. join point

  2. pointcut

  3. advice
  4. 编译器,织入 (weaving)

Join Point

函数执行时的切入点,类别挺多的

方法:

以Account类的debit方法为例:

execution,如下图

Spring AOP学习之aspectj_第1张图片

call,如下图

构造函数:

Spring AOP学习之aspectj_第2张图片

访问属性:

Spring AOP学习之aspectj_第3张图片

异常处理:

Spring AOP学习之aspectj_第4张图片

类初始化(静态代码块):

Spring AOP学习之aspectj_第5张图片

 

还有其他几种暂时忽略

注意以上的具体代码中,表示的都是一个join cut

 

Point Cut

多个join point的集合。方便对集合中的join point统一处理。为了与join point对应,point cut也有好几种type。另外,为了方便收集join point,point cut一般会用到通配符。

 

通配符:

  1. *,表示任意的字符,不包括括号
  2. ..,表示任意的字符,包括括号
  3. +,表示子类

通配符举例:

  1. 包com.yxm下的所有方法,参数不限,返回不限:* com.yxm..*.*(..),..*查找包中(包括所有子包和后代包)中的所有类,.*表示任意方法,..表示参数的数量和类型不限
  2. 包com.yxm下的所有方法,不包括子包和后代包:* com.yxm.*.*(..)
  3. 以"com.yxm.Accout"开头的所有类,比如com.yxm.AccountService: com.yxm.Account*
  4. com.yxm.Account类的所有子类: com.yxm.Account+

 

point cut type:

  1. execution,对应的join point是:方法execution,构造函数
  2. call,对应的join point是:方法调用call
  3. get/set,对应的join point是:访问属性
  4. handler,对应的join point是:异常处理
  5. staticinitialization,对应的join point是:类初始化(静态代码块)

point cut举例

  1. 执行com.yxm包下的所有方法,参数不限:execution(* com.yxm..*.*(..));
  2. 调用com.yxm包下的所有方法,参数不限:call(* com.yxm..*.*(..));
  3. 调用com.yxm包下的所有方法,不包括子包和后代包: call (* com.yxm.*.*(..));

使用父类方法

如果类com.yxm.Parent有一个方法p();同时它的子类com.yxm.child.Child1定义了父类没有的方法c1;子类com.yxm.child.Child2重写了p()方法,里面还调用了super.p()

  1. execution(* com.yxm.*.*(..))不会收集到Child1.c1()这个join point
  2. execution(* com.yxm.*.*(..))会收集到Child1.p()这个join point(因为Child1.p()调用的也是父类的方法)
  3. execution(* com.yxm.*.*(..))会收集到Child2.p()这个join point,也会收集到super.p()

 

通配符与类型

  1. com.yxm.Account,具体的类型
  2. com.yxm.Account*,com.yxm包下Account开头的类,比如com.yxm.AccountService
  3. com.yxm..*,com.yxm包和子包后代包中的类
  4. com.yxm.Account+, Account类/接口的子类

 

执行环境point cut

  1. this(类型)
  2. target(类型)

this表示当前join point收集时,“this”所指的对象;

target表示当前join point收集时,正在执行某个对象(target)的方法/变量

以在类Main中调用Account类的debit方法举例:

call (* Account.*(..)) 收集到的join point中,this指向了Main对象,target指向了Account对象

execution (* Account.*(..)) 收集到的join point 中,this和target都是Account对象

使用this和target可以获取join point执行时的执行环境相关的对象,类型不能使用通配符只能使用具体的类型,不过实际获取到的this/target对象可以是此类型的子类

 

参数point cut: args

  1. args(String a, ..)收集参数列表第一个参数是String,其他参数的类型/数量不限制
  2. args(String a, int b), 收集参数列表有2个参数,第一个String类型,第二个int类型的join point

 

point cut的组合使用

  1. call (* com.yxm..*.*(..)) && this(com.yxm.Account);
  2. call (* com.yxm..*.*(..)) && args(String a);

 

Advice

使用point cut收集到join point之后,用advice对point cut做切面编程,主要的advice type是:

  1. before
  2. after
  3. after returning
  4. around
  5. 其他

aspectj编译器,织入

织入(weaving),将AOP代码逻辑与核心代码逻辑融合

织入可以是:

  1. 编译时织入,需要特殊的编译器
  2. 编译后织入,需要修改核心代码编译后的二进制文件
  3. 加载类时织入,需要特殊的classloader
  4. 运行时织入,可以使用动态代理来实现运行时织入

aspectj支持编译时,编译后,加载类时织入,不支持运行时织入(Spring AOP会用运行时织入)

如果使用编译时织入,需要下载aspectj 自己的编译器acj编译代码

官网下载,使用ajc命令代替javac命令编译,编译得到是普通的.class文件,使用java命令即可运行。

通过反编译.class文件可以看到aspectj使用的是编译时修改.class文件的字节码实现AOP,不基于继承,也不基于代理模式(包括动态代理和静态代理)

下图是反编译的代码中一个before execution添加的

Spring AOP学习之aspectj_第6张图片

你可能感兴趣的:(Spring AOP学习之aspectj)