4.1 什么是面向切片编程
4.1.1 定义AOP术语
- 通知(Advice):定义了“何时”
1.前置通知(Before)
2.后置通知(After)
3.返回通知(After-returning)
4.异常通知(After-throwing)
5.环绕通知(Around) - 连接点(Join Point):可以被切的地方
- 切点(Pointcut):定义了“何处”,已经被切的地方
- 切面(Aspect):是通知和切点的结合
- 引入(Introduction):允许我们向现有的类添加新方法或属性
- 织入(Weaving):把切面应用到目标对象并创建新的代理对象的过程,有多个点可以织入
1.编译期:在目标类编译时织入(AspectJ)
2.类加载期:切面在类被加载到JVM时被织入
3.运行期:切面在运行的某个时刻被织入(Spring AOP)
4.1.2 Spring对AOP的支持
Spring提供了4种类型的AOP支持
- 基于代理的经典Spring AOP
- 纯POJO切面
- @AspectJ注解驱动的切面
- 注入式AspectJ切面
前三种是Spring AOP的变体,Spring AOP构建在动态代理的基础上,因此,Spring对AOP的支持局限于方法拦截,所以如果对AOP需求超过了简单的方法调用,那就考虑使用AspectJ来实现切面
4.2 通过切点来选择连接点
只有execution是实际执行匹配的,其他指示器都是用来限制匹配的
4.2.1 编写切点
execution(* concert.Performance.perform(..))
若想让切点仅匹配concert包,可以只用within()指示器
execution(* concert.Performance.perform(..))&&within(concert.*)
4.2.2 在切点中选择bean
bean指示器允许我们通过bean的id来限制切点只匹配特定的bean
execution(* concert.Performance.perform(..))
and bean (‘Woodstock’)
表明希望在执行Performance接口的perform方法时应用通知,但是只有ID为Woodstock的bean能接收到
4.3 使用注解创建切面
4.3.1 定义切面
@Aspect声明了一个bean是切面
@Pointcut可以定义一个命名的切点:
@Pointcut(“execution(* concert.Performance.perform(..))”)
public void performance(){}//作为一个标识
@Before,@Around等放在切面的上面
@After("performance()")
如果使用JavaConfig可以在配置类的级别上使用@EnableAspectJAutoProxy启用自动代理功能
如果使用XML文件,可以加上<aop:aspectj-autoproxy />
启用自动代理功能
4.3.2 创建环绕通知
环绕通知是最强大的通知方法,它可以将被通知的目标全部包含起来
@Around("performance()")
public void method(ProceedingJoinPoint jp){
try{
...//before method
jp.proceed();
...//after method
}catch(Exception e){}
}
4.3.3 处理通知中的参数
若被切的方法有参数:
@Pointcut(“execution(* concert.Performance.perform
(int))&&args(performNumber)”) //将参数传入被切函数
public void performance(){}//作为一个标识
@Before("performance(performNumber)")
public void method(int performNumber){
....
}
4.3.4 通过注解引入新功能
使用代理,为以编译好的java对象引入新的功能
4.4 在XML中声明切面
Spring AOP配置元素能够以非侵入性的方式声明切面
4.4.1 声明前置或者后置通知
<aop:config>
<aop:aspect ref="audience">//引用audience bean
<aop:before pointcut="excution(** concert.Performance.perform(..))"
method="silenceCellPhones"/>
<aop:after pointcut="excution(** concert.Performance.perform(..))"
method="task"/>
</aop:aspect>
</aop:config>
也可以使用pointcut定义切点:
<aop:config>
<aop:aspect id="performance" expression=
"excution(** concert.Performance.perform(..))" />
<aop:aspect ref="audience">//引用audience bean
<aop:before pointcut="performance"
method="silenceCellPhones"/>
<aop:after pointcut="performance"
method="task"/>
</aop:aspect>
</aop:config>
4.4.2 声明环绕通知
<aop:config>
<aop:aspect id="performance" expression=
"excution(** concert.Performance.perform(..))" />
<aop:aspect ref="audience">//引用audience bean
<aop:around pointcut="performance"
method="silenceCellPhones"/>
</aop:config>
4.4.3 为通知传递参数
4.4.4 通过切面引入新的功能
4.5 注入AspectJ切面
AspectJ能够在创建对象时应用通知,且AspectJ切面与Spring是互相独立的,虽然它可以应用到任何地方,包括Spring