在软件开发过程中,发布于应用程序多处的功能成为横切关注点,通常这些横切关注点是与应用程序分离的。
横切关注点被模块化为特殊的类,称为“切面”。通过声明的方式来决定切面在何处以何种方式被应用。
这样1,每个关注点都被集中在一个地方,而不是分散在多出代码。2,服务器比较简洁,只包含核心功能的代码,次要的关注点都被移动到切面上了。
AOP的术语
1, 切面:实现了横切关注点(事务、安全、日志等)的类,是通知和切点的集合
2, 通知:通知描述了切面要完成的工作,以及切面在合适执行这个工作
Spring的切面可以应用5种Advice Before :在方法调用之前调用通知 After:之后,无论是否调用成功 After-returning:返回之后 After-throwing:抛出异常之后 Around :在方法调用之前和之后通知
3, 连接点:应用程序中可以插入前面的位置,切面代码可以通过连接点插入到应用程序中
4, 切点:明确切面要织入的连接点的位置
5, 引入:引入允许向已知类中加入新的方法和属性
6, 织入:切面在指定的连接点织入到目标对象,在目标对象的声明周期中,有多个点可以织入,包括:编译期、类加载期、运行期
Spring AOP是在运行期织入的。
Spring提供了4种类型的AOP支持:
1,基于代理的经典Spring AOP;
2,纯POJO切面;使用xml配置
3,@AspectJ注解驱动的切面;使用注解配置
4,注入式AspectJ切面(适用于Spring各版本) 。
Spring的通知是使用java编写,定义通知所应用的切点通常会使用注解或在Spring配置文件里采用XML来编写。
通过在代理类中包裹切面, Spring在运行期把切面织入到Spring管理的bean中
Spring只支持方法级别的连接点,不支持在字段上的连接点(比如说,某一个字段发生了变化做出响应的这种动作)和构造器连接点。
举例:
通过注解为类引入新的功能:
通过代理的方式,代理把委托的方法交给了另外一个类来实现,实现完了之后再交回给原来的类,实际上一个bean的实现被拆分到了多个类中。
在xml中声明切面
<aop:config> 顶层的AOP配置元素。 大多数的<aop:*>元素必须包含在<aop:config>元素内 <aop:advisor> 定义AOP通知器 <aop:declare-parents> 以透明的方式为被通知的对象引入额外的接口 <aop:pointcut> 定义一个切点 <aop:aspect> 定义一个切面 <aop:aspectj-autoproxy> 启用@AspectJ注解驱动的切面 <aop:before> 定义一个AOP前置通知 <aop:after> 定义AOP后置通知(不管被通知的方法是否执行成功) <aop:after-returning> 定义AOP返回通知 <aop:after-throwing> 定义AOP异常通知 <aop:around> 定义AOP环绕通知
XML可以吧一个POJO声明为一个切面,完成所有的Spring AOP的全部功能。
一个配置的例子如下
<bean id="as1" class="aspect.as1"></bean> 定义切面的bean <aop:config> AOP的配置都放在config下,可以定义多个aspect,对应多个切面 <aop:aspect ref="as1"> aspect定义一个切面,指向POJO的bean <aop:before pointcut="execution(* Test.T1.doo(..)))" method="Before"/> <aop:after pointcut="execution(* Test.T1.doo(..)))" method="After" /> <aop:around pointcut="execution(* Test.T1.doo(..)))" method="Around" /> <aop:after-throwing pointcut="execution(* Test.T1.doo(..)))" method="Throw"/> </aop:aspect> </aop:config> <aop:aspectj-autoproxy/> 启动自动代理
可以看到这里的PointCut都是一样的,可以定义出来一个PointCut进行简化,如下
<aop:config> <aop:aspect ref="as1"> 在这里定义了PointCut,下面就可以直接使用了,也可以定义在config标签下面,这样所有的aspect都可以使用 <aop:pointcut id="pc" expression="execution(* Test.T1.doo(..)))"/> <aop:before pointcut-ref="pc" method="Before"/> <aop:after pointcut-ref="pc" method="After" /> <aop:around pointcut-ref="pc" method="Around" /> <aop:after-throwing pointcut-ref="pc" method="Throw"/> </aop:aspect> </aop:config>