Spring侧重于提供一种基于代理(proxy-based)的AOP实现,我们可以无缝的整合Spring AOP,IoC和AspectJ,使得所有的AOP应用完全融入基于Spring的应用体系。Spring目前仅支持使用方法调用作为连接点(join point),在Spring bean上通知方法的执行。
AOP基本概念
- 切面(Aspect): 一个关注点的模块化,这个关注点可能会横切多个对象。事务管理是J2EE应用中一个关于横切关注点的很好的例子。在Spring AOP中,切面可以使用基于模式)或者基于@Aspect注解的方式来实现。
- 连接点(Joinpoint): 在程序执行过程中某个特定的点,比如某方法调用的时候或者处理异常的时候。在Spring AOP中,一个连接点总是表示一个方法的执行。
- 通知(Advice): 在切面的某个特定的连接点上执行的动作。其中包括了“around”、“before”和“after”等不同类型的通知(通知的类型将在后面部分进行讨论)。许多AOP框架(包括Spring)都是以拦截器做通知模型,并维护一个以连接点为中心的拦截器链。
- 切入点(Pointcut):匹配连接点的断言。通知和一个切入点表达式关联,并在满足这个切入点的连接点上运行(例如,当执行某个特定名称的方法时)。切入点表达式如何和连接点匹配是AOP的核心:Spring缺省使用AspectJ切入点语法。
- 引入(Introduction): 用来给一个类型声明额外的方法或属性(也被称为连接类型声明(inter-type declaration))。Spring允许引入新的接口(以及一个对应的实现)到任何被代理的对象。例如,你可以使用引入来使一个bean实现IsModified接口,以便简化缓存机制。
- 目标对象(Target Object): 被一个或者多个切面所通知的对象。也被称做被通知(advised)对象。 既然Spring AOP是通过运行时代理实现的,这个对象永远是一个被代理(proxied)对象。
- AOP代理(AOP Proxy): AOP框架创建的对象,用来实现切面契约(例如通知方法执行等等)。在Spring中,AOP代理可以是JDK动态代理或者CGLIB代理。
- 织入(Weaving): 把切面连接到其它的应用程序类型或者对象上,并创建一个被通知的对象。这些可以在编译时(例如使用AspectJ编译器),类加载时和运行时完成。Spring和其他纯Java AOP框架一样,在运行时完成织入。
通知类型:
- 前置通知(Before advice):在某连接点之前执行的通知,但这个通知不能阻止连接点之前的执行流程(除非它抛出一个异常)。
- 后置通知(After returning advice):在某连接点正常完成后执行的通知:例如,一个方法没有抛出任何异常,正常返回。
- 异常通知(After throwing advice):在方法抛出异常退出时执行的通知。
- 最终通知(After (finally) advice):当某连接点退出的时候执行的通知(不论是正常返回还是异常退出)。
- 环绕通知(Around Advice):包围一个连接点的通知,如方法调用。这是最强大的一种通知类型。环绕通知可以在方法调用前后完成自定义的行为。它也会选择是否继续执行连接点或直接返回它自己的返回值或抛出异常来结束执行。
AspectJ切入点语法详解
切入点指示符用来指示切入点表达式目的,Spring AOP支持的AspectJ切入点指示符如下:
切入点指示符 | 说明 |
---|---|
execution | 方法签名需要满足execution中描述的方法签名 |
within | 包或者类型满足within中描述的包或者类型的类的所有非私有方法 |
this | Spring AOP 的代理实例的类型满足this中的描述的类型 |
target | 业务实例对象(非代理实例)的类型满足target 中的描述的类型 |
args | 方法的参数满参数类型为args中描述的类型 |
@target | 类型拥有@target描述中给出的annotation |
@args | 方法运行时传入的参数的实际类型拥有@args描述中给出的annotation |
@within | 类型拥有@target描述中给出的annotatio |
@annotation | 方法拥有@annotation 描述中给出的annotation |
bean(idOrNameOfBean) | bean的名字或者为bean描述中的名字或者Id |
切入指示符特性对比
切入点指示符 | 切人元素 | 织入方式 | 通配符 |
---|---|---|---|
execution | 方法 | 动态织入 | 支持 |
@annotation | 方法 | 动态织入 | 不支持 |
within | 类 | 静态织入 | 支持 |
@within | 类 | 静态织入 | 不支持 |
target | 类 | 动态织入 | 不支持 |
@target | 类 | 动态织入 | 不支持 |
this | 类 | 动态织入 | 不支持 |
bean | 类 | 动态织入 | 支持 |
args | 方法参数 | 动态织入 | 支持 |
@args | 方法参数 | 动态织入 | 不支持 |
织入类型
- 动态织入:需要在运行时才能确定那些被拦截,可以获取他们对应的实例。如果切入的是基类,那么这个pointcut同时也会对他的子类也起作用。
- 静态织入:指在编译时期就织入,即编译出来的class文件,字节码就已经被织入了。
AspectJ类型匹配的通配符
通配符 | 说明 |
---|---|
* | 匹配任何数量字符 |
.. | 匹配任何数量字符的重复,如在类型模式中匹配任何数量子包;而在方法参数模式中匹配任何数量参数 |
+ | 匹配指定类型的子类型;仅能作为后缀放在类型模式后边 |
execution基本语法
execution(<修饰符模式>?<返回类型模式><方法名模式>(<参数模式>)<异常模式>?)
除了返回类型模式、方法名模式和参数模式外,其它项都是可选的。
组合切入点表达式
AspectJ使用 且(&&)、或(||)、非(!)来组合切入点表达式。
通知参数
有两种获取通知参数的方式
- 使用JoinPoint获取:任何通知方法的第一个参数都可以是JoinPoint。然后使用jp.getArgs()就能获取到被通知方法参数:
- 自动获取:除了execution和bean指示符不能传递参数给通知方法,其他指示符都可以将匹配的相应参数或对象自动传递给通知方法。
JoinPoint参数类型
- JoinPoint:提供访问当前被通知方法的目标对象、代理对象、方法参数等数据:
- ProceedingJoinPoint:用于环绕通知,使用proceed()方法来执行目标方法:
- JoinPoint.StaticPart:提供访问连接点的静态部分,如被通知方法签名、连接点类型等
通知顺序
Spring AOP使用AspectJ的优先级规则来确定通知执行顺序。AspectJ根据@Order注解判断顺序,数字越大越晚通知。
spring2.5官方文档: http://shouce.jb51.net/spring/aop.html
开涛的博客:http://jinnianshilongnian.iteye.com/blog/1415606
开涛的代码: http://www.programcreek.com/java-api-examples/index.php?source_dir=javasousuo-master/javasousuo/springTest/spring/src/cn/javass/spring/chapter6/aop/PointcutAspect.java
我对AOP的理解:http://jinnianshilongnian.iteye.com/blog/1474325
Spring AOP 和 AspectJ 之间的差别 : http://blog.csdn.net/a128953ad/article/details/50509437