Spring学习心得(18)-- 通知的种类

通知的种类:

1、前置通知
2、后置通知
3、最终通知
4、异常通知
5、环绕通知

在之前的例子中,我们使用到了before(前置通知)和after-returning(后置通知)。还有after最终通知(最终通知)和around(环绕通知)。


前置通知和后置通知已经在前面的帖子涉及到,这里只做总结:

前置通知:
*在目标方法执行前执行
*所以目标方法如果出现异常,这里还会执行
后置通知:
*在目标方法执行后执行
*如果目标方法出现异常,这里不会执行
*可以接收由目标方法的返回值

配置如下: 

*注意:这些配置是在标签里面定义的

 <!-- 
        aop配置
      -->
      <aop:config>
        <!-- 
            aop:pointcut 指的是切入点判断,我们昨天使用的是在拦截器中使用if方法,具体内容可以看上一篇帖子
                         但是考虑到如果有很多个dao,那么就要判断很多次,效率会降低

            expression   指的是切入点的表达式,该表达式的作用就是调用哪些方法,
                         一般都使用简写形式,即只需标明 (* *(..)),
                         第一个*是指返回值类型,第二个是指方法全名
                         括号中的.. 类似于可变参数的作用, 
                         在这里我们执行的是目标类PersonDaoImpl 的某个方法

            id          是指对这个切入点的唯一标识符
         -->
        <aop:pointcut expression="execution(* cn.ansel.aopExample.PersonDaoImpl.*(..))" id="perform"/>
        <!-- 
            aop:aspect  定义切面,因为要把相应的类定义到配置文件中才算是切面

            id          该切面的唯一标识符   

            ref         该切面的引用对象
         -->


        <aop:aspect id="mytransaction" ref="myTransaction">
             <!-- 
                method          指对应切面中的通知,这里的method对应的切面,就是上级标签ref对应的切面
                pointcut-ref    指该值对应的切入点表达式
                before          指前置通知的配置
              -->
            <aop:before method="before" pointcut-ref="perform" />
            <!-- 
                aop:after-returning   指后置通知的定义标签
                returning             指目标方法中返回值的名称
             -->
            <aop:after-returning method="afterReturning" pointcut-ref="perform" returning="var"/>
        </aop:aspect>
      </aop:config>

/目标类的代码:
public class PersonDaoImpl extends hibernateUtil  {

    public String savePerson(Person person) {

        System.out.println("targetMethod");
        //返回字符串
        return "the object form targetMethod";
    }
}


//切面中方法:
public class MyTransaction extends hibernateUtil{

    public void before(){
        System.out.println("beforeMethod");
    }
    public void afterReturning(Object var){
        //接收目标类返回值,并输出
        System.out.println(var);
    }
}



//测试类的方法:
public class testAOP {
    @Test
    public void test(){
        //加载spring配置文件
        ApplicationContext applicationContext=new ClassPathXmlApplicationContext("cn/ansel/aopExample/applicationContext.xml");
        //得到目标类
        PersonDaoImpl dao=(PersonDaoImpl) applicationContext.getBean("personDaoImpl");
        //存入数据
        Person person=new Person();
        person.setPname("ansel");
        person.setPdescription("fine");
        dao.savePerson(person);
    }
}

运行结果: 
这里写图片描述

*主要注意的是:在配置文件中配置的returning参数的名字,必须与切面的后置通知中的传入参数的名字要一致,否则会报错 
example:

 //我把后置通知中的传入参数名字改成sth,然后再输出sth
    public void afterReturning(Object sth){
        //接收目标类返回值,并输出
        System.out.println(sth);
    }

此时,目标方法不变,继续执行测试类的运行结果,有一大堆报错,于是我标注了重要的提示: 
这里写图片描述

最终通知:
直接看配置:在切面中,直接写一个新的方法作为最终通知,然后在配置文件中配置
 //最终通知
    public void after(){
        System.out.println("after");
    }
<!--
    配置文件中的配置,在刚刚后置通知的后面加上这一行代码

    after  指最终通知,其他没有什么不同,需要注意的是,配置每一个通知的时候,都不要忘记了pointcut-ref的引用
-->
<aop:after method="after" pointcut-ref="perform" />

目标方法不变,运行结果: 
这里写图片描述

要看最终通知有什么真正的效果,由于最终的名字,想到了Java中有一个finally代码块,所以我们在目标方法加一个异常:

public class PersonDaoImpl extends hibernateUtil  {

    public String savePerson(Person person) {
        //添加一个异常,用来测试最终通知的作用
        int a=1/0;
        System.out.println("targetMethod");
        //返回字符串
        return "the object form targetMethod";
    }
}

运行结果:毫无意外的报了异常,可是最终通知运行了,后置通知没有运行,目标方法也没有运行 
这里写图片描述

由此可以看出,最终通知跟finally代码块的作用是一致的,finally也是最终的意思好吧。。

异常通知:
该通知的作用主要用于返回目标方法中出现的异常。配置如下:

在切面中增加这样一个方法:

 /**
     * 异常通知
     * @param ex 参数为目标方法中返回的异常,改名字与配置文件中的throwing配置的名字要一致
     *           否则跟上面返回值一样报错
     */
    public void throwing(Throwable ex){
        System.out.println(ex.getMessage());
    }
<!-- 
    配置文件:
                aop:after-throwing 指异常通知,接收目标方法发生的异常
                throwing                指目标方法抛出异常的引用名
-->
            <aop:after-throwing method="throwing" pointcut-ref="perform" throwing="ex"/>

测试类不变,运行结果为: 
这里写图片描述

环绕通知:
用来控制目标方法是否执行。
//ProceedingJoinPoint 该类有一个proceed方法,用来控制目标方法是否执行。 在这里我们先不用那个方法,看看目标方法是否会执行
public void around(ProceedingJoinPoint joinPoint){
        System.out.println("around");
    }
配置文件:

  <!-- 
                aop:around  配置环绕通知
         -->
            <aop:around method="around" pointcut-ref="perform"/>

运行结果: 
这里写图片描述 
在目标方法中有

int a=1/0l
 
 
  • 1
  • 1

但是没有报错,并且只是执行了前置通知和环绕通知。这时候最终通知也不执行了。 
但是当我调用ProceedingJoinPoint类的proceed方法时,这里先把异常代码注释掉: 
目标类代码:

public class PersonDaoImpl extends hibernateUtil  {

    public String savePerson(Person person) {
        //添加一个异常,用来测试最终通知的作用
//      int a=1/0;
        System.out.println("targetMethod");
        //返回字符串
        return "the object form targetMethod";
    }
}
环绕通知的代码该为:

public void around(ProceedingJoinPoint joinPoint) throws Throwable{
        System.out.println("around");
        //调用proceed方法
        joinPoint.proceed();
    }

运行结果为: 
这里写图片描述  
全部配置的通知都执行了,除了异常通知。










评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值