AOP的深刻理解实例讲解spring

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