1、概念定义spring
通知:定义了切面的"什么"和"什么时候"。express
切点:定义了切面的"何处"。用于准肯定位应该在什么地方应用切面的通知。app
切面:切面是通知和切点的集合。.net
链接点:在应用执行过程当中可以插入切面的一个点。代理
织入:将切面应用到目标对象来建立新的代理对象的过程。orm
2、使用切点选择链接点对象
在Spring AOP中,须要使用AspectJ的切点表达式语言来定义切点。Spring仅支持AspectJ切点指示器的子集。其中只有execution指
示器是惟一的执行匹配,其余的指示器都是限制匹配的。get
一、切点的编写it
示例1:execution(* com.springinaction.springidol.Instrument.play(...))
咱们使用execution()指示器选择Instrument的play()方法。方法表达式以*号隔开,标识了咱们不关心方法返回值的类型。而后,咱们制订了全限定名和方法。方法中的(...)标识切点选择任意的play()方法,不管方法入参是什么。io
示例2:execution(* com.springinaction.springidol.Instrument.play(...)) && within(com.springinaction.spriingidol.*)
咱们使用within()指示器来限制切点仅匹配com.springinaction.springidol包。
3、在XML中声明切面
一、 声明前置通知和后置通知:
声明一个audience Bean:
<bean id="audience" class="com.springinaction.springidol.Audience" />
把audience Bean声明为一个切面:
<aop : config>
<aop : aspect ref="audience">
<aop : before pointcut="execution(* com.springinaction.springidol.Performer(...))" method="takeSeats" />
<aop : before pointcut="execution(* com.springinaction.springidol.Performer(...))" method="turnOffCellPhones" />
<aop : after-returning pointcut="execution(* com.springinaction.springidol.Performer(...))" method="applaud" />
<aop : after-throwing pointcut="execution(* com.springinaction.springidol.Performer(...))" method="demandRefund" />
</aop : aspect>
</aop : config>
pointcut属性的值定义了通知应用的切点。pointcut属性的值是使用AspectJ切点表达式语法所定义的切点。
定义一个命名切点消除冗余的切点定义:
<aop : config>
<aop : aspect ref="audience">
<aop : pointcut id="performance" expression="execution(* com.springinaction.springidol.Performer(...))">
<aop : before pointcut-ref="performance" method="takeSeats" />
<aop : before pointcut-ref="performance" method="turnOffCellPhones" />
<aop : after-returning pointcut-ref="performance" method="applaud" />
<aop : after-throwing pointcut-ref="performance" method="demandRefund" />
</aop : aspect>
</aop : config>
二、声明环绕通知
这是环绕通知方法:
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.");
joinpoint.proceed(); //执行被通知的方法
long end = System.currentTimeMillis(); //表演以后
System.out.println("CLAP CLAP CLAP CLAP CLAP CLAP ");
System.out.println("The performance took " + (end - start));
}catch(Throwable t){
System.out.println("Boo! we want our money back!"); //表演失败以后
}
}
该通知方法使用了ProceedingJoinPoint做为方法的入参,该对象能让咱们在通知里调用被通知的方法。
若是咱们忘记调用proceed()方法,通知将会阻止被通知方法的调用。
在此audience切面,watchPerformance()方法包含以前4个通知方法的全部逻辑,但全部逻辑都放在一个方法中了。
声明环绕通知:
<aop : config>
<aop : aspect ref="audience">
<aop : pointcut id="performance2" expression="execution(* com.springinaction.springidol.Performer(...))">
<aop : around pointcut-ref="performance" method="watchPerformance()" />
</aop : aspect>
</aop : config>
三、为通知传递参数
有时候通知并不单单是对方法进行简单的包装,还须要检验传递给方法的参数值,这时候为通知传递参数就很是有用了。
4、注解切面
一、注解前置、后置通知:
package com.springinaction.springidol;
@Aspect
public class Audience {
@Pointcut( //定义切点
"execution(* com.springincation.springidol.Performer.perform( .. ))")
public void performance(){
}
@Before("performance()") //表演以前
public void takeseats(){
System.out.println("The audience is taking their seats.");
@Before("performance()") //表演以前
public void turnoffCellPhones(){
System.out.println("The audience is turning off their cellphones.");
@AfterReturning("performance()") //表演以后
public void applaud(){
System.out.println("CLAP CLAP CLAP CLAP CLAP");
@AfterThrowing("performance()") //表演失败以后
public void demandRefund(){
System.out.println("Boo! We want our money back!");
}
}
新的Audience类使用@AspectJ注解进行了标注。该注解标注了Audience不单单是一个POJO,仍是一个切面。
@pointCut注解用于定义一个能够在@AspectJ切面内可重用的切点。切点的名称来源于注解所应用的方法名称。所以该切点名称为performance()。performance()方法在这里是空的,该方法自己只是一个标识,供@pointCut注解依附。
二、注解环绕通知:
@Around("performance()")
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!"); } }