一.基本介绍
在软件开发中,散布于应用中多处的功能被称为横切关注点(crosscutting concern)。
我们把这些横切关注点与业务逻辑相分离的编程过程称之为面向切面编程(AOP)。
在前面我们学习了依赖注入的目的是实现应用对象的解耦,同样,AOP的目的也是实现横切关注点和它们所影响的对象之间的解耦,来方便我们的开发过程。
二.什么是面向切面编程(AOP)?
一.什么是切面?
面向切面编程时,我们仍然在一个地方定义通用功能,但我们却可以通过声明的方式定义这个功能以何种方式在何处应用而无需修改受影响的类。也就是说横切关注点可以被模块化在一个特殊的地方,这些类我们称之为切面(aspect)。
二.AOP术语学习
1.通知(advice):定义了切面是什么以及何时使用。
2.切点(pointcut):指定切面的作用位置。
3.连接点(join point):我们的应用可能有很多的时机应用通知,这种时机被称为连接点。
4.切面(Aspect):切面是通知和切点的结合,通知和切点共同定义了切面的全部内容—-它是什么,在何时何处完成其功能。
5.织入(weaving):织入是把切面应用到目标对象并创建新的代理对象的过程。
下图展示了它们之间的关系:
6.引入(Introduction):引入允许我们向现有的类添加新方法或属性而无需修改现有类。
三.Spring对AOP的支持
实际上有很多AOP框架,它们的功能也都不完全相同,但无论如何,我们可以确定的是创建切点来定义切面所织入的连接点是AOP框架的基本功能。
1.Spring提供了4种类型的AOP支持:
1).基于代理的经典Spring AOP(已被淘汰)
2).纯POJO切面
借助Spring的aop命名空间,我们可以将纯POJO转换为切面,实际上,这些POJO只提供了满足切点条件时所要调用的方法,用XML配置。
3).@AspectJ注解驱动的切面
Spring借鉴了AspectJ的切面,以提供注解驱动的AOP,本质上,它依然是Spring基于代理的AOP,但编程模型几乎与编写成熟的AspectJ注解切面完全一致,这种AOP风格的好处在于能够不适用XML来完成。
4).注入式AspectJ切面(适用于Spring所有版本)
如果你的AOP需求超过了简单的方法调用(如构造器或属性拦截),那么你需要考虑使用注入式AspectJ来实现切面。
三.通过切点来选择连接点
在Spring AOP中,要使用AspectJ的切点表达式语言来定义切点。其中最重要的就是Spring仅支持AspectJ切点指示器的一个子集,下表列出了Spring AOP所支持的AspectJ切点指示器:
从上表中我们可以看出 execution指示器是我们在编写切点定义时最主要使用的,在此基础上,我们使用其他指示器来限制所匹配的切点。
1.编写切点
我们知道切点的作用就是指定切面的作用位置。
下面我们通过一个例子来学习
我们定义一个接口:
package concert;
public interface Performance{
public void perform();
}
1)假设我们编写了perform()方法触发的通知,下面的切点表达式则可以设置当perform()方法执行时触发通知的应用用:
execution(* concert.Performance.perform(..))
上面表达式以 *开始表明了我们不关心方法的返回值和类型,然后我们指定了全限定类名和方法名。
对于方法参数列表,我们使用(…)表明切点要选择任意的perform()方法,无论该方法的入参是什么。
2)现在假设我们要配置的切点只匹配concert包,我们可以:
execution(* concert.Performance.perform(..)) && within(concert.*)
2.在切点中选择bean
除了上表的指示器之外,Spring还引入了一个新的bean()指示器,它允许我们在切点表达式中使用bean的id来标识bean,bean()使用beanid或bean名称作为参数来限制切点只匹配特定的bean。
例如:
execution(* concert.Performance.perform()) and bean('woodstock')
上面的表达式希望在执行perform()方法时应用通知,但限定bean的ID为woodstock。
与之相反的是:
execution(* concert.Performance.perform()) and !bean('woodstock')
在上面的情况下,切面的通知会被编织到所有ID不为woodstock的bean中。