这周开始着手的AOP,因为同时在弄数学建模和计算机网络的复习,所以跟着书和视频只学了一点点。
面向切面的Spring(AOP)
概念:
AOP:Aspect Oriented Programming的缩写,意为:面向切面编程,通过预编译方式和运行期间动态代理实现程序功能的统一维护的一种技术。主要的功能是:日志记录、性能统计、安全控制、事务处理、异常处理等等。
分布于应用中多处的功能被称为横切关注点。
面向切面编程(AOP)所要解决的问题是将横切关注点与业务逻辑相分离。
tip:AspectJ面向切面的一个框架
关于几个概念(个人理解):
通知(Advice):通知定义了切面是什么以及何时使用
切点(Pointcut):通知应用于哪些类
连接点(Joinpoint):通知应用于类中的哪些位置
切面(Aspect):通知和切点的结合
引入(Introduction):引入允许我们向现有的类添加新的方法或属性
AOP框架的基本功能:创建切点来定义切面织入的连接点(好绕。。)
五种Advice的类型:
Before Advice:在某连接点(join point)之前执行的通知,但不能阻止连接点前的执行
After returning Advice:在某连接点正常完成后执行的通知
After throwing Advice:在方法抛出异常退出时执行的通知
After Advice:在某连接点退出的时候执行的通知(无论是正常返回还是异常返回)
Around Advice:包围一个连接点
Spring AOP原理:
Spring在运行期将切面织入到Spring管理的Bean中,代理类封装了目标类(也就是要执行的类),并拦截被通知的方法的调用,再将调用转发给真正的目标Bean。当拦截到方法调用时,在调用目标Bean方法之前,代理会执行切面逻辑。
tip:Spring只支持方法连接点,也就是说Spring只能拦截方法,缺少对字段连接点的支持,无法让我们创建细粒度的通知。
Spring借助AspectJ的切点表达式语言定义Spring切面
在Spring支持的指示器中,只有execution指示器是唯一的执行匹配,而其他的指示器都是用于限制匹配。
tip:DRY原则(不要重复你自己)
六月四号更新线(颜色好浅。。)
(期末到了,要开始预习了)
在XML中声明切面
前面我们用名为Spring Idol的选秀节目来掩饰依赖注入,在这里我们创建一个观众(Audience)类。
//为选秀节目定义观众
package springinaction.springidol;
public class Audience {
public void takeSeats(){//表演之前
System.out.println("The audience is taking their seats!");
}
public void turnOffCellPhones(){//表演之前
System.out.println("The audience is turning off their cellphones!");
}
public void applaud(){//表演之后
System.out.println("CLAP CLAP CLAP CLAP CLAP !");
}
public void demandRefund(){//表演失败之后
System.out.println("Boo! We want our money back!");
}
利用XML配置文档把它注册成为Spring引用上下文的一个Bean:
<bean id="audience"
class="com.springinaction.springidol.Audience"/>
使用Spring的AOP配置元素声明一个audience切面
<aop:config>
<aop:aspect ref="audience">
<aop:before pointcut=
"execution(* com.springinaction.springidol.Performer.perform(..))"
method="takeSeats"/>
<aop:before pocincut=
"execution(* com.springinaction.springidol.Performer.perform(..))"
method="turnOffCellPhones"/>
<aop:after-returning poincut=
"execution(* com.springianction.springidol.Performer.perform(..))"
method="applaud"/>
<aop:after-throwing pointcut=
"execution(* com.springianction.springidol.Performer.perform(..))"
method="demandRefund"/>
</aop:aspect>
</aop:config>
注意通知元素中的pointcut属性的值都是一样的,这是因为所有的通知都是引用到相同的切点上。为避免重复定义切点,使用<aop:pointcut>
元素定义一个命名切点。
<aop:config>//定义一个命名切点消除冗余的切点定义
<aop:aspect ref="audience">
<aop:pointcut id="performance" expression=
"execution(* com.springinaction.springidol.Performer.perform(..))"/> //定义切点
<aop:before pointcut-ref="performance" method="takeSeats"/>
<aop:before pointcut-ref="performance" method="turnOffcellPhones"/>
<aop:before pointcut-ref="performance" method="applaud"/>
<aop:before pointcut-ref="performance" method="demandRefund"/>
</aop:aspect>
</aop:config>
现在切点在一个地方定义了,并且被多个通知元素所引用,同时修改所有的通知元素,用point-ref属性来应用这个命名切点。
声明环绕通知
相对于前置通知和后置通知,环绕通知可以完成之前前置通知和后置通知所实现的相同的功能,但是优势在于只需要在一个方法中实现。
//AOP环绕通知
public void watchPerformance(ProceedingJoinPoint joinpoint){
try{
System.out.println("The audience is taking their seats!");
System.out.println("The audience is turning off their cellphones!");//表演之前
long start = System.currentTimeMillis();
joinpoint.proceed();//执行被通知方法
long end = System.currentTimeMillis();
System.out.println("CLAP CLAP CLAP CLAP CLAP!");//表演之后
System.out.println("The performance took"+(end-start)+"milliseconds.");
}
catch (Throwable t){
System.out.println("Boo! We want our money back!");//表演失败之后
}
}
(未完)