Spring Aop之(二)--Aop 切面声明和通知

6.3.1. 声明一个切面

有了schema的支持,切面就和常规的Java对象一样被定义成application context中的一个bean。 对象的字段和方法提供了状态和行为信息,XML文件则提供了切入点和通知信息。

切面使用<aop:aspect>来声明,backing bean(支持bean)通过 ref 属性来引用:

<aop:config>  <aop:aspect id="myAspect" ref="aBean">...  </aop:aspect></aop:config><bean id="aBean" class="...">  ...</bean>

切面的支持bean(上例中的"aBean")可以象其他Spring bean一样被容器管理配置以及依赖注入。

6.3.2. 声明一个切入点

切入点可以在切面里面声明,这种情况下切入点只在切面内部可见。切入点也可以直接在<aop:config>下定义,这样就可以使多个切面和通知器共享该切入点。

一个描述service层中表示所有service执行的切入点可以如下定义:

<aop:config>  <aop:pointcut id="businessService"expression="execution(* com.xyz.myapp.service.*.*(..))"/></aop:config>

注意切入点表达式本身使用了 Section 6.2, “@AspectJ支持” 中描述的AspectJ 切入点表达式语言。 如果你在Java 5环境下使用基于schema的声明风格,可参考切入点表达式类型中定义的命名式切入点,不过这在JDK1.4及以下版本中是不被支持的(因为依赖于 Java 5中的AspectJ反射API)。 所以在JDK 1.5中,上面的切入点的另外一种定义形式如下:

<aop:config>  <aop:pointcut id="businessService"expression="com.xyz.myapp.SystemArchitecture.businessService()"/></aop:config>

假定你有 Section 6.2.3.3, “共享常见的切入点(pointcut)定义”中说描述的 SystemArchitecture 切面。

在切面里面声明一个切入点和声明一个顶级的切入点非常类似:

<aop:config>  <aop:aspect id="myAspect" ref="aBean"><aop:pointcut id="businessService"  expression="execution(* com.xyz.myapp.service.*.*(..))"/>...  </aop:aspect></aop:config>

当需要连接子表达式的时候,'&'在XML中用起来非常不方便,所以关键字'and', 'or' 和 'not'可以分别用来代替'&', '||' 和 '!'。

注意这种方式定义的切入点通过XML id来查找,并且不能定义切入点参数。在基于schema的定义风格中命名切入点支持较之@AspectJ风格受到了很多的限制。

6.3.3. 声明通知

和@AspectJ风格一样,基于schema的风格也支持5种通知类型并且两者具有同样的语义。

6.3.3.1. 通知(Advice)

Before通知在匹配方法执行前进入。在<aop:aspect>里面使用<aop:before>元素进行声明。

<aop:aspect id="beforeExample" ref="aBean"><aop:before  pointcut-ref="dataAccessOperation"  method="doAccessCheck"/>...</aop:aspect>

这里 dataAccessOperation 是一个顶级(<aop:config>)切入点的id。 要定义内置切入点,可将 pointcut-ref 属性替换为 pointcut 属性:

<aop:aspect id="beforeExample" ref="aBean"><aop:before  pointcut="execution(* com.xyz.myapp.dao.*.*(..))"  method="doAccessCheck"/>...</aop:aspect>

我们已经在@AspectJ风格章节中讨论过了,使用命名切入点能够明显的提高代码的可读性。

Method属性标识了提供了通知的主体的方法(doAccessCheck)。这个方法必须定义在包含通知的切面元素所引用的bean中。 在一个数据访问操作执行之前(执行连接点和切入点表达式匹配),切面中的"doAccessCheck"会被调用。

6.3.3.2. 返回后通知(After returning advice)

After returning通知在匹配的方法完全执行后运行。和Before通知一样,可以在<aop:aspect>里面声明。例如:

<aop:aspect id="afterReturningExample" ref="aBean"><aop:after-returning  pointcut-ref="dataAccessOperation"  method="doAccessCheck"/>...</aop:aspect>

和@AspectJ风格一样,通知主体可以接收返回值。使用returning属性来指定接收返回值的参数名:

<aop:aspect id="afterReturningExample" ref="aBean"><aop:after-returning  pointcut-ref="dataAccessOperation"  returning="retVal"  method="doAccessCheck"/>...</aop:aspect>

doAccessCheck方法必须声明一个名字叫 retVal 的参数。 参数的类型强制匹配,和先前我们在@AfterReturning中讲到的一样。例如,方法签名可以这样声明:

public void doAccessCheck(Object retVal) {...
6.3.3.3. 抛出异常后通知(After throwing advice)

After throwing通知在匹配方法抛出异常退出时执行。在 <aop:aspect> 中使用after-throwing元素来声明:

<aop:aspect id="afterThrowingExample" ref="aBean"><aop:after-throwing  pointcut-ref="dataAccessOperation"  method="doRecoveryActions"/>...</aop:aspect>

和@AspectJ风格一样,可以从通知体中获取抛出的异常。 使用throwing属性来指定异常的名称,用这个名称来获取异常:

<aop:aspect id="afterThrowingExample" ref="aBean"><aop:after-throwing  pointcut-ref="dataAccessOperation"  thowing="dataAccessEx"  method="doRecoveryActions"/>...</aop:aspect>

doRecoveryActions方法必须声明一个名字为 dataAccessEx 的参数。 参数的类型强制匹配,和先前我们在@AfterThrowing中讲到的一样。例如:方法签名可以如下这般声明:

public void doRecoveryActions(DataAccessException dataAccessEx) {...
6.3.3.4. 后通知(After (finally) advice)

After (finally)通知在匹配方法退出后执行。使用 after 元素来声明:

<aop:aspect id="afterFinallyExample" ref="aBean"><aop:after  pointcut-ref="dataAccessOperation"  method="doReleaseLock"/>...</aop:aspect>
6.3.3.5. 通知

Around通知是最后一种通知类型。Around通知在匹配方法运行期的“周围”执行。 它有机会在目标方法的前面和后面执行,并决定什么时候运行,怎么运行,甚至是否运行。 Around通知经常在需要在一个方法执行前或后共享状态信息,并且是线程安全的情况下使用(启动和停止一个计时器就是一个例子)。 注意选择能满足你需求的最简单的通知类型(i.e.如果简单的before通知就能做的事情绝对不要使用around通知)。

Around通知使用 aop:around 元素来声明。 通知方法的第一个参数的类型必须是 ProceedingJoinPoint 类型。 在通知的主体中,调用 ProceedingJoinPointproceed() 方法来执行真正的方法。 proceed 方法也可能会被调用并且传入一个 Object[] 对象 - 该数组将作为方法执行时候的参数。 参见 Section 6.2.4.5, “环绕通知(Around Advice)” 中提到的一些注意点。

<aop:aspect id="aroundExample" ref="aBean"><aop:around  pointcut-ref="businessService"  method="doBasicProfiling"/>...</aop:aspect>

doBasicProfiling 通知的实现和@AspectJ中的例子完全一样(当然要去掉注解):

public Object doBasicProfiling(ProceedingJoinPoint pjp) throws Throwable {    // start stopwatch    Object retVal = pjp.proceed();    // stop stopwatch    return retVal;}
<aop:config proxy-target- class= " true " >
        <aop:aspect id= " aop_aspect_frisetclass "   ref= " AopAdvice ">
                <!-- 定义个After增强处理,直接指定切入点表达式,以切面 Bean 中的 Release() 方法作为增强处理方法 -->  
                <aop:around pointcut= " execution(* cn.damai.std.mypoxy.FrisetClass.*(..)) " method= " doBasicProfiling " />
                <aop:before pointcut= " execution(* cn.damai.std.mypoxy.FrisetClass.addStudent(..)) " method= " aopbeforemethod "/>
                  <aop:after pointcut= " execution(* cn.damai.std.mypoxy.FrisetClass.addStudent(..)) " method= " aopaftermethod "/>
                  <aop:after-returning pointcut= " execution(* cn.damai.std.mypoxy.FrisetClass.getStudentScores(..)) "  returning= " val " method= " aopafterreturnmethod "/>
                  <aop:after-throwing pointcut= " execution(* cn.damai.std.mypoxy.FrisetClass.getStudentScores(..)) "  throwing= " exdate "  method= " aopafterthrowmethod "/>
        </aop:aspect>
    </aop:config>

 

public Object doBasicProfiling(ProceedingJoinPoint pjp) throws Throwable {   
         //  start stopwatch   
        Object retVal = pjp.proceed();   
         if(pjp.getArgs()!= null){
             for(Object o : pjp.getArgs()){
                
                logger.debug( " 参赛= "+o);
                
            }
        }
         //  stop stopwatch   
         return retVal;
    }
     public  void aopbeforemethod(){
        logger.debug( " 执行  方法 aopbeforemethod  ");
    }
     public  void aopaftermethod(){
    
    }
     public  void aopafterreturnmethod(Object val){
        logger.debug( " 执行  方法 aopafterreturnmethod  返回值 "+val);
    }
     public  void aopafterthrowmethod(Throwable  exdate){
        logger.debug( " 执行  方法 aopafterthrowmethod  "+exdate);
    }

 

 

转载于:https://www.cnblogs.com/65702708/archive/2012/08/20/2647793.html

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值