本文是Spring AOP官方文档部分内容的简记。
1,Introduction
Spring IoC容器不依赖于AOP,但是作为IoC容器的补充,AOP提供了非常强大的中间件解决方案。
AOP在Spring框架中的用途:
- 提供声明式企业级服务,特别是作为EJB声明式服务的替代品,典型的应用就是Spring声明式事务管理。
- 允许用户自定义切面
1.1,AOP概念
- 切面(Aspect):切面是模块化的关注点,这些关注点会横切多个类。在Spring AOP中,切面通过普通java类(基于原型—schema-based的方法)或者基于注解
@Aspect
实现。切面=切点+通知。 - 连接点(Joint Point):程序执行期间的某个运行点,如方法的执行或异常处理。在Spring AOP中,连接点总是表示方法的执行。
- 通知(Advice):在特定的连接点上由切面执行的动作。通知分为不同的类型:around, before 和 after,后面会详细讨论。在 Spring 中,通知是一个拦截器(interceptor)模型,Spring在连接点前后维护一个拦截器链。
- 切点(Pointcut):匹配连接点的断言。切面总是和切点表达式相关,并在任何匹配的连接点执行通知。Spring默认使用AspectJ切点表达式语言。切点决定了在何处执行通知。
- 引入(Introduction):向现有的类添加额外的属性或方法。
- 目标对象(Target object):被一个或多个切面通知的对象。由于Spring AOP使用运行时代理实现,目标对象总是被代理的对象—参考Spring AOP的实现。
- AOP代理(AOP proxy):有AOP框架创建的用来实现切面协议的对象。Spring框架通过JDK动态代理或者CGLIB代理实现AOP。
- 织入(Weaving):将切面和应用类型或对象连接起来创建advised对象的过程。织入过程能发生在编译时期,加载时期以及运行时。Spring AOP在运行时执行织入。
通知类型:
- 前置通知(Before advice):执行在连接点之前的通知。除非抛出异常,前置通知无法阻止程序执行到连接点。
- 后置返回通知(After returning advice):连接点正常返回后的通知。
- 后置异常通知(After throwing advice):连接点抛出异常时的通知。
- 后置通知(After finally advice):不管连接点执行成功与否都会执行的通知,类似try-catch中的finally。
- 环绕通知(Around advice):包裹连接点的通知。环绕通知能运行到连接点也可以直接返回或抛出异常防止程序运行到连接点。
1.2,Spring AOP的能力和目标
Spring AOP由纯Java实现,不需要控制类加载器,适用于Servlet容器或应用服务器。
Spring AOP的实现和大多数其它的AOP框架不同,Spring的目标不是提供完整的AOP实现,而是在AOP实现和IoC容器提供一个集成方案,以此解决企业级y应用中的一些常见问题。因此,Spring AOP的功能总是和IoC容器结合在一起,切面通过常规的bean definition语法配置。
1.3,AOP代理
Spring AOP默认使用标准的JDK动态代理实现。Spring AOP也能使用CGLIB代理,这在代理类而不是接口的时候是必要的。当业务对象没有实现任何接口的时候,CGLIB默认被使用。
2,@AspectJ注解支持
Spring利用AspectJ中的切点解析和匹配库来解析AspectJ中的注解,但是AOP运行时仍旧是纯Spring AOP,它并不依赖于AspectJ编译器或织入器。
2.1,启动@AspectJ支持
可以通过Java配置使能@AspectJ
注解支持(XML配置不在此记录)
@Configuration
@EnableAspectJAutoProxy
public class AppConfig{
// TODO
}
2.2,声明一个切面
任何定义在上下文中并被@Aspect
注解的bean都可以被Spring探测到并用于配置Spring AOP。例如:
package com.example;
import org.aspectj.lang.annotation.Aspect
@Aspect
public class NotVeryUsefulAspect {
// TODO
}
可以通过xml配置将切面类注册成切面bean,也可以通过组件扫描自动探测它们。自动扫描需要配合Spring 原型注解(例如
@Component
)使用。
2.3,声明切点
切点的声明包括两部分:1,由名称和任意多个参数构成的签名;2,切点表达式。在@AspectJ
注解风格的AOP中,切点签名由一个常规的方法定义表示,切点表达式由@Pointcut
注解表示。注意,作为切点签名的方法的返回类型只能是void.
示例代码:<