内容
- 面向切面编程基本原理
- 通过POJO创建切面
- 使用@AspectJ注解
- 为AspectJ切面注入依赖
关键词
- 横切关注点(cross-cutting concern)
- 继承 (inheritance)
- 委托 (delegation)
- 通知 (advice)
- 切点 (pointcut)
- 连接点 (join point)
4.1 面向切面编程
日志是应用切面的常见范例,其他常见还包括声明式事务、安全和缓存
那么什么是切面编程?
在代码中的一个地方定义通用功能,通过声明的方式被调用,而无需修改其他类。那么该模块化的特殊类,就被称之为切面(Aspect)。可以使关注代码集中管理,而不是分散式管理;服务模块更加简洁,更多的关注于核心代码,而切面类的代码就可以使次要关注点。
4.1.1 定义AOP术语
- 通知 (advice)
- 切点 (pointcut)
- 连接点 (join point)
通知:切面的工作被称之为通知。通知定义了切面是什么以及何时使用,还解决了什么时候执行的问题。
五种类型的通知
名词 | 说明 |
---|---|
前置通知(Before) | 在目标方法被调用之前调用通知功能 |
后置通知(After) | 在目标方法完成之后调用通知,此时不会关心方法的输出是什么 |
返回通知(After-returning) | 在目标方法执行成功后通知 |
异常通知(After-throwing) | 在目标方法抛出异常后通知 |
环绕通知(Around) | 通知包裹了被通知的方法,在被通知的方法调用之前和调用之后执行自定义的行为。 |
连接点:是在应用执行过程中能够插入切面的一个点。这个点可以是调用方法时、抛出异常时、甚至是修改一个字段时。切面代码可以利用这些点插入到应用的正常流程之中,并添加新的行为。
切点:通知定义了“何时”和“什么”,那么切点就定义了“何处”。切点的定义通常会匹配通知所要织入的一个或多个连接点。通常会指定明确的类或者方法,但是也会使用正则等进行类和方法的匹配。
切面:切面=通知+切点;即阐明了“何时”在“何处”执行了“什么”。
引入(Introduction):引入允许我们向现有的类添加新方法或属性
织入(Weaving):织入是把切面应用到目标对象并创建新的代理对象的过程。切面在指定的连接点被织入到目标对象中。在目标对象的生命周期里有多个点可以进行织入。
- 编译期:切面在目标类编译时被织入。
- 类加载期:切面在目标类加载到JVM时被织入。
- 运行期:切面在应用运行的某个时刻被织入。
4.2 切点表达式语言
AspectJ指示器 | 描述 |
---|---|
arg | 限制连接点匹配参数为指定类型的执行方法 |
@args() | 限制连接点匹配参数为指定注解的执行方法 |
execution() | 用于匹配时连接点的执行方法 |
this() | 限制连接点匹配AOP代理的bean引用为指定类型的类 |
target | 限制连接点匹配目标对象为指定类型的类 |
@target() | 限制连接点匹配特定的执行对象,这些对象对应的类要具有指定类型的注解 |
within() | 限制连接点匹配指定的类型 |
@within() | 限制连接点匹配指定注解所标注的类型 |
@annotation | 限制连接点匹配带有指定注解的连接点 |
1. execution(* concert.Performance.perform(..))
* 为返回任意类型
concert.Performance为方法所属类
perform 方法
(..) 任意参数
2. execution(* concert.Performance.perform(..) &&(||、!) within(concert.*))
可以使用与或非和其他关系关联
使用AspectJ注解来声明通知方法
注解 | 描述 |
---|---|
@Before | 通知方法会在目标方法调用之前执行 |
@After | 在目标方法完成之后调用通知,此时不会关心方法的输出是什么 |
@After-returning | 在目标方法执行成功后通知 |
@After-throwing | 在目标方法抛出异常后通知 |
@Around | 通知包裹了被通知的方法,在被通知的方法调用之前和调用之后执行自定义的行为。 |
@PointCut | 在一个@AspectJ切面内定义可重用的切点 |
4.2.1 @Around
@Around注解表明一个方法会作为该切点的环绕通知,也可以理解为前置+后置的总和。但是现在会放置在一个方法中,而不会分布在其他其他不同的方法里。而且,在新的通知方法里,ProceedingJointPoint jp必须作为参数。这个对象必须要有而且也不要忘记调用jp.proceed()方法来执行源方法。