springAOP中的各种通知

  转载自http://blog.csdn.net/hao134838/article/details/53457619

在上一篇博客中我们介绍了AOP的一些基本概念,并且在博客中的Demo我们没有使用配置文件的形式来实现,在博客的结尾我们我们也抛出了那样写的问题,在这篇博客中我们就用配置文件的方式来来介绍AOP中的五大通知。

 前置通知(before):在目标方法执行之前执行

 后置通知(after):在目标方执行完成后执行,如果目标方法异常,则后置通知不再执行

 异常通知(After-throwing):目标方法抛出异常的时候执行  

 最终通知(finally);不管目标方法是否有异常都会执行,相当于try。。catch。。finally中的finally

 环绕通知(round):可以控制目标方法是否执行

 下面就通过一个栗子来总结一下这几个通知应该如何使用.

           

  上面截图就是demo的基本目录结构,先来说一下jar包,其中aspectjrt.jar和aspectjweaver.jar是springAOP配置文件形式所需要的jar包,其实这和springAOP的由来有联系,因为AOP的思想最原始就是aspect技术,只不过当时开发人员不知道这个技术干什么用,导致该项技术没有什么用武之地,但是到后来spring的作者意识到这种思想的优势的使用,加以整合提出aop的思想,使这项技术到达了巅峰。cglib是代理对象形成的另一种形式。

  和上一篇博客对比我们可以发现,我们不需要自己写拦截器,而是在配置文件中实现。

  首先来看一下配置文件:

 

[html] view plain copy
 
 print?在CODE上查看代码片派生到我的代码片
  1. <?xml version="1.0" encoding="UTF-8"?>  
  2. <beans xmlns="http://www.springframework.org/schema/beans"  
  3.        xmlns:aop="http://www.springframework.org/schema/aop"  
  4.        xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"  
  5.        xsi:schemaLocation="http://www.springframework.org/schema/beans  
  6.            http://www.springframework.org/schema/beans/spring-beans-2.5.xsd  
  7.            http://www.springframework.org/schema/aop   
  8.            http://www.springframework.org/schema/aop/spring-aop-2.5.xsd">  
  9.       <!--   
  10.           导入目标类  
  11.           导入切面  
  12.           进行aop的配置  
  13.     -->          
  14.    <bean id="personDao" class="com.itheima11.spring.aop.xml.transaction.PersonDaoImpl"></bean>  
  15.    <bean id="transaction" class="com.itheima11.spring.aop.xml.transaction.Transaction"></bean>  
  16.      
  17.     <aop:config>  
  18.     <!--   
  19.             切入点表达式  
  20.               符合切入点表达式的类要产生代理对象  
  21.               expression就是切入点表达式  
  22.               id 标示符  
  23.          -->  
  24.         <aop:pointcut   
  25.             expression="execution(* com.itheima11.spring.aop.xml.transaction.PersonDaoImpl.*(..))"   
  26.             id="perform"/>  
  27.         <aop:aspect ref="transaction">  
  28.             <!--   
  29.                 前置通知  
  30.                     1、在目标方法执行之前  
  31.                     2、前置通知中,方法有一个参数JoinPoint  
  32.              -->  
  33.               
  34.             <aop:before method="beginTransaction" pointcut-ref="perform"/>  
  35.               
  36.             <!--   
  37.                 后置通知  
  38.                    1、在目标方法执行之后  
  39.                    2、能够获取目标方法的返回值  
  40.                        returning="val" val就是通知方法中 后置通知中的参数名称  
  41.                    3、如果目标方法产生异常,则后置通知不再执行  
  42.              -->  
  43.               
  44.             <aop:after-returning method="commit" pointcut-ref="perform" returning="val"/>  
  45.               
  46.             <!--   
  47.                 异常通知  
  48.                           获取目标方法抛出的异常信息  
  49.                     throwing="ex"  
  50.              -->  
  51.             <aop:after-throwing method="throwingMethod" pointcut-ref="perform" throwing="ex"/>  
  52.             <!--  
  53.                 最终通知 
  54.              -->  
  55.             <aop:after method="finallyMethod" pointcut-ref="perform"/>  
  56.             <!--   
  57.                 环绕通知  
  58.                     能够控制目标方法的执行  
  59.                     环绕通知可以有返回值,这个返回值就是代理对象的方法的返回值  
  60.                     前置通知和后置通知只能在目标方法执行之前和之后加代码,但是不能控制目标方法的执行  
  61.              -->  
  62.             <aop:around method="aroundMethod" pointcut-ref="perform"/>  
  63.         </aop:aspect>  
  64.     </aop:config>  
  65. </beans>  


  核心类切面代码:

 

 

[html] view plain copy
 
 print?在CODE上查看代码片派生到我的代码片
  1. package com.itheima11.spring.aop.xml.transaction;  
  2.   
  3. import org.aspectj.lang.JoinPoint;  
  4. import org.aspectj.lang.ProceedingJoinPoint;  
  5.   
  6. public class Transaction {  
  7.     /**  
  8.      * 前置通知 参数:JoinPoint 连接点:客户端调用哪个方法,这个方法就是连接点  
  9.      */  
  10.     public void beginTransaction(JoinPoint joinPoint) {  
  11.         System.out.println("目标类:" + joinPoint.getTarget().getClass());  
  12.         System.out.println("目标方法的名称:" + joinPoint.getSignature().getName());  
  13.         System.out.println("目标方法的参数:" + joinPoint.getArgs().length);  
  14.         System.out.println("begin transaction");  
  15.     }  
  16.   
  17.     /**  
  18.      * 后置通知 val接收目标类的目标方法的返回值  
  19.      */  
  20.     public void commit(JoinPoint joinPoint, Object val) {  
  21.         System.out.println("返回值:" + val);  
  22.         System.out.println("commit");  
  23.     }  
  24.   
  25.     /**  
  26.      * 异常通知 不管是否目标方法是否抛出异常,都会执行这个方法,相当于finally  
  27.      */  
  28.     public void throwingMethod(JoinPoint joinPoint, Throwable ex) {  
  29.         System.out.println(ex.getMessage());  
  30.     }  
  31.   
  32.     /**  
  33.      * 最终通知  
  34.      */  
  35.     public void finallyMethod() {  
  36.         System.out.println("finally method");  
  37.     }  
  38.   
  39.     /**  
  40.      * 环绕通知 可以控制目标方法的是否执行  
  41.      */  
  42.     public Object aroundMethod(ProceedingJoinPoint joinPoint) throws Throwable {  
  43.         System.out.println("around method");  
  44.         return joinPoint.proceed();// 执行目标方法,如果不写行代码 则目标方法不会执行  
  45.     }  
  46. }  

  客户端代码

 

 

[html] view plain copy
 
 print?在CODE上查看代码片派生到我的代码片
  1. package com.itheima11.spring.aop.xml.transaction;  
  2.   
  3. import org.junit.Test;  
  4. import org.springframework.context.ApplicationContext;  
  5. import org.springframework.context.support.ClassPathXmlApplicationContext;  
  6.   
  7.   
  8. /**  
  9.  * aop的原理  
  10.  *     1、启动spring容器  
  11.  *     2、spring容器会为personDao和transaction实例化  
  12.  *     3、spring容器解析aop:config的配置  
  13.  *         当spring容器解析到切入点表达式的时候,就会把切入点表达式解析出来  
  14.  *            会让切入点表达式的类和spring容器中的类进行匹配  
  15.  *               如果匹配成功,则会为该对象创建代理对象  
  16.  *                  代理对象的方法形成=通知+目标方法  
  17.  *               如果匹配不成功,则会报错  
  18.  *     4、在客户端context.getBean时,如果当前的对象有代理对象,则返回代理对象  
  19.  *              如果没有代理对象返回对象的本身  
  20.  *     5、在spring内部会检查目标类有没有实现接口  
  21.  *           如果目标类实现了接口,则采用jdkproxy产生代理对象  
  22.  *           如果目标类没有实现接口,则采用cglibproxy产生代理对象  
  23.  * @author zd  
  24.  *  
  25.  */  
  26. public class PersonDaoTest {  
  27.     @Test  
  28.     public void testSpring(){  
  29.         ApplicationContext context =   
  30.                 new ClassPathXmlApplicationContext("applicationContext.xml");  
  31.         PersonDao personDao = (PersonDao)context.getBean("personDao");  
  32.         String s = personDao.savePerson();  
  33.         System.out.println(s);  
  34.     }  
  35. }  

  结果:

 

  

  小编在都将重要的注释写在代码中,请读者自行体会。上面这个demo就是对于springAOP中常用的几个通知的实现,在实际的场景我们需要不同的需求来运用不同的通知来实现。

  当我们对这个模式比较熟悉以后,里面比较重要是我们切入点表达式的编写,我们不在用原先的if。。else。。来实现,我们根据需求编写表达式实现。所以我们需要熟悉表达式的编写。

  在下面的博客中将会利用这些基本知识,实现具体的业务需求。

posted @ 2017-03-06 19:56  不违本心  阅读(167)  评论(0)    收藏  举报