开源框架spring学习之道:AOP的深刻理解

Java代码   收藏代码
  1. 开源框架spring详解-----AOP的深刻理解  
  2.   
  3. AOP的理解  
  4.   
  5.          1、AOP的概述  
  6.                    AOP是一种不同于OOP(面向对象编程)的编程模式,它不是OOP的替代,而是对OOP的一种有益补充。  
  7.          2、spring AOP的原理  
  8.          3、spring AOP的实现  
  9.                    在spring2.5中,常用的AOP实现方式有两种。第一种是基于xml配置文件方式的实现,第二种是基于注解方式的实现。  
  10.                    接下来,以具体的是理智讲解这两种方式的使用。  
  11.    
  12. Java代码    
  13. package com.zxf.service;    
  14.     
  15. /**  
  16.  * 业务逻辑接口  
  17.  * @author z_xiaofei168  
  18.  */    
  19. public interface AccountService {    
  20.     public void save(String loginname, String password);    
  21. }    
  22.     
  23. 它的实现类    
  24.     
  25. package com.zxf.service;    
  26. import com.zxf.dao.AccountDao;    
  27.     
  28. /**  
  29.  * AccountService的实现类  
  30.  * @author z_xiaofei168  
  31.  */    
  32. public class AccountServiceImpl implements AccountService {    
  33.     private  AccountDao accountDao;    
  34.         
  35.     public AccountServiceImpl() {}    
  36.         
  37.     /** 带参数的构造方法 */    
  38.     public AccountServiceImpl(AccountDao accountDao){    
  39.         this.accountDao = accountDao;    
  40.     }    
  41.         
  42.     public void save(String loginname, String password) {    
  43.         accountDao.save(loginname, password);    
  44.         throw new RuntimeException("故意抛出一个异常。。。。");    
  45.     }    
  46.         
  47.     /** set方法 */    
  48.     public void setAccountDao(AccountDao accountDao) {    
  49.         this.accountDao = accountDao;    
  50.     }    
  51. }    
  52.      
  53.      对于业务系统来说,AccountServiceImpl类就是目标实现类,它的业务方法,如save()方法的前后或代码会出现异常的地方都是AOP的连接点。  
  54.    
  55. 下面是日志服务类的代码:  
  56.    
  57.    
  58. Java代码    
  59. package com.zxf.aspect;    
  60.     
  61. import org.aspectj.lang.JoinPoint;    
  62. import org.aspectj.lang.ProceedingJoinPoint;    
  63.     
  64. /**  
  65.  * 日志切面类  
  66.  * @author z_xiaofei168  
  67.  */    
  68. public class LogAspect {    
  69.     
  70.     //任何通知方法都可以将第一个参数定义为 org.aspectj.lang.JoinPoint类型     
  71.     public void before(JoinPoint call) {    
  72.         //获取目标对象对应的类名    
  73.         String className = call.getTarget().getClass().getName();    
  74.         //获取目标对象上正在执行的方法名    
  75.         String methodName = call.getSignature().getName();    
  76.             
  77.         System.out.println("前置通知:" + className + "类的" + methodName + "方法开始了");    
  78.     }    
  79.         
  80.     public void afterReturn() {    
  81.         System.out.println("后置通知:方法正常结束了");    
  82.     }    
  83.         
  84.     public void after(){    
  85.         System.out.println("最终通知:不管方法有没有正常执行完成,一定会返回的");    
  86.     }    
  87.         
  88.     public void afterThrowing() {    
  89.         System.out.println("异常抛出后通知:方法执行时出异常了");    
  90.     }    
  91.         
  92.     //用来做环绕通知的方法可以第一个参数定义为org.aspectj.lang.ProceedingJoinPoint类型    
  93.     public Object doAround(ProceedingJoinPoint call) throws Throwable {    
  94.         Object result = null;    
  95.         this.before(call);//相当于前置通知    
  96.         try {    
  97.             result = call.proceed();    
  98.             this.afterReturn(); //相当于后置通知    
  99.         } catch (Throwable e) {    
  100.     
  101.             this.afterThrowing();  //相当于异常抛出后通知    
  102.             throw e;    
  103.         }finally{    
  104.             this.after();  //相当于最终通知    
  105.         }    
  106.             
  107.         return result;    
  108.     }    
  109. }    
  110.    
  111.      这个类属于业务服务类,如果用AOP的术语来说,它就是一个切面类,它定义了许多通知。Before()、afterReturn()、after()和afterThrowing()这些方法都是通知。  
  112.    
  113. <1>.基于xml配置文件的AOP实现  
  114.    
  115.          这种方式在实现AOP时,有4个步骤。  
  116.    
  117. Xml代码    
  118. <?xml version="1.0" encoding="UTF-8"?>    
  119. <beans xmlns="http://www.springframework.org/schema/beans"    
  120.         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"    
  121.         xmlns:aop="http://www.springframework.org/schema/aop"    
  122.         xsi:schemaLocation="    
  123.             http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-2.5.xsd    
  124.             http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-2.5.xsd>    
  125.     
  126.     <bean id="accountDaoImpl" class="com.zxf.dao.AccountDaoImpl"/>    
  127.         
  128.     <bean id="accountService" class="com.zxf.service.AccountServiceImpl">    
  129.         <property name=" accountDaoImpl " ref=" accountDaoImpl "/>    
  130.     </bean>    
  131.     
  132.     <!-- 日志切面类 -->    
  133.     <bean id="logAspectBean" class="com.zxf.aspect.LogAspect"/>    
  134.         
  135.     <!-- 第1步: AOP的配置 -->    
  136.     <aop:config>    
  137.         <!-- 第2步:配置一个切面 -->    
  138.         <aop:aspect id="logAspect" ref="logAspectBean">    
  139.             <!-- 第3步:定义切入点,指定切入点表达式 -->    
  140.             <aop:pointcut id="allMethod"     
  141.                 expression="execution(* com.zxf.service.*.*(..))"/>    
  142.                     
  143.             <!-- 第4步:应用前置通知 -->    
  144.             <aop:before method="before" pointcut-ref="allMethod" />    
  145.             <!-- 第4步:应用后置通知 -->    
  146.             <aop:after-returning method="afterReturn" pointcut-ref="allMethod"/>    
  147.             <!-- 第4步:应用最终通知 -->    
  148.             <aop:after method="after" pointcut-ref="allMethod"/>    
  149.             <!-- 第4步:应用抛出异常后通知 -->    
  150.             <aop:after-throwing method="afterThrowing" pointcut-ref="allMethod"/>    
  151.                 
  152.             <!-- 第4步:应用环绕通知 -->    
  153.             <!--    
  154.             <aop:around method="doAround" pointcut-ref="allMethod" />   
  155.              -->    
  156.         </aop:aspect>    
  157.     </aop:config>    
  158. </beans>    
  159.    
  160.    
  161.     上述配置针对切入点应用了前置、后置、最终,以及抛出异常后通知。这样在测试执行AccountServiceImpl类的save()方法时,控制台会有如下结果输出。  
  162.    
  163. 前置通知:com.zxf.service.AccountServiceImpl类的save方法开始了。  
  164. 针对MySQL的AccountDao实现中的save()方法。  
  165. 后置通知:方法正常结束了。  
  166. 最终通知:不管方法有没有正常执行完成,一定会返回的。  
  167.    <2>基于注解的AOP的实现  
  168.    
  169.     首先创建一个用来作为切面的类LogAnnotationAspect,同时把这个类配置在spring的配置文件中。  
  170.         在spring2.0以后引入了JDK5.0的注解Annotation的支持,提供了对AspectJ基于注解的切面的支持,从而 更进一步地简化AOP的配置。具体的步骤有两步。  
  171.    
  172. Spring的配置文件是如下的配置:  
  173.    
  174.    
  175. Xml代码    
  176. <?xml version="1.0" encoding="UTF-8"?>    
  177. <beans xmlns="http://www.springframework.org/schema/beans"    
  178.         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"    
  179.         xmlns:aop="http://www.springframework.org/schema/aop"    
  180.         xsi:schemaLocation="    
  181.             http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-2.5.xsd    
  182.             http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-2.5.xsd>    
  183.     
  184.     <bean id="accountDao" class="com.zxf.dao.AccountDaoImpl"/>    
  185.     <bean id="accountService" class="com.zxf.service.AccountServiceImpl">    
  186.         <property name="accountDao" ref="accountDao"/>    
  187.     </bean>    
  188.     <!-- 把切面类交由Spring容器来管理 -->    
  189.     <bean id="logAspectBean" class="com.zxf.aspect.LogAnnotationAspect"/>    
  190.     <!-- 启用spring对AspectJ注解的支持 -->    
  191.     <aop:aspectj-autoproxy/>    
  192. </beans>    
  193.    
  194. 这是那个切面的类LogAnnotationAspect  
  195. Java代码    
  196. package com.zxf.aspect;    
  197.     
  198. import org.aspectj.lang.JoinPoint;    
  199. import org.aspectj.lang.ProceedingJoinPoint;    
  200. import org.aspectj.lang.annotation.After;    
  201. import org.aspectj.lang.annotation.AfterReturning;    
  202. import org.aspectj.lang.annotation.AfterThrowing;    
  203. import org.aspectj.lang.annotation.Aspect;    
  204. import org.aspectj.lang.annotation.Before;    
  205. import org.aspectj.lang.annotation.Pointcut;    
  206.     
  207. /**  
  208.  * 日志切面类  
  209.  */    
  210. @Aspect  //定义切面类    
  211. public class LogAnnotationAspect {    
  212.     @SuppressWarnings("unused")    
  213.     //定义切入点    
  214.     @Pointcut("execution(* com.zxf.service.*.*(..))")    
  215.     private void allMethod(){}    
  216.         
  217.     //针对指定的切入点表达式选择的切入点应用前置通知    
  218.     @Before("execution(* com. zxf.service.*.*(..))")    
  219.     public void before(JoinPoint call) {    
  220.             
  221.         String className = call.getTarget().getClass().getName();    
  222.         String methodName = call.getSignature().getName();    
  223.             
  224.         System.out.println("【注解-前置通知】:" + className + "类的"     
  225.                 + methodName + "方法开始了");    
  226.     }    
  227.     //访问命名切入点来应用后置通知    
  228.     @AfterReturning("allMethod()")    
  229.     public void afterReturn() {    
  230.         System.out.println("【注解-后置通知】:方法正常结束了");    
  231.     }    
  232.         
  233.     //应用最终通知    
  234.     @After("allMethod()")    
  235.     public void after(){    
  236.         System.out.println("【注解-最终通知】:不管方法有没有正常执行完成,"     
  237.                 + "一定会返回的");    
  238.     }    
  239.         
  240.     //应用异常抛出后通知    
  241.     @AfterThrowing("allMethod()")    
  242.     public void afterThrowing() {    
  243.         System.out.println("【注解-异常抛出后通知】:方法执行时出异常了");    
  244.     }    
  245.         
  246.     //应用周围通知    
  247.     //@Around("allMethod()")    
  248.     public Object doAround(ProceedingJoinPoint call) throws Throwable{    
  249.         Object result = null;    
  250.         this.before(call);//相当于前置通知    
  251.         try {    
  252.             result = call.proceed();    
  253.             this.afterReturn(); //相当于后置通知    
  254.         } catch (Throwable e) {    
  255.             this.afterThrowing();  //相当于异常抛出后通知    
  256.             throw e;    
  257.         }finally{    
  258.             this.after();  //相当于最终通知    
  259.         }    
  260.             
  261.         return result;    
  262.     }    
  263. }    

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值