zoukankan      html  css  js  c++  java
  • 【转-整理】Spring的aop原理

    相信只要使用过Spring框架的,大家对于AOP都不陌生,尤其提起它就能立刻随口说出,一般用在日志处理、异常处理、权限验证等方面。但刚开始 接触难免会有各种各样的疑惑,今天抽时间,按照之前的理解整理了一份关于Spring AOP的简单教程,希望能够帮助大家尽快的了解它的实现过程及原理。首先来明确几个概念:

    • JointPoint

    系统在运行之前,AOP的功能模块需要织入到OOP的功能模块中。要进行这种织入过程,需要知道在系统的哪些功能点上进行织入操作,这些将要在其上 进行织入操作的系统功能点就称为JointPoint。如某方法调用的时候或者处理异常的时候,在Spring AOP中,一个连接点总是表示一个方法的执行。常见的几种类型的JoinPoint:

    Ø 方法调用:当某个方法被调用的时候所处的程序执行点;

    Ø 方法执行:该类型表示的是某个方法内部执行开始时的点,应该与方法调用相区分;

    Ø 构造方法调用:程序执行过程中对某个对象调用其构造方法进行初始化时的点;

    Ø 构造方法执行:它与构造方法调用关系如同方法调用与方法执行间的关系;

    Ø 字段设置:对象的某个属性通过setter方法被设置或直接被设置的执行点;

    Ø 字段获取:某个对象相应属性被访问的执行点;

    Ø 异常处理执行:某些类型异常抛出后,对应的异常处理逻辑执行点;

    Ø 类初始化:类中某些静态类型或静态块的初始化时的执行点。

    • Pointcut

    Pointcut代表的是JoinPoint的表述方式。在将横切逻辑织入当前系统的过程中,虽然知道需要在哪些功能点上织入AOP的功能模块,但 需要一种表达方法。Pointcut和一个切入点表达式关联,并在满足这个切入点的Joinpoint上运行。目前通常使用的Pointcut方式有以下 几种:

    Ø 直接指定Joinpoint所在的方法名称;

    Ø 正则表达式,Spring的AOP支持该种方式;

    Ø 使用特定的Pointcut表述语言,Spring 2.0后支持该方式。

    • Advice

    Advice是单一横切关注点逻辑的载体,它代表将会织入到JoinPoint的横切逻辑。在切面的某个特定的连接点上执行的逻辑。根据它在Joinpoint位置执行时机的差异或完成功能的不同,可分为以下几种形式:

    Ø Before Advice:在Joinpoint指定位置之前执行的Advice类型,可以采用它来做一些系统的初始化工作,如设置系统初始值,获取必要系统资源等。

    Ø After Advice:在相应连接点之后执行的Advice类型,它还可以细分为以下三种:

    ² After Returning Advice:只有当前Joinpoint处执行流程正常完成后,它才会执行;

    ² After throwing Advice:在当前Joinpoint执行过程中抛出异常的情况下会执行;

    ² After Advice:该类型的Advice不管JoinPoint处执行流程是正常还是抛出异常都会执行。

    Ø Around Advice:对附加其上的Joinpoint进行包裹,可以在joinpoint之前和之后都指定相应的逻辑,甚至中断或忽略joinpoint处原来程序流程的执行。

    •  Aspect

    它是对系统中横切关注点逻辑进行模块化封装的AOP概念实体,它可以包含多个Pointcut以及相关的Advice定义。

    •  织入器

    经过织入过程后,以Aspect模块化的横切关注点才会集成到oop的现存系统中,而完成织入过程实体称为织入器。Spring中使用一组类来完成最终的织入操作,ProxyFactory类是Spring AOP最通用的织入器。

    •  目标对象

    符合Pointcut所指定的条件,将在织入过程中被织入横切逻辑的对象,称之为目标对象。

    单看上述的概念,可能会觉得有点眼花缭乱,其实通过一个简单的AOP的实例即可以帮助我们很快的了解其内部的机制。其实对于方法拦截有不同的实现方 式,常用的即有直接采用Spring提供的各种Advice进行拦截,另一种则是采用MethodInterceptor方式进行拦截。

    Spring提供的Advice拦截方式

    定义一个逻辑接口IBusinessLogic:

    1. package com.wow.asc.aop;  
    2.   
    3. public interface IBusinessLogic {  
    4.   
    5.     public void foo();  
    6.   
    7.     public void bar() throws BusinessLogicException;  
    8.       
    9.     public long time();  
    10. }  

    其中有一个BusinessLogicException异常,它用于后面对于ThrowsAdvice进行检验的实例,在此定义为:

    1. package com.wow.asc.aop;  
    2.   
    3. public class BusinessLogicException extends Exception {  
    4.   
    5. }  

    对于该业务逻辑的实现BusinessLogic,如下所示:

    1. package com.wow.asc.aop;  
    2.   
    3. public class BusinessLogic implements IBusinessLogic {  
    4.     @Override  
    5.     public void foo() {  
    6.         System.out.println("Inside BusinessLogic.foo()");  
    7.     }  
    8.     @Override  
    9.     public void bar() throws BusinessLogicException {  
    10.         System.out.println("Inside BusinessLogic.bar()");  
    11.         throw new BusinessLogicException();  
    12.     }  
    13.      /*  
    14.      * 返回该方法执行的时间 
    15.      */  
    16.     @Override  
    17.     public long time() {  
    18.         System.out.println("Inside BusinessLogic.time()");  
    19.         long startTime = System.currentTimeMillis();  
    20.         for(int i = 0; i < 100000000; i++);  
    21.         long endTime = System.currentTimeMillis();  
    22.           
    23.         return (endTime - startTime);  
    24.     }  
    25. }  

    在完成上述业务逻辑编码后,接下来将进行更多的横切插入点的设计,如在方法执行前或返回时、抛出异常时进行各种处理。对于Advice的写法如下所示:

    1. package com.wow.asc.aop;  
    2.   
    3. import java.lang.reflect.Method;  
    4. import org.springframework.aop.MethodBeforeAdvice;  
    5. /* 
    6. * 表示一个在方法执行前进行拦截的一个Advice 
    7.  */  
    8. public class TracingBeforeAdvice implements MethodBeforeAdvice {  
    9.     @Override  
    10.     public void before(Method method, Object[] args, Object target) throws Throwable {  
    11.         System.out.println("execute before (by " + method.getDeclaringClass().getName() + "." + method.getName() + ")");  
    12.     }  
    13. }  
    14.   
    15. package com.wow.asc.aop;  
    16.   
    17. import java.lang.reflect.Method;  
    18. import org.springframework.aop.AfterReturningAdvice;  
    19. /* 
    20.  * 表示一个在方法返回时进行拦截的Advice 
    21. */  
    22. public class TracingAfterAdvice implements AfterReturningAdvice {  
    23.     @Override  
    24.     public void afterReturning(Object returnValue, Method method, Object[] args, Object target) throws Throwable {  
    25.         System.out.println(method.getDeclaringClass().getName() + "." + method.getName() + "spend time: " + returnValue);  
    26.         System.out.println("execute after (by " + method.getDeclaringClass().getName() + "." + method.getName() + ")");  
    27.     }  
    28. }  
    29.   
    30. package com.wow.asc.aop;  
    31.   
    32. import java.lang.reflect.Method;  
    33. import org.springframework.aop.ThrowsAdvice;  
    34. /* 
    35.  * 表示一个异常抛出时进行拦截的Advice 
    36. */  
    37. public class TracingThrowsAdvice implements ThrowsAdvice {  
    38.       
    39.     public void afterThrowing(Method method, Object[] args, Object target, Throwable subclass) {  
    40.          System.out.println( "Logging that a " + subclass + "Exception was thrown.");  
    41.       }  
    42. }  

    在设计完上述的代码及逻辑后,即可以通过applicationContext.xml将上述类进行组合,在装配过程中即可明确哪个类的哪些方法需要被拦截,及拦截前、后会做哪些事情。具体的配置示例:

    1. <?xml version="1.0" encoding="UTF-8"?>  
    2. <beans xmlns="http://www.springframework.org/schema/beans"  
    3.     xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:aop="http://www.springframework.org/schema/aop"  
    4.     xmlns:tx="http://www.springframework.org/schema/tx" xmlns:context="http://www.springframework.org/schema/context"  
    5.     xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-2.5.xsd  
    6.         http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-2.5.xsd  
    7.         http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-2.5.xsd  
    8.         http://www.springframework.org/schema/context http://localhost:8080/schema/www.springframework.org/schema/context/spring-context-2.5.xsd">  
    9.     <bean id="businessLogic" class="com.wow.asc.aop.BusinessLogic" />  
    10.     <bean id="businessLogicBean" class="org.springframework.aop.framework.ProxyFactoryBean">  
    11.         <property name="proxyInterfaces">  
    12.             <value>com.wow.asc.aop.IBusinessLogic</value>  
    13.         </property>  
    14.         <property name="target">  
    15.             <ref local="businessLogic"/>   
    16.         </property>  
    17.         <property name="interceptorNames">  
    18.             <list>  
    19.                 <value>theTracingBeforeAdvisor</value>  
    20.                     <value>theTracingAfterAdvisor</value>  
    21.                     <value>theTracingThrowsAdvisor</value>  
    22.             </list>  
    23.         </property>  
    24.     </bean>  
    25.       
    26.     <bean id="theTracingBeforeAdvisor" class="org.springframework.aop.support.RegexpMethodPointcutAdvisor">  
    27.         <property name="advice">  
    28.             <ref local="theTracingBeforeAdvice"/>  
    29.         </property>  
    30.         <property name="pattern">  
    31.             <value>.*</value>  
    32.         </property>  
    33.     </bean>  
    34.     <bean id="theTracingAfterAdvisor" class="org.springframework.aop.support.RegexpMethodPointcutAdvisor">  
    35.         <property name="advice">  
    36.             <ref local="theTracingAfterAdvice"/>  
    37.         </property>  
    38.         <property name="pattern">  
    39.             <value>.*time.*</value>  
    40.         </property>  
    41.     </bean>  
    42.     <bean id="theTracingThrowsAdvisor" class="org.springframework.aop.support.RegexpMethodPointcutAdvisor">  
    43.         <property name="advice">  
    44.             <ref local="theTracingThrowsAdvice"/>  
    45.         </property>  
    46.         <property name="pattern">  
    47.             <value>.*bar.*</value>  
    48.         </property>  
    49.     </bean>  
    50.     <bean id="theTracingBeforeAdvice" class="com.wow.asc.aop.TracingBeforeAdvice"/>  
    51.     <bean id="theTracingAfterAdvice" class="com.wow.asc.aop.TracingAfterAdvice"/>  
    52.     <bean id="theTracingThrowsAdvice" class="com.wow.asc.aop.TracingThrowsAdvice"/>  
    53. </beans>  

             通过上述的配置,我们可以看出我们将IBusinessLogic做为代理接口,同时它的真正的目标类是BusinesssLogic。同时会对所有进入 方法之前采用TracingBeforeAdvice进行拦截,进行方法前的预处理;对time方法采用TracingAfterAdvice进行拦截, 进行方法返回后的处理;对于bar则采用TracingThrowsAdvice进行拦截,当方法返回BusinessLogicException时进 行相应的处理。

             在配置完上述类的依赖关系及需要拦截的方法后,即可以编写客户端程序来调用,查看它的运行机制。客户端调用代码:

    1. package com.wow.asc.test;  
    2.   
    3. import org.springframework.context.ApplicationContext;  
    4. import org.springframework.context.support.ClassPathXmlApplicationContext;  
    5. import com.wow.asc.aop.BusinessLogicException;  
    6. import com.wow.asc.aop.IBusinessLogic;  
    7.   
    8. public class AOPTest {  
    9.     public static void main(String[] args) {  
    10.         ApplicationContext ac = new ClassPathXmlApplicationContext("applicationContext.xml");  
    11.         IBusinessLogic ibl = (IBusinessLogic)ac.getBean("businessLogicBean");  
    12.         ibl.foo();  
    13.         try {  
    14.             ibl.bar();  
    15.         } catch (BusinessLogicException e) {  
    16.             System.out.println("Caught BusinessLogicException");  
    17.         }  
    18.         ibl.time();  
    19.     }  
    20. }  

            通过运行结果来详细的了解下,看是否真正的如上所述,会在方法前、后及异常抛出时能够拦截并进行相应处理。结果如下:

    1. 1、execute before (by com.wow.asc.aop.IBusinessLogic.foo)  
    2. 2、Inside BusinessLogic.foo()  
    3. 3、execute before (by com.wow.asc.aop.IBusinessLogic.bar)  
    4. 4、Inside BusinessLogic.bar()  
    5. 5、Logging that a com.wow.asc.aop.BusinessLogicExceptionException was thrown.  
    6. 6、Caught BusinessLogicException  
    7. 7、execute before (by com.wow.asc.aop.IBusinessLogic.time)  
    8. 8、Inside BusinessLogic.time()  
    9. 9、com.wow.asc.aop.IBusinessLogic.timespend time: 46  
    10. 10、execute after (by com.wow.asc.aop.IBusinessLogic.time)  

            其实通过1、3、7行可以非常清晰的了解到,每个方法在执行前都被TracingBeforeAdvice拦截到,并执行了预处理。5、6行表示当调用的 是bar方法时,会被TracingThrowsAdvice拦截,当有异常抛出时,会执行相应的处理;8、9、10行则表示当调用的是time方法,返 回时会被TracingAfterAdvice拦截,对其返回值进行处理。

    MethodInterceptor拦截方式

            采用该种方式进行拦截,需要实现一个继承自MethodInterceptor的类,并将该类注册至spring Context中,具体如下:

    1. package com.wow.asc.aop;  
    2.   
    3. import org.aopalliance.intercept.MethodInterceptor;  
    4. import org.aopalliance.intercept.MethodInvocation;  
    5.   
    6. public class MyInterceptor implements MethodInterceptor {  
    7.     @Override  
    8.     public Object invoke(MethodInvocation invocation) {  
    9.         Object result = null;  
    10.         StringBuffer info = new StringBuffer();  
    11.         info.append("intercept the method: ");  
    12.         info.append(invocation.getMethod().getDeclaringClass().  
    13. getName());  
    14.         info.append(".");  
    15.         info.append(invocation.getMethod().getName());  
    16.         System.out.println("start " + info.toString());  
    17.         try {  
    18.            result = invocation.proceed();  
    19.         } catch (Throwable e) {  
    20.             e.printStackTrace();  
    21.         } finally {  
    22.             System.out.println("end " + info.toString());  
    23.         }  
    24.         return result;  
    25.     }  
    26. }  

    对于类的装配,其实和上面的非常类似,示例:

    1. <bean id="testBean" class="org.springframework.aop.framework.ProxyFactoryBean">  
    2.         <property name="proxyInterfaces">  
    3.             <value>com.wow.asc.aop.IBusinessLogic</value>  
    4.         </property>  
    5.         <property name="target">  
    6.             <ref local="businessLogic"/>   
    7.         </property>  
    8.         <property name="interceptorNames">  
    9.             <list>  
    10.                 <value>myInterceptor</value>  
    11.             </list>  
    12.         </property>  
    13. </bean>  
    14. <bean id="myInterceptor" class="com.wow.asc.aop.MyInterceptor"/>  

            再通过客户端进行调用,可得到运行结果,从结果来分析可以看出它在方法执行的前、后均添加了相应的日志。

    1. start intercept the method: com.wow.asc.aop.IBusinessLogic.foo  
    2. Inside BusinessLogic.foo()  
    3. end intercept the method: com.wow.asc.aop.IBusinessLogic.foo  
    4. start intercept the method: com.wow.asc.aop.IBusinessLogic.time  
    5. Inside BusinessLogic.time()  
    6. end intercept the method: com.wow.asc.aop.IBusinessLogic.time  

    至此,采用两种不同方式实现的AOP就结束了,希望大家能够体会到其中的奥妙。

    相信只要使用过Spring框架的,大家对于AOP都不陌生,尤其提起它就能立刻随口说出,一般用在日志处理、异常处理、权限验证等方面。但刚开始 接触难免会有各种各样的疑惑,今天抽时间,按照之前的理解整理了一份关于Spring AOP的简单教程,希望能够帮助大家尽快的了解它的实现过程及原理。首先来明确几个概念:

    • JointPoint

    系统在运行之前,AOP的功能模块需要织入到OOP的功能模块中。要进行这种织入过程,需要知道在系统的哪些功能点上进行织入操作,这些将要在其上 进行织入操作的系统功能点就称为JointPoint。如某方法调用的时候或者处理异常的时候,在Spring AOP中,一个连接点总是表示一个方法的执行。常见的几种类型的JoinPoint:

    Ø 方法调用:当某个方法被调用的时候所处的程序执行点;

    Ø 方法执行:该类型表示的是某个方法内部执行开始时的点,应该与方法调用相区分;

    Ø 构造方法调用:程序执行过程中对某个对象调用其构造方法进行初始化时的点;

    Ø 构造方法执行:它与构造方法调用关系如同方法调用与方法执行间的关系;

    Ø 字段设置:对象的某个属性通过setter方法被设置或直接被设置的执行点;

    Ø 字段获取:某个对象相应属性被访问的执行点;

    Ø 异常处理执行:某些类型异常抛出后,对应的异常处理逻辑执行点;

    Ø 类初始化:类中某些静态类型或静态块的初始化时的执行点。

    • Pointcut

    Pointcut代表的是JoinPoint的表述方式。在将横切逻辑织入当前系统的过程中,虽然知道需要在哪些功能点上织入AOP的功能模块,但 需要一种表达方法。Pointcut和一个切入点表达式关联,并在满足这个切入点的Joinpoint上运行。目前通常使用的Pointcut方式有以下 几种:

    Ø 直接指定Joinpoint所在的方法名称;

    Ø 正则表达式,Spring的AOP支持该种方式;

    Ø 使用特定的Pointcut表述语言,Spring 2.0后支持该方式。

    • Advice

    Advice是单一横切关注点逻辑的载体,它代表将会织入到JoinPoint的横切逻辑。在切面的某个特定的连接点上执行的逻辑。根据它在Joinpoint位置执行时机的差异或完成功能的不同,可分为以下几种形式:

    Ø Before Advice:在Joinpoint指定位置之前执行的Advice类型,可以采用它来做一些系统的初始化工作,如设置系统初始值,获取必要系统资源等。

    Ø After Advice:在相应连接点之后执行的Advice类型,它还可以细分为以下三种:

    ² After Returning Advice:只有当前Joinpoint处执行流程正常完成后,它才会执行;

    ² After throwing Advice:在当前Joinpoint执行过程中抛出异常的情况下会执行;

    ² After Advice:该类型的Advice不管JoinPoint处执行流程是正常还是抛出异常都会执行。

    Ø Around Advice:对附加其上的Joinpoint进行包裹,可以在joinpoint之前和之后都指定相应的逻辑,甚至中断或忽略joinpoint处原来程序流程的执行。

    •  Aspect

    它是对系统中横切关注点逻辑进行模块化封装的AOP概念实体,它可以包含多个Pointcut以及相关的Advice定义。

    •  织入器

    经过织入过程后,以Aspect模块化的横切关注点才会集成到oop的现存系统中,而完成织入过程实体称为织入器。Spring中使用一组类来完成最终的织入操作,ProxyFactory类是Spring AOP最通用的织入器。

    •  目标对象

    符合Pointcut所指定的条件,将在织入过程中被织入横切逻辑的对象,称之为目标对象。

    单看上述的概念,可能会觉得有点眼花缭乱,其实通过一个简单的AOP的实例即可以帮助我们很快的了解其内部的机制。其实对于方法拦截有不同的实现方 式,常用的即有直接采用Spring提供的各种Advice进行拦截,另一种则是采用MethodInterceptor方式进行拦截。

    Spring提供的Advice拦截方式

    定义一个逻辑接口IBusinessLogic:

    1. package com.wow.asc.aop;  
    2.   
    3. public interface IBusinessLogic {  
    4.   
    5.     public void foo();  
    6.   
    7.     public void bar() throws BusinessLogicException;  
    8.       
    9.     public long time();  
    10. }  

    其中有一个BusinessLogicException异常,它用于后面对于ThrowsAdvice进行检验的实例,在此定义为:

    1. package com.wow.asc.aop;  
    2.   
    3. public class BusinessLogicException extends Exception {  
    4.   
    5. }  

    对于该业务逻辑的实现BusinessLogic,如下所示:

    1. package com.wow.asc.aop;  
    2.   
    3. public class BusinessLogic implements IBusinessLogic {  
    4.     @Override  
    5.     public void foo() {  
    6.         System.out.println("Inside BusinessLogic.foo()");  
    7.     }  
    8.     @Override  
    9.     public void bar() throws BusinessLogicException {  
    10.         System.out.println("Inside BusinessLogic.bar()");  
    11.         throw new BusinessLogicException();  
    12.     }  
    13.      /*  
    14.      * 返回该方法执行的时间 
    15.      */  
    16.     @Override  
    17.     public long time() {  
    18.         System.out.println("Inside BusinessLogic.time()");  
    19.         long startTime = System.currentTimeMillis();  
    20.         for(int i = 0; i < 100000000; i++);  
    21.         long endTime = System.currentTimeMillis();  
    22.           
    23.         return (endTime - startTime);  
    24.     }  
    25. }  

    在完成上述业务逻辑编码后,接下来将进行更多的横切插入点的设计,如在方法执行前或返回时、抛出异常时进行各种处理。对于Advice的写法如下所示:

    1. package com.wow.asc.aop;  
    2.   
    3. import java.lang.reflect.Method;  
    4. import org.springframework.aop.MethodBeforeAdvice;  
    5. /* 
    6. * 表示一个在方法执行前进行拦截的一个Advice 
    7.  */  
    8. public class TracingBeforeAdvice implements MethodBeforeAdvice {  
    9.     @Override  
    10.     public void before(Method method, Object[] args, Object target) throws Throwable {  
    11.         System.out.println("execute before (by " + method.getDeclaringClass().getName() + "." + method.getName() + ")");  
    12.     }  
    13. }  
    14.   
    15. package com.wow.asc.aop;  
    16.   
    17. import java.lang.reflect.Method;  
    18. import org.springframework.aop.AfterReturningAdvice;  
    19. /* 
    20.  * 表示一个在方法返回时进行拦截的Advice 
    21. */  
    22. public class TracingAfterAdvice implements AfterReturningAdvice {  
    23.     @Override  
    24.     public void afterReturning(Object returnValue, Method method, Object[] args, Object target) throws Throwable {  
    25.         System.out.println(method.getDeclaringClass().getName() + "." + method.getName() + "spend time: " + returnValue);  
    26.         System.out.println("execute after (by " + method.getDeclaringClass().getName() + "." + method.getName() + ")");  
    27.     }  
    28. }  
    29.   
    30. package com.wow.asc.aop;  
    31.   
    32. import java.lang.reflect.Method;  
    33. import org.springframework.aop.ThrowsAdvice;  
    34. /* 
    35.  * 表示一个异常抛出时进行拦截的Advice 
    36. */  
    37. public class TracingThrowsAdvice implements ThrowsAdvice {  
    38.       
    39.     public void afterThrowing(Method method, Object[] args, Object target, Throwable subclass) {  
    40.          System.out.println( "Logging that a " + subclass + "Exception was thrown.");  
    41.       }  
    42. }  

    在设计完上述的代码及逻辑后,即可以通过applicationContext.xml将上述类进行组合,在装配过程中即可明确哪个类的哪些方法需要被拦截,及拦截前、后会做哪些事情。具体的配置示例:

    1. <?xml version="1.0" encoding="UTF-8"?>  
    2. <beans xmlns="http://www.springframework.org/schema/beans"  
    3.     xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:aop="http://www.springframework.org/schema/aop"  
    4.     xmlns:tx="http://www.springframework.org/schema/tx" xmlns:context="http://www.springframework.org/schema/context"  
    5.     xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-2.5.xsd  
    6.         http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-2.5.xsd  
    7.         http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-2.5.xsd  
    8.         http://www.springframework.org/schema/context http://localhost:8080/schema/www.springframework.org/schema/context/spring-context-2.5.xsd">  
    9.     <bean id="businessLogic" class="com.wow.asc.aop.BusinessLogic" />  
    10.     <bean id="businessLogicBean" class="org.springframework.aop.framework.ProxyFactoryBean">  
    11.         <property name="proxyInterfaces">  
    12.             <value>com.wow.asc.aop.IBusinessLogic</value>  
    13.         </property>  
    14.         <property name="target">  
    15.             <ref local="businessLogic"/>   
    16.         </property>  
    17.         <property name="interceptorNames">  
    18.             <list>  
    19.                 <value>theTracingBeforeAdvisor</value>  
    20.                     <value>theTracingAfterAdvisor</value>  
    21.                     <value>theTracingThrowsAdvisor</value>  
    22.             </list>  
    23.         </property>  
    24.     </bean>  
    25.       
    26.     <bean id="theTracingBeforeAdvisor" class="org.springframework.aop.support.RegexpMethodPointcutAdvisor">  
    27.         <property name="advice">  
    28.             <ref local="theTracingBeforeAdvice"/>  
    29.         </property>  
    30.         <property name="pattern">  
    31.             <value>.*</value>  
    32.         </property>  
    33.     </bean>  
    34.     <bean id="theTracingAfterAdvisor" class="org.springframework.aop.support.RegexpMethodPointcutAdvisor">  
    35.         <property name="advice">  
    36.             <ref local="theTracingAfterAdvice"/>  
    37.         </property>  
    38.         <property name="pattern">  
    39.             <value>.*time.*</value>  
    40.         </property>  
    41.     </bean>  
    42.     <bean id="theTracingThrowsAdvisor" class="org.springframework.aop.support.RegexpMethodPointcutAdvisor">  
    43.         <property name="advice">  
    44.             <ref local="theTracingThrowsAdvice"/>  
    45.         </property>  
    46.         <property name="pattern">  
    47.             <value>.*bar.*</value>  
    48.         </property>  
    49.     </bean>  
    50.     <bean id="theTracingBeforeAdvice" class="com.wow.asc.aop.TracingBeforeAdvice"/>  
    51.     <bean id="theTracingAfterAdvice" class="com.wow.asc.aop.TracingAfterAdvice"/>  
    52.     <bean id="theTracingThrowsAdvice" class="com.wow.asc.aop.TracingThrowsAdvice"/>  
    53. </beans>  

             通过上述的配置,我们可以看出我们将IBusinessLogic做为代理接口,同时它的真正的目标类是BusinesssLogic。同时会对所有进入 方法之前采用TracingBeforeAdvice进行拦截,进行方法前的预处理;对time方法采用TracingAfterAdvice进行拦截, 进行方法返回后的处理;对于bar则采用TracingThrowsAdvice进行拦截,当方法返回BusinessLogicException时进 行相应的处理。

             在配置完上述类的依赖关系及需要拦截的方法后,即可以编写客户端程序来调用,查看它的运行机制。客户端调用代码:

    1. package com.wow.asc.test;  
    2.   
    3. import org.springframework.context.ApplicationContext;  
    4. import org.springframework.context.support.ClassPathXmlApplicationContext;  
    5. import com.wow.asc.aop.BusinessLogicException;  
    6. import com.wow.asc.aop.IBusinessLogic;  
    7.   
    8. public class AOPTest {  
    9.     public static void main(String[] args) {  
    10.         ApplicationContext ac = new ClassPathXmlApplicationContext("applicationContext.xml");  
    11.         IBusinessLogic ibl = (IBusinessLogic)ac.getBean("businessLogicBean");  
    12.         ibl.foo();  
    13.         try {  
    14.             ibl.bar();  
    15.         } catch (BusinessLogicException e) {  
    16.             System.out.println("Caught BusinessLogicException");  
    17.         }  
    18.         ibl.time();  
    19.     }  
    20. }  

            通过运行结果来详细的了解下,看是否真正的如上所述,会在方法前、后及异常抛出时能够拦截并进行相应处理。结果如下:

    1. 1、execute before (by com.wow.asc.aop.IBusinessLogic.foo)  
    2. 2、Inside BusinessLogic.foo()  
    3. 3、execute before (by com.wow.asc.aop.IBusinessLogic.bar)  
    4. 4、Inside BusinessLogic.bar()  
    5. 5、Logging that a com.wow.asc.aop.BusinessLogicExceptionException was thrown.  
    6. 6、Caught BusinessLogicException  
    7. 7、execute before (by com.wow.asc.aop.IBusinessLogic.time)  
    8. 8、Inside BusinessLogic.time()  
    9. 9、com.wow.asc.aop.IBusinessLogic.timespend time: 46  
    10. 10、execute after (by com.wow.asc.aop.IBusinessLogic.time)  

            其实通过1、3、7行可以非常清晰的了解到,每个方法在执行前都被TracingBeforeAdvice拦截到,并执行了预处理。5、6行表示当调用的 是bar方法时,会被TracingThrowsAdvice拦截,当有异常抛出时,会执行相应的处理;8、9、10行则表示当调用的是time方法,返 回时会被TracingAfterAdvice拦截,对其返回值进行处理。

    MethodInterceptor拦截方式

            采用该种方式进行拦截,需要实现一个继承自MethodInterceptor的类,并将该类注册至spring Context中,具体如下:

    1. package com.wow.asc.aop;  
    2.   
    3. import org.aopalliance.intercept.MethodInterceptor;  
    4. import org.aopalliance.intercept.MethodInvocation;  
    5.   
    6. public class MyInterceptor implements MethodInterceptor {  
    7.     @Override  
    8.     public Object invoke(MethodInvocation invocation) {  
    9.         Object result = null;  
    10.         StringBuffer info = new StringBuffer();  
    11.         info.append("intercept the method: ");  
    12.         info.append(invocation.getMethod().getDeclaringClass().  
    13. getName());  
    14.         info.append(".");  
    15.         info.append(invocation.getMethod().getName());  
    16.         System.out.println("start " + info.toString());  
    17.         try {  
    18.            result = invocation.proceed();  
    19.         } catch (Throwable e) {  
    20.             e.printStackTrace();  
    21.         } finally {  
    22.             System.out.println("end " + info.toString());  
    23.         }  
    24.         return result;  
    25.     }  
    26. }  

    对于类的装配,其实和上面的非常类似,示例:

    1. <bean id="testBean" class="org.springframework.aop.framework.ProxyFactoryBean">  
    2.         <property name="proxyInterfaces">  
    3.             <value>com.wow.asc.aop.IBusinessLogic</value>  
    4.         </property>  
    5.         <property name="target">  
    6.             <ref local="businessLogic"/>   
    7.         </property>  
    8.         <property name="interceptorNames">  
    9.             <list>  
    10.                 <value>myInterceptor</value>  
    11.             </list>  
    12.         </property>  
    13. </bean>  
    14. <bean id="myInterceptor" class="com.wow.asc.aop.MyInterceptor"/>  

            再通过客户端进行调用,可得到运行结果,从结果来分析可以看出它在方法执行的前、后均添加了相应的日志。

    1. start intercept the method: com.wow.asc.aop.IBusinessLogic.foo  
    2. Inside BusinessLogic.foo()  
    3. end intercept the method: com.wow.asc.aop.IBusinessLogic.foo  
    4. start intercept the method: com.wow.asc.aop.IBusinessLogic.time  
    5. Inside BusinessLogic.time()  
    6. end intercept the method: com.wow.asc.aop.IBusinessLogic.time  

    至此,采用两种不同方式实现的AOP就结束了,希望大家能够体会到其中的奥妙。

  • 相关阅读:
    P2216-[HAOI2007]理想的正方形
    P2157-[SDOI2009]学校食堂
    Leetcode-5176 Number of Valid Words for Each Puzzle(猜字谜)
    Leetcode-5175 Can Make Palindrome from Substring(构建回文串检测)
    Leetcode-5174 Diet Plan Performance(健身计划评估)
    Task6.PyTorch理解更多神经网络优化方法
    Task5.PyTorch实现L1,L2正则化以及Dropout
    Task4.用PyTorch实现多层网络
    Task3.PyTorch实现Logistic regression
    Task2.设立计算图并自动计算
  • 原文地址:https://www.cnblogs.com/Nouno/p/5706357.html
Copyright © 2011-2022 走看看