一、Spring对AOP的支持
1. AOP术语
通知(Advice)
Spring切面可以应用5种类型的通知:
- 前置通知(Before)
- 后置通知(After)
- 返回通知(After-returning)
- 异常通知(After-throwing)
- 环绕通知(Around)
连接点(Join point)
切点(Pointcut)
切面(Aspect)
引入(Introduction)
织入(Weaving)
在目标对象的生命周期里有多个点可以进行织入:- 编译期,AspectJ的织入编译器就是用这种方式
- 类加载期
- 运行期,Spring AOP使用此种方式织入切面。
Spring提供了4种类型的AOP支持:
- 基于代理的经典Spring AOP
- 纯POJO切面
- @AspectJ注解驱动的切面
- 注入式AspectJ切面
Spring只支持方法级别的连接点,不支持字段和构造器接入点。
2、通过切点选择连接点
Spring AOP使用AspectJ的切点表达式语言来定义切点,只支持AspectJ切点指示器的一个子集。下表为支持的指示器:
AspectJ指示器 | 描述 |
---|---|
args() | 限制连接点匹配参数为指定类型的执行方法 |
@args() | 限制连接点匹配参数由指定注解标注的执行方法 |
execution() | 用于匹配是连接点的执行方法 |
this() | 限制连接点匹配AOP代理的bean引用为指定类型的类 |
target | 限制连接点匹配目标对象为指定类型的类】 |
@target() | 限制连接点匹配特定的执行对象,这些对象对应的类型要具有指定类型的注解 |
within() | 限制连接点匹配指定的类型 |
@within() | 限制连接点匹配指定注解所标注的类型(当使用Spring AOP时,方法定义在由指定的注解所标注的类里) |
@annotation | 限定匹配带有指定注解的连接点 |
编写切点
execution(* concert.Performance.perform(..))
* 号表示方法返回值可以是任意类型,然后指定全限定类名和方法名,方法参数列表
(..)
表明切点要选择任意的perform()方法,无论方法的入参是什么。
execution(* concert.Performance.perform(..)) && within(concert.*)
&&
操作符表示同时满足的条件,也可使用||
,!
操作符 ,within(concert.*)
表示当concert包下的任意类的方法被调用时。
xml配置中"&"有特殊含义,可以用and
、or
、not
代替。
处理通知中的参数
@Pointcut("@execution(* concert.Performance.perform(int) && args(num))")
public void played(int num){}
@Befor("played(num)")
public void countPlayed(int num){
···
}
agrs(num)表明传递给perform()方法的in类型参数也会传递到通知中去,参数名称与切点方法签名中一致。
开启配置
使用@EnableAspectJAutoProxy
启动AspectJ自动代理,配置才能生效
xml使用aop命名空间<aop:aspectj-autoproxy>
通过注解引入新功能
@Aspect
public class EncoreableINtroducer(){
@DeclareParents(value="concert.Performance+",defaultImpl=DefaultEncoreable.class)
public static Encoreable encoreable;
}
EncoreableINtroducer 是一个切面,通过 DeclareParents 注解,将 Encoreable 接口引入到Perfirmance bean中。DeclareParents 由三部分组成:
- value 指定哪种类型的bean需要引入该接口,
Performance+
中的+
表示所有子类型,而不是其本身。- defaultImpl 指定为引入功能提供实现的类。
- @DeclareParents注解所标注的静态属性指明了要引入的接口。
xml中声明切面
Spring aop配置元素能够以非入侵方式声明切面
AOP配置元素 | 用途 |
---|---|
<aop:adviser> | 定义aop通知器 |
<aop:after> | 定义后置通知(不管被通知的方法是否执行成功) |
<aop:after-returning> | 定义aop返回通知 |
<aop:after-throwing> | 定义aop异常通知 |
<aop:around> | 定义aop环绕通知 |
<aop:aspect> | 定义一个切面 |
<aop:aspect-autoproxy> | 启用@AspectJ注解驱动的切面 |
<aop:before> | 定义aop前置通知 |
<aop:config> | 顶层的AOP元素。大多<aop:*>元素必须包含在<aop:config>内 |
<aop:declare-parents> | 以透明的方式为被通知的对象引入额外的接口 |
<aop:pointcut> | 定义一个切点 |
声明一个没有注解的bean为切面
<aop:config>
<!--引用一个bean声明为切面-->
<aop:aspect ref="audience">
<aop:before pointcut="execution(* concert.Performance.perform(..))" method="dobefore" />
</aop:config>
使用<aop:pointcut>
定义命名切点
<aop:config>
<!--引用一个bean声明为切面-->
<aop:aspect ref="audience">
<!--定义切点-->
<aop:pointcut id="performance" expression="execution(* concert.Performance.perform(..))">
<aop:before pointcut-ref="performance" method="dobefore" />
</aop:config>