Bootstrap

【Spring】——AOP实现原理(基于JDK和CGLIB)

本文转自:http://blog.csdn.net/luanlouis/article/details/51155821


0、前言

     在上篇文章 《Spring设计思想》AOP设计基本原理  中阐述了Spring AOP 的基本原理以及基本机制,本文将深入源码,详细阐述整个Spring AOP实现的整个过程。

    

读完本文,你将了解到
1、Spring内部创建代理对象的过程
2、Spring AOP的核心---ProxyFactoryBean
3、基于JDK面向接口的动态代理JdkDynamicAopProxy生成代理对象
4、基于Cglib子类继承方式的动态代理CglibAopProxy生成代理对象
5、各种Advice是的执行顺序是如何和方法调用进行结合的?
6、PointCut与Advice的结合------Adivce的条件执行
7、总结

1、Spring内部创建代理对象的过程

            在Spring的底层,如果我们配置了代理模式,Spring会为每一个Bean创建一个对应的ProxyFactoryBeanFactoryBean来创建某个对象的代理对象。

            假定我们现在有一个接口TicketService及其实现类RailwayStation,我们打算创建一个代理类,在执行TicketService的方法时的各个阶段,插入对应的业务代码。

[java]  view plain  copy
 print ? 在CODE上查看代码片 派生到我的代码片
  1. package org.luanlouis.meditations.thinkinginspring.aop;  
  2.   
  3. /** 
  4.  * 售票服务 
  5.  * Created by louis on 2016/4/14. 
  6.  */  
  7. public interface TicketService {  
  8.   
  9.     //售票  
  10.     public void sellTicket();  
  11.   
  12.     //问询  
  13.     public void inquire();  
  14.   
  15.     //退票  
  16.     public void withdraw();  
  17. }  

[java]  view plain  copy
 print ? 在CODE上查看代码片 派生到我的代码片
  1. package org.luanlouis.meditations.thinkinginspring.aop;  
  2.   
  3. /** 
  4.  * RailwayStation 实现 TicketService 
  5.  * Created by louis on 2016/4/14. 
  6.  */  
  7. public class RailwayStation implements TicketService {  
  8.   
  9.     public void sellTicket(){  
  10.         System.out.println("售票............");  
  11.     }  
  12.   
  13.     public void inquire() {  
  14.         System.out.println("问询.............");  
  15.     }  
  16.   
  17.     public void withdraw() {  
  18.         System.out.println("退票.............");  
  19.     }  
  20. }  

[java]  view plain  copy
 print ? 在CODE上查看代码片 派生到我的代码片
  1. package org.luanlouis.meditations.thinkinginspring.aop;  
  2.   
  3. import org.springframework.aop.MethodBeforeAdvice;  
  4.   
  5. import java.lang.reflect.Method;  
  6.   
  7. /** 
  8.  * 执行RealSubject对象的方法之前的处理意见 
  9.  * Created by louis on 2016/4/14. 
  10.  */  
  11. public class TicketServiceBeforeAdvice implements MethodBeforeAdvice {  
  12.   
  13.     public void before(Method method, Object[] args, Object target) throws Throwable {  
  14.         System.out.println("BEFORE_ADVICE: 欢迎光临代售点....");  
  15.     }  
  16. }  

[java]  view plain  copy
 print ? 在CODE上查看代码片 派生到我的代码片
  1. package org.luanlouis.meditations.thinkinginspring.aop;  
  2.   
  3. import org.springframework.aop.AfterReturningAdvice;  
  4.   
  5. import java.lang.reflect.Method;  
  6.   
  7. /** 
  8.  * 返回结果时后的处理意见 
  9.  * Created by louis on 2016/4/14. 
  10.  */  
  11. public class TicketServiceAfterReturningAdvice implements AfterReturningAdvice {  
  12.     @Override  
  13.     public void afterReturning(Object returnValue, Method method, Object[] args, Object target) throws Throwable {  
  14.         System.out.println("AFTER_RETURNING:本次服务已结束....");  
  15.     }  
  16. }  

[java]  view plain  copy
 print ? 在CODE上查看代码片 派生到我的代码片
  1. package org.luanlouis.meditations.thinkinginspring.aop;  
  2.   
  3. import org.springframework.aop.ThrowsAdvice;  
  4.   
  5. import java.lang.reflect.Method;  
  6.   
  7. /** 
  8.  * 抛出异常时的处理意见 
  9.  * Created by louis on 2016/4/14. 
  10.  */  
  11. public class TicketServiceThrowsAdvice implements ThrowsAdvice {  
  12.   
  13.     public void afterThrowing(Exception ex){  
  14.         System.out.println("AFTER_THROWING....");  
  15.     }  
  16.     public void afterThrowing(Method method, Object[] args, Object target, Exception ex){  
  17.         System.out.println("调用过程出错啦!!!!!");  
  18.     }  
  19.   
  20. }   

[java]  view plain  copy
 print ? 在CODE上查看代码片 派生到我的代码片
  1. package org.luanlouis.meditations.thinkinginspring.aop;  
  2.   
  3. import org.aopalliance.intercept.MethodInterceptor;  
  4. import org.aopalliance.intercept.MethodInvocation;  
  5. import org.springframework.aop.aspectj.AspectJAroundAdvice;  
  6.   
  7. /** 
  8.  * 
  9.  * AroundAdvice 
  10.  * Created by louis on 2016/4/15. 
  11.  */  
  12. public class TicketServiceAroundAdvice implements MethodInterceptor {  
  13.     @Override  
  14.     public Object invoke(MethodInvocation invocation) throws Throwable {  
  15.         System.out.println("AROUND_ADVICE:BEGIN....");  
  16.         Object returnValue = invocation.proceed();  
  17.         System.out.println("AROUND_ADVICE:END.....");  
  18.         return returnValue;  
  19.     }  
  20. }  


               现在,我们来手动使用ProxyFactoryBean来创建Proxy对象,并将相应的几种不同的Advice加入这个proxy对应的各个执行阶段中:


[java]  view plain  copy
 print ? 在CODE上查看代码片 派生到我的代码片
  1. package org.luanlouis.meditations.thinkinginspring.aop;  
  2.   
  3. import org.aopalliance.aop.Advice;  
  4. import org.springframework.aop.framework.ProxyFactoryBean;  
  5.   
  6. /** 
  7.  * 通过ProxyFactoryBean 手动创建 代理对象 
  8.  * Created by louis on 2016/4/14. 
  9.  */  
  10. public class App {  
  11.   
  12.     public static void main(String[] args) throws Exception {  
  13.   
  14.         //1.针对不同的时期类型,提供不同的Advice  
  15.         Advice beforeAdvice = new TicketServiceBeforeAdvice();  
  16.         Advice afterReturningAdvice = new TicketServiceAfterReturningAdvice();  
  17.         Advice aroundAdvice = new TicketServiceAroundAdvice();  
  18.         Advice throwsAdvice = new TicketServiceThrowsAdvice();  
  19.   
  20.         RailwayStation railwayStation = new RailwayStation();  
  21.   
  22.         //2.创建ProxyFactoryBean,用以创建指定对象的Proxy对象  
  23.         ProxyFactoryBean proxyFactoryBean = new ProxyFactoryBean();  
  24.        //3.设置Proxy的接口  
  25.         proxyFactoryBean.setInterfaces(TicketService.class);  
  26.         //4. 设置RealSubject  
  27.         proxyFactoryBean.setTarget(railwayStation);  
  28.         //5.使用JDK基于接口实现机制的动态代理生成Proxy代理对象,如果想使用CGLIB,需要将这个flag设置成true  
  29.         proxyFactoryBean.setProxyTargetClass(true);  
  30.   
  31.         //6. 添加不同的Advice  
  32.   
  33.         proxyFactoryBean.addAdvice(afterReturningAdvice);  
  34.         proxyFactoryBean.addAdvice(aroundAdvice);  
  35.         proxyFactoryBean.addAdvice(throwsAdvice);  
  36.         proxyFactoryBean.addAdvice(beforeAdvice);  
  37.         proxyFactoryBean.setProxyTargetClass(false);  
  38.         //7通过ProxyFactoryBean生成Proxy对象  
  39.         TicketService ticketService = (TicketService) proxyFactoryBean.getObject();  
  40.         ticketService.sellTicket();  
  41.   
  42.     }  
  43.   
  44.   
  45. }  


不出意外的话,你会得到如下的输出结果:

你会看到,我们成功地创建了一个通过一个ProxyFactoryBean和 真实的实例对象创建出了对应的代理对象,并将各个Advice加入到proxy代理对象中。

你会发现,在调用RailwayStationsellticket()之前,成功插入了BeforeAdivce逻辑,而调用RailwayStation的sellticket()之后,AfterReturning逻辑也成功插入了。

AroundAdvice也成功包裹了sellTicket()方法,只不过这个AroundAdvice发生的时机有点让人感到迷惑。实际上,这个背后的执行逻辑隐藏了Spring AOP关于AOP的关于Advice调度最为核心的算法机制,这个将在本文后面详细阐述。

另外,本例中ProxyFactoryBean是通过JDK的针对接口的动态代理模式生成代理对象的,具体机制,请看下面关于ProxyFactoryBean的介绍。

2、Spring AOP的核心---ProxyFactoryBean

          上面我们通过了纯手动使用ProxyFactoryBean实现了AOP的功能。现在来分析一下上面的代码:我们为ProxyFactoryBean提供了如下信息:

1). Proxy应该感兴趣的Adivce列表;

2). 真正的实例对象引用ticketService;

3).告诉ProxyFactoryBean使用基于接口实现的JDK动态代理机制实现proxy: 

4). Proxy应该具备的Interface接口:TicketService;

根据这些信息,ProxyFactoryBean就能给我们提供我们想要的Proxy对象了!那么,ProxyFactoryBean帮我们做了什么?


              Spring 使用工厂Bean模式创建每一个Proxy,对应每一个不同的Class类型,在Spring中都会有一个相对应的ProxyFactoryBean. 以下是ProxyFactoryBean的类图。

如上所示,对于生成Proxy的工厂Bean而言,它要知道对其感兴趣的Advice信息,而这类的信息,被维护到Advised中。Advised可以根据特定的类名和方法名返回对应的AdviceChain,用以表示需要执行的Advice串。


3、基于JDK面向接口的动态代理JdkDynamicAopProxy生成代理对象

JdkDynamicAopProxy类实现了AopProxy,能够返回Proxy,并且,其自身也实现了InvocationHandler角色。也就是说,当我们使用proxy时,我们对proxy对象调用的方法,都最终被转到这个类的invoke()方法中。

[java]  view plain  copy
 print ? 在CODE上查看代码片 派生到我的代码片
  1. final class JdkDynamicAopProxy implements AopProxy, InvocationHandler, Serializable {  
  2.         //省略若干...  
  3.     /** Proxy的配置信息,这里主要提供Advisor列表,并用于返回AdviceChain */  
  4.     private final AdvisedSupport advised;  
  5.   
  6.     /** 
  7.      * Construct a new JdkDynamicAopProxy for the given AOP configuration. 
  8.      * @param config the AOP configuration as AdvisedSupport object 
  9.      * @throws AopConfigException if the config is invalid. We try to throw an informative 
  10.      * exception in this case, rather than let a mysterious failure happen later. 
  11.      */  
  12.     public JdkDynamicAopProxy(AdvisedSupport config) throws AopConfigException {  
  13.         Assert.notNull(config, "AdvisedSupport must not be null");  
  14.         if (config.getAdvisors().length == 0 && config.getTargetSource() == AdvisedSupport.EMPTY_TARGET_SOURCE) {  
  15.             throw new AopConfigException("No advisors and no TargetSource specified");  
  16.         }  
  17.         this.advised = config;  
  18.     }  
  19.   
  20.   
  21.     @Override  
  22.     public Object getProxy() {  
  23.         return getProxy(ClassUtils.getDefaultClassLoader());  
  24.     }  
  25.         //返回代理实例对象  
  26.     @Override  
  27.     public Object getProxy(ClassLoader classLoader) {  
  28.         if (logger.isDebugEnabled()) {  
  29.             logger.debug("Creating JDK dynamic proxy: target source is " + this.advised.getTargetSource());  
  30.         }  
  31.         Class<?>[] proxiedInterfaces = AopProxyUtils.completeProxiedInterfaces(this.advised);  
  32.         findDefinedEqualsAndHashCodeMethods(proxiedInterfaces);  
  33.                 //这里的InvocationHandler设置成了当前实例对象,即对这个proxy调用的任何方法,都会调用这个类的invoke()方法  
  34.                 //这里的invoke方法被调用,动态查找Advice列表,组成ReflectMethodInvocation  
  35.         return Proxy.newProxyInstance(classLoader, proxiedInterfaces, this);  
  36.     }  
  37.     /** 
  38.      * 对当前proxy调用其上的任何方法,都将转到这个方法上 
  39.          * Implementation of {@code InvocationHandler.invoke}. 
  40.      * <p>Callers will see exactly the exception thrown by the target, 
  41.      * unless a hook method throws an exception. 
  42.      */  
  43.     @Override  
  44.     public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {  
  45.         MethodInvocation invocation;  
  46.         Object oldProxy = null;  
  47.         boolean setProxyContext = false;  
  48.   
  49.         TargetSource targetSource = this.advised.targetSource;  
  50.         Class<?> targetClass = null;  
  51.         Object target = null;  
  52.   
  53.         try {  
  54.             if (!this.equalsDefined && AopUtils.isEqualsMethod(method)) {  
  55.                 // The target does not implement the equals(Object) method itself.  
  56.                 return equals(args[0]);  
  57.             }  
  58.             if (!this.hashCodeDefined && AopUtils.isHashCodeMethod(method)) {  
  59.                 // The target does not implement the hashCode() method itself.  
  60.                 return hashCode();  
  61.             }  
  62.             if (!this.advised.opaque && method.getDeclaringClass().isInterface() &&  
  63.                     method.getDeclaringClass().isAssignableFrom(Advised.class)) {  
  64.                 // Service invocations on ProxyConfig with the proxy config...  
  65.                 return AopUtils.invokeJoinpointUsingReflection(this.advised, method, args);  
  66.             }  
  67.   
  68.             Object retVal;  
  69.   
  70.             if (this.advised.exposeProxy) {  
  71.                 // Make invocation available if necessary.  
  72.                 oldProxy = AopContext.setCurrentProxy(proxy);  
  73.                 setProxyContext = true;  
  74.             }  
  75.   
  76.             // May be null. Get as late as possible to minimize the time we "own" the target,  
  77.             // in case it comes from a pool.  
  78.             target = targetSource.getTarget();  
  79.             if (target != null) {  
  80.                 targetClass = target.getClass();  
  81.             }  
  82.   
  83.             // Get the interception chain for this method.获取当前调用方法的拦截链  
  84.             List<Object> chain = this.advised.getInterceptorsAndDynamicInterceptionAdvice(method, targetClass);  
  85.   
  86.             // Check whether we have any advice. If we don't, we can fallback on direct  
  87.             // reflective invocation of the target, and avoid creating a MethodInvocation.  
  88.                         //如果没有拦截链,则直接调用Joinpoint连接点的方法。  
  89.             if (chain.isEmpty()) {  
  90.                 // We can skip creating a MethodInvocation: just invoke the target directly  
  91.                 // Note that the final invoker must be an InvokerInterceptor so we know it does  
  92.                 // nothing but a reflective operation on the target, and no hot swapping or fancy proxying.  
  93.                 Object[] argsToUse = AopProxyUtils.adaptArgumentsIfNecessary(method, args);  
  94.                 retVal = AopUtils.invokeJoinpointUsingReflection(target, method, argsToUse);  
  95.             }  
  96.             else {  
  97.                 // We need to create a method invocation...  
  98.                                 //根据给定的拦截链和方法调用信息,创建新的MethodInvocation对象,整个拦截链的工作逻辑都在这个ReflectiveMethodInvocation里   
  99.                 invocation = new ReflectiveMethodInvocation(proxy, target, method, args, targetClass, chain);  
  100.                 // Proceed to the joinpoint through the interceptor chain.  
  101.                 retVal = invocation.proceed();  
  102.             }  
  103.   
  104.             // Massage return value if necessary.  
  105.             Class<?> returnType = method.getReturnType();  
  106.             if (retVal != null && retVal == target && returnType.isInstance(proxy) &&  
  107.                     !RawTargetAccess.class.isAssignableFrom(method.getDeclaringClass())) {  
  108.                 // Special case: it returned "this" and the return type of the method  
  109.                 // is type-compatible. Note that we can't help if the target sets  
  110.                 // a reference to itself in another returned object.  
  111.                 retVal = proxy;  
  112.             }  
  113.             else if (retVal == null && returnType != Void.TYPE && returnType.isPrimitive()) {  
  114.                 throw new AopInvocationException(  
  115.                         "Null return value from advice does not match primitive return type for: " + method);  
  116.             }  
  117.             return retVal;  
  118.         }  
  119.         finally {  
  120.             if (target != null && !targetSource.isStatic()) {  
  121.                 // Must have come from TargetSource.  
  122.                 targetSource.releaseTarget(target);  
  123.             }  
  124.             if (setProxyContext) {  
  125.                 // Restore old proxy.  
  126.                 AopContext.setCurrentProxy(oldProxy);  
  127.             }  
  128.         }  
  129.     }  
  130. }  

4、基于Cglib子类继承方式的动态代理CglibAopProxy生成代理对象

基于Cglib子类继承方式的动态代理CglibAopProxy生成代理对象:

[java]  view plain  copy
 print ? 在CODE上查看代码片 派生到我的代码片
  1. package org.springframework.aop.framework;  
  2. /** 
  3.  * CGLIB-based {@link AopProxy} implementation for the Spring AOP framework. 
  4.  * 
  5.  * <p>Formerly named {@code Cglib2AopProxy}, as of Spring 3.2, this class depends on 
  6.  * Spring's own internally repackaged version of CGLIB 3.</i>. 
  7.  */  
  8. @SuppressWarnings("serial")  
  9. class CglibAopProxy implements AopProxy, Serializable {  
  10.   
  11.     // Constants for CGLIB callback array indices  
  12.     private static final int AOP_PROXY = 0;  
  13.     private static final int INVOKE_TARGET = 1;  
  14.     private static final int NO_OVERRIDE = 2;  
  15.     private static final int DISPATCH_TARGET = 3;  
  16.     private static final int DISPATCH_ADVISED = 4;  
  17.     private static final int INVOKE_EQUALS = 5;  
  18.     private static final int INVOKE_HASHCODE = 6;  
  19.   
  20.   
  21.     /** Logger available to subclasses; static to optimize serialization */  
  22.     protected static final Log logger = LogFactory.getLog(CglibAopProxy.class);  
  23.   
  24.     /** Keeps track of the Classes that we have validated for final methods */  
  25.     private static final Map<Class<?>, Boolean> validatedClasses = new WeakHashMap<Class<?>, Boolean>();  
  26.   
  27.   
  28.     /** The configuration used to configure this proxy */  
  29.     protected final AdvisedSupport advised;  
  30.   
  31.     protected Object[] constructorArgs;  
  32.   
  33.     protected Class<?>[] constructorArgTypes;  
  34.   
  35.     /** Dispatcher used for methods on Advised */  
  36.     private final transient AdvisedDispatcher advisedDispatcher;  
  37.   
  38.     private transient Map<String, Integer> fixedInterceptorMap;  
  39.   
  40.     private transient int fixedInterceptorOffset;  
  41.   
  42.   
  43.     /** 
  44.      * Create a new CglibAopProxy for the given AOP configuration. 
  45.      * @param config the AOP configuration as AdvisedSupport object 
  46.      * @throws AopConfigException if the config is invalid. We try to throw an informative 
  47.      * exception in this case, rather than let a mysterious failure happen later. 
  48.      */  
  49.     public CglibAopProxy(AdvisedSupport config) throws AopConfigException {  
  50.         Assert.notNull(config, "AdvisedSupport must not be null");  
  51.         if (config.getAdvisors().length == 0 && config.getTargetSource() == AdvisedSupport.EMPTY_TARGET_SOURCE) {  
  52.             throw new AopConfigException("No advisors and no TargetSource specified");  
  53.         }  
  54.         this.advised = config;  
  55.         this.advisedDispatcher = new AdvisedDispatcher(this.advised);  
  56.     }  
  57.   
  58.     /** 
  59.      * Set constructor arguments to use for creating the proxy. 
  60.      * @param constructorArgs the constructor argument values 
  61.      * @param constructorArgTypes the constructor argument types 
  62.      */  
  63.     public void setConstructorArguments(Object[] constructorArgs, Class<?>[] constructorArgTypes) {  
  64.         if (constructorArgs == null || constructorArgTypes == null) {  
  65.             throw new IllegalArgumentException("Both 'constructorArgs' and 'constructorArgTypes' need to be specified");  
  66.         }  
  67.         if (constructorArgs.length != constructorArgTypes.length) {  
  68.             throw new IllegalArgumentException("Number of 'constructorArgs' (" + constructorArgs.length +  
  69.                     ") must match number of 'constructorArgTypes' (" + constructorArgTypes.length + ")");  
  70.         }  
  71.         this.constructorArgs = constructorArgs;  
  72.         this.constructorArgTypes = constructorArgTypes;  
  73.     }  
  74.   
  75.   
  76.     @Override  
  77.     public Object getProxy() {  
  78.         return getProxy(null);  
  79.     }  
  80.   
  81.     @Override  
  82.     public Object getProxy(ClassLoader classLoader) {  
  83.         if (logger.isDebugEnabled()) {  
  84.             logger.debug("Creating CGLIB proxy: target source is " + this.advised.getTargetSource());  
  85.         }  
  86.   
  87.         try {  
  88.             Class<?> rootClass = this.advised.getTargetClass();  
  89.             Assert.state(rootClass != null"Target class must be available for creating a CGLIB proxy");  
  90.   
  91.             Class<?> proxySuperClass = rootClass;  
  92.             if (ClassUtils.isCglibProxyClass(rootClass)) {  
  93.                 proxySuperClass = rootClass.getSuperclass();  
  94.                 Class<?>[] additionalInterfaces = rootClass.getInterfaces();  
  95.                 for (Class<?> additionalInterface : additionalInterfaces) {  
  96.                     this.advised.addInterface(additionalInterface);  
  97.                 }  
  98.             }  
  99.   
  100.             // Validate the class, writing log messages as necessary.  
  101.             validateClassIfNecessary(proxySuperClass, classLoader);  
  102.   
  103.             // Configure CGLIB Enhancer...  
  104.             Enhancer enhancer = createEnhancer();  
  105.             if (classLoader != null) {  
  106.                 enhancer.setClassLoader(classLoader);  
  107.                 if (classLoader instanceof SmartClassLoader &&  
  108.                         ((SmartClassLoader) classLoader).isClassReloadable(proxySuperClass)) {  
  109.                     enhancer.setUseCache(false);  
  110.                 }  
  111.             }  
  112.             enhancer.setSuperclass(proxySuperClass);  
  113.             enhancer.setInterfaces(AopProxyUtils.completeProxiedInterfaces(this.advised));  
  114.             enhancer.setNamingPolicy(SpringNamingPolicy.INSTANCE);  
  115.             enhancer.setStrategy(new ClassLoaderAwareUndeclaredThrowableStrategy(classLoader));  
  116.   
  117.             Callback[] callbacks = getCallbacks(rootClass);  
  118.             Class<?>[] types = new Class<?>[callbacks.length];  
  119.             for (int x = 0; x < types.length; x++) {  
  120.                 types[x] = callbacks[x].getClass();  
  121.             }  
  122.             // fixedInterceptorMap only populated at this point, after getCallbacks call above  
  123.             enhancer.setCallbackFilter(new ProxyCallbackFilter(  
  124.                     this.advised.getConfigurationOnlyCopy(), this.fixedInterceptorMap, this.fixedInterceptorOffset));  
  125.             enhancer.setCallbackTypes(types);  
  126.   
  127.             // Generate the proxy class and create a proxy instance.  
  128.             return createProxyClassAndInstance(enhancer, callbacks);  
  129.         }  
  130.         catch (CodeGenerationException ex) {  
  131.             throw new AopConfigException("Could not generate CGLIB subclass of class [" +  
  132.                     this.advised.getTargetClass() + "]: " +  
  133.                     "Common causes of this problem include using a final class or a non-visible class",  
  134.                     ex);  
  135.         }  
  136.         catch (IllegalArgumentException ex) {  
  137.             throw new AopConfigException("Could not generate CGLIB subclass of class [" +  
  138.                     this.advised.getTargetClass() + "]: " +  
  139.                     "Common causes of this problem include using a final class or a non-visible class",  
  140.                     ex);  
  141.         }  
  142.         catch (Exception ex) {  
  143.             // TargetSource.getTarget() failed  
  144.             throw new AopConfigException("Unexpected AOP exception", ex);  
  145.         }  
  146.     }  
  147.   
  148.     protected Object createProxyClassAndInstance(Enhancer enhancer, Callback[] callbacks) {  
  149.         enhancer.setInterceptDuringConstruction(false);  
  150.         enhancer.setCallbacks(callbacks);  
  151.         return (this.constructorArgs != null ?  
  152.                 enhancer.create(this.constructorArgTypes, this.constructorArgs) :  
  153.                 enhancer.create());  
  154.     }  
  155.   
  156.     /** 
  157.      * Creates the CGLIB {@link Enhancer}. Subclasses may wish to override this to return a custom 
  158.      * {@link Enhancer} implementation. 
  159.      */  
  160.     protected Enhancer createEnhancer() {  
  161.         return new Enhancer();  
  162.     }  
  163.   
  164.   
  165.   
  166.     private Callback[] getCallbacks(Class<?> rootClass) throws Exception {  
  167.         // Parameters used for optimisation choices...  
  168.         boolean exposeProxy = this.advised.isExposeProxy();  
  169.         boolean isFrozen = this.advised.isFrozen();  
  170.         boolean isStatic = this.advised.getTargetSource().isStatic();  
  171.   
  172.         // Choose an "aop" interceptor (used for AOP calls).  
  173.         Callback aopInterceptor = new DynamicAdvisedInterceptor(this.advised);  
  174.   
  175.         // Choose a "straight to target" interceptor. (used for calls that are  
  176.         // unadvised but can return this). May be required to expose the proxy.  
  177.         Callback targetInterceptor;  
  178.         if (exposeProxy) {  
  179.             targetInterceptor = isStatic ?  
  180.                     new StaticUnadvisedExposedInterceptor(this.advised.getTargetSource().getTarget()) :  
  181.                     new DynamicUnadvisedExposedInterceptor(this.advised.getTargetSource());  
  182.         }  
  183.         else {  
  184.             targetInterceptor = isStatic ?  
  185.                     new StaticUnadvisedInterceptor(this.advised.getTargetSource().getTarget()) :  
  186.                     new DynamicUnadvisedInterceptor(this.advised.getTargetSource());  
  187.         }  
  188.   
  189.         // Choose a "direct to target" dispatcher (used for  
  190.         // unadvised calls to static targets that cannot return this).  
  191.         Callback targetDispatcher = isStatic ?  
  192.                 new StaticDispatcher(this.advised.getTargetSource().getTarget()) : new SerializableNoOp();  
  193.   
  194.         Callback[] mainCallbacks = new Callback[] {  
  195.                 aopInterceptor,  // for normal advice  
  196.                 targetInterceptor,  // invoke target without considering advice, if optimized  
  197.                 new SerializableNoOp(),  // no override for methods mapped to this  
  198.                 targetDispatcher, this.advisedDispatcher,  
  199.                 new EqualsInterceptor(this.advised),  
  200.                 new HashCodeInterceptor(this.advised)  
  201.         };  
  202.   
  203.         Callback[] callbacks;  
  204.   
  205.         // If the target is a static one and the advice chain is frozen,  
  206.         // then we can make some optimisations by sending the AOP calls  
  207.         // direct to the target using the fixed chain for that method.  
  208.         if (isStatic && isFrozen) {  
  209.             Method[] methods = rootClass.getMethods();  
  210.             Callback[] fixedCallbacks = new Callback[methods.length];  
  211.             this.fixedInterceptorMap = new HashMap<String, Integer>(methods.length);  
  212.   
  213.             // TODO: small memory optimisation here (can skip creation for methods with no advice)  
  214.             for (int x = 0; x < methods.length; x++) {  
  215.                 List<Object> chain = this.advised.getInterceptorsAndDynamicInterceptionAdvice(methods[x], rootClass);  
  216.                 fixedCallbacks[x] = new FixedChainStaticTargetInterceptor(  
  217.                         chain, this.advised.getTargetSource().getTarget(), this.advised.getTargetClass());  
  218.                 this.fixedInterceptorMap.put(methods[x].toString(), x);  
  219.             }  
  220.   
  221.             // Now copy both the callbacks from mainCallbacks  
  222.             // and fixedCallbacks into the callbacks array.  
  223.             callbacks = new Callback[mainCallbacks.length + fixedCallbacks.length];  
  224.             System.arraycopy(mainCallbacks, 0, callbacks, 0, mainCallbacks.length);  
  225.             System.arraycopy(fixedCallbacks, 0, callbacks, mainCallbacks.length, fixedCallbacks.length);  
  226.             this.fixedInterceptorOffset = mainCallbacks.length;  
  227.         }  
  228.         else {  
  229.             callbacks = mainCallbacks;  
  230.         }  
  231.         return callbacks;  
  232.     }  
  233.   
  234.   
  235.     /** 
  236.      * General purpose AOP callback. Used when the target is dynamic or when the 
  237.      * proxy is not frozen. 
  238.      */  
  239.     private static class DynamicAdvisedInterceptor implements MethodInterceptor, Serializable {  
  240.   
  241.         private final AdvisedSupport advised;  
  242.   
  243.         public DynamicAdvisedInterceptor(AdvisedSupport advised) {  
  244.             this.advised = advised;  
  245.         }  
  246.   
  247.         @Override  
  248.         public Object intercept(Object proxy, Method method, Object[] args, MethodProxy methodProxy) throws Throwable {  
  249.             Object oldProxy = null;  
  250.             boolean setProxyContext = false;  
  251.             Class<?> targetClass = null;  
  252.             Object target = null;  
  253.             try {  
  254.                 if (this.advised.exposeProxy) {  
  255.                     // Make invocation available if necessary.  
  256.                     oldProxy = AopContext.setCurrentProxy(proxy);  
  257.                     setProxyContext = true;  
  258.                 }  
  259.                 // May be null. Get as late as possible to minimize the time we  
  260.                 // "own" the target, in case it comes from a pool...  
  261.                 target = getTarget();  
  262.                 if (target != null) {  
  263.                     targetClass = target.getClass();  
  264.                 }  
  265.                 List<Object> chain = this.advised.getInterceptorsAndDynamicInterceptionAdvice(method, targetClass);  
  266.                 Object retVal;  
  267.                 // Check whether we only have one InvokerInterceptor: that is,  
  268.                 // no real advice, but just reflective invocation of the target.  
  269.                 if (chain.isEmpty() && Modifier.isPublic(method.getModifiers())) {  
  270.                     // We can skip creating a MethodInvocation: just invoke the target directly.  
  271.                     // Note that the final invoker must be an InvokerInterceptor, so we know  
  272.                     // it does nothing but a reflective operation on the target, and no hot  
  273.                     // swapping or fancy proxying.  
  274.                     Object[] argsToUse = AopProxyUtils.adaptArgumentsIfNecessary(method, args);  
  275.                     retVal = methodProxy.invoke(target, argsToUse);  
  276.                 }  
  277.                 else {  
  278.                     // We need to create a method invocation...  
  279.                     retVal = new CglibMethodInvocation(proxy, target, method, args, targetClass, chain, methodProxy).proceed();  
  280.                 }  
  281.                 retVal = processReturnType(proxy, target, method, retVal);  
  282.                 return retVal;  
  283.             }  
  284.             finally {  
  285.                 if (target != null) {  
  286.                     releaseTarget(target);  
  287.                 }  
  288.                 if (setProxyContext) {  
  289.                     // Restore old proxy.  
  290.                     AopContext.setCurrentProxy(oldProxy);  
  291.                 }  
  292.             }  
  293.         }  
  294.         //省略...  
  295.     }  
  296.   
  297.   
  298.     /** 
  299.      * Implementation of AOP Alliance MethodInvocation used by this AOP proxy. 
  300.      */  
  301.     private static class CglibMethodInvocation extends ReflectiveMethodInvocation {  
  302.   
  303.         private final MethodProxy methodProxy;  
  304.   
  305.         private final boolean publicMethod;  
  306.   
  307.         public CglibMethodInvocation(Object proxy, Object target, Method method, Object[] arguments,  
  308.                 Class<?> targetClass, List<Object> interceptorsAndDynamicMethodMatchers, MethodProxy methodProxy) {  
  309.   
  310.             super(proxy, target, method, arguments, targetClass, interceptorsAndDynamicMethodMatchers);  
  311.             this.methodProxy = methodProxy;  
  312.             this.publicMethod = Modifier.isPublic(method.getModifiers());  
  313.         }  
  314.   
  315.         /** 
  316.          * Gives a marginal performance improvement versus using reflection to 
  317.          * invoke the target when invoking public methods. 
  318.          */  
  319.         @Override  
  320.         protected Object invokeJoinpoint() throws Throwable {  
  321.             if (this.publicMethod) {  
  322.                 return this.methodProxy.invoke(this.target, this.arguments);  
  323.             }  
  324.             else {  
  325.                 return super.invokeJoinpoint();  
  326.             }  
  327.         }  
  328.     }  
  329.   
  330. }  


5、各种Advice是的执行顺序是如何和方法调用进行结合的?

JdkDynamicAopProxy 和CglibAopProxy只是创建代理方式的两种方式而已,实际上我们为方法调用添加的各种Advice的执行逻辑都是统一的。在Spring的底层,会把我们定义的各个Adivce分别 包裹成一个 MethodInterceptor,这些Advice按照加入Advised顺序,构成一个AdivseChain.

比如我们上述的代码:

[java]  view plain  copy
 print ? 在CODE上查看代码片 派生到我的代码片
  1. //5. 添加不同的Advice  
  2.   
  3. proxyFactoryBean.addAdvice(afterReturningAdvice);  
  4. proxyFactoryBean.addAdvice(aroundAdvice);  
  5. proxyFactoryBean.addAdvice(throwsAdvice);  
  6. proxyFactoryBean.addAdvice(beforeAdvice);  
  7. proxyFactoryBean.setProxyTargetClass(false);  
  8. //通过ProxyFactoryBean生成  
  9. TicketService ticketService = (TicketService) proxyFactoryBean.getObject();  
  10. ticketService.sellTicket();  

当我们调用 ticketService.sellTicket()时,Spring会把这个方法调用转换成一个MethodInvocation对象,然后结合上述的我们添加的各种Advice,组成一个ReflectiveMethodInvocation:

 各种Advice本质而言是一个方法调用拦截器,现在让我们看看各个Advice拦截器都干了什么?

[java]  view plain  copy
 print ? 在CODE上查看代码片 派生到我的代码片
  1. /** 
  2.  * 包裹MethodBeforeAdvice的方法拦截器 
  3.  * Interceptor to wrap am {@link org.springframework.aop.MethodBeforeAdvice}. 
  4.  * Used internally by the AOP framework; application developers should not need 
  5.  * to use this class directly. 
  6.  * 
  7.  * @author Rod Johnson 
  8.  */  
  9. @SuppressWarnings("serial")  
  10. public class MethodBeforeAdviceInterceptor implements MethodInterceptor, Serializable {  
  11.   
  12.     private MethodBeforeAdvice advice;  
  13.   
  14.   
  15.     /** 
  16.      * Create a new MethodBeforeAdviceInterceptor for the given advice. 
  17.      * @param advice the MethodBeforeAdvice to wrap 
  18.      */  
  19.     public MethodBeforeAdviceInterceptor(MethodBeforeAdvice advice) {  
  20.         Assert.notNull(advice, "Advice must not be null");  
  21.         this.advice = advice;  
  22.     }  
  23.   
  24.     @Override  
  25.     public Object invoke(MethodInvocation mi) throws Throwable {  
  26.         //在调用方法之前,先执行BeforeAdvice  
  27.         this.advice.before(mi.getMethod(), mi.getArguments(), mi.getThis() );  
  28.         return mi.proceed();  
  29.     }  
  30.   
  31. }  

[java]  view plain  copy
 print ? 在CODE上查看代码片 派生到我的代码片
  1. /** 
  2.  * 包裹AfterReturningAdvice的方法拦截器 
  3.  * Interceptor to wrap am {@link org.springframework.aop.AfterReturningAdvice}. 
  4.  * Used internally by the AOP framework; application developers should not need 
  5.  * to use this class directly. 
  6.  * 
  7.  * @author Rod Johnson 
  8.  */  
  9. @SuppressWarnings("serial")  
  10. public class AfterReturningAdviceInterceptor implements MethodInterceptor, AfterAdvice, Serializable {  
  11.   
  12.     private final AfterReturningAdvice advice;  
  13.   
  14.   
  15.     /** 
  16.      * Create a new AfterReturningAdviceInterceptor for the given advice. 
  17.      * @param advice the AfterReturningAdvice to wrap 
  18.      */  
  19.     public AfterReturningAdviceInterceptor(AfterReturningAdvice advice) {  
  20.         Assert.notNull(advice, "Advice must not be null");  
  21.         this.advice = advice;  
  22.     }  
  23.   
  24.     @Override  
  25.     public Object invoke(MethodInvocation mi) throws Throwable {  
  26.         //先调用invocation  
  27.         Object retVal = mi.proceed();  
  28.         //调用成功后,调用AfterReturningAdvice  
  29.         this.advice.afterReturning(retVal, mi.getMethod(), mi.getArguments(), mi.getThis());  
  30.         return retVal;  
  31.     }  
  32.   
  33. }  

[java]  view plain  copy
 print ? 在CODE上查看代码片 派生到我的代码片
  1. /** 
  2.  * Interceptor to wrap an after-throwing advice. 
  3.  * 
  4.  * <p>The signatures on handler methods on the {@code ThrowsAdvice} 
  5.  * implementation method argument must be of the form:<br> 
  6.  * 
  7.  * {@code void afterThrowing([Method, args, target], ThrowableSubclass);} 
  8.  * 
  9.  * <p>Only the last argument is required. 
  10.  * 
  11.  * <p>Some examples of valid methods would be: 
  12.  * 
  13.  * <pre class="code">public void afterThrowing(Exception ex)</pre> 
  14.  * <pre class="code">public void afterThrowing(RemoteException)</pre> 
  15.  * <pre class="code">public void afterThrowing(Method method, Object[] args, Object target, Exception ex)</pre> 
  16.  * <pre class="code">public void afterThrowing(Method method, Object[] args, Object target, ServletException ex)</pre> 
  17.  * 
  18.  * <p>This is a framework class that need not be used directly by Spring users. 
  19.  * 
  20.  * @author Rod Johnson 
  21.  * @author Juergen Hoeller 
  22.  */  
  23. public class ThrowsAdviceInterceptor implements MethodInterceptor, AfterAdvice {  
  24.   
  25.     private static final String AFTER_THROWING = "afterThrowing";  
  26.   
  27.     private static final Log logger = LogFactory.getLog(ThrowsAdviceInterceptor.class);  
  28.   
  29.   
  30.     private final Object throwsAdvice;  
  31.   
  32.     /** Methods on throws advice, keyed by exception class */  
  33.     private final Map<Class<?>, Method> exceptionHandlerMap = new HashMap<Class<?>, Method>();  
  34.   
  35.   
  36.     /** 
  37.      * Create a new ThrowsAdviceInterceptor for the given ThrowsAdvice. 
  38.      * @param throwsAdvice the advice object that defines the exception 
  39.      * handler methods (usually a {@link org.springframework.aop.ThrowsAdvice} 
  40.      * implementation) 
  41.      */  
  42.     public ThrowsAdviceInterceptor(Object throwsAdvice) {  
  43.         Assert.notNull(throwsAdvice, "Advice must not be null");  
  44.         this.throwsAdvice = throwsAdvice;  
  45.   
  46.         Method[] methods = throwsAdvice.getClass().getMethods();  
  47.         for (Method method : methods) {  
  48.             //ThrowsAdvice定义的afterThrowing方法是Handler方法  
  49.             if (method.getName().equals(AFTER_THROWING) &&  
  50.                     (method.getParameterTypes().length == 1 || method.getParameterTypes().length == 4) &&  
  51.                     Throwable.class.isAssignableFrom(method.getParameterTypes()[method.getParameterTypes().length - 1])  
  52.                 ) {  
  53.                 // Have an exception handler  
  54.                 this.exceptionHandlerMap.put(method.getParameterTypes()[method.getParameterTypes().length - 1], method);  
  55.                 if (logger.isDebugEnabled()) {  
  56.                     logger.debug("Found exception handler method: " + method);  
  57.                 }  
  58.             }  
  59.         }  
  60.   
  61.         if (this.exceptionHandlerMap.isEmpty()) {  
  62.             throw new IllegalArgumentException(  
  63.                     "At least one handler method must be found in class [" + throwsAdvice.getClass() + "]");  
  64.         }  
  65.     }  
  66.   
  67.     public int getHandlerMethodCount() {  
  68.         return this.exceptionHandlerMap.size();  
  69.     }  
  70.   
  71.     /** 
  72.      * Determine the exception handle method. Can return null if not found. 
  73.      * @param exception the exception thrown 
  74.      * @return a handler for the given exception type 
  75.      */  
  76.     private Method getExceptionHandler(Throwable exception) {  
  77.         Class<?> exceptionClass = exception.getClass();  
  78.         if (logger.isTraceEnabled()) {  
  79.             logger.trace("Trying to find handler for exception of type [" + exceptionClass.getName() + "]");  
  80.         }  
  81.         Method handler = this.exceptionHandlerMap.get(exceptionClass);  
  82.         while (handler == null && exceptionClass != Throwable.class) {  
  83.             exceptionClass = exceptionClass.getSuperclass();  
  84.             handler = this.exceptionHandlerMap.get(exceptionClass);  
  85.         }  
  86.         if (handler != null && logger.isDebugEnabled()) {  
  87.             logger.debug("Found handler for exception of type [" + exceptionClass.getName() + "]: " + handler);  
  88.         }  
  89.         return handler;  
  90.     }  
  91.   
  92.     @Override  
  93.     public Object invoke(MethodInvocation mi) throws Throwable {  
  94.         //使用大的try,先执行代码,捕获异常  
  95.         try {  
  96.             return mi.proceed();  
  97.         }  
  98.         catch (Throwable ex) {  
  99.             //获取异常处理方法  
  100.             Method handlerMethod = getExceptionHandler(ex);  
  101.             //调用异常处理方法  
  102.             if (handlerMethod != null) {  
  103.                 invokeHandlerMethod(mi, ex, handlerMethod);  
  104.             }  
  105.             throw ex;  
  106.         }  
  107.     }  
  108.   
  109.     private void invokeHandlerMethod(MethodInvocation mi, Throwable ex, Method method) throws Throwable {  
  110.         Object[] handlerArgs;  
  111.         if (method.getParameterTypes().length == 1) {  
  112.             handlerArgs = new Object[] { ex };  
  113.         }  
  114.         else {  
  115.             handlerArgs = new Object[] {mi.getMethod(), mi.getArguments(), mi.getThis(), ex};  
  116.         }  
  117.         try {  
  118.             method.invoke(this.throwsAdvice, handlerArgs);  
  119.         }  
  120.         catch (InvocationTargetException targetEx) {  
  121.             throw targetEx.getTargetException();  
  122.         }  
  123.     }  
  124.   
  125. }  

关于AroundAdivce,其本身就是一个MethodInterceptor,所以不需要额外做转换了。

细心的你会发现,在拦截器串中,每个拦截器最后都会调用MethodInvocation的proceed()方法。如果按照简单的拦截器的执行串来执行的话,MethodInvocation的proceed()方法至少要执行N次(N表示拦截器Interceptor的个数),因为每个拦截器都会调用一次proceed()方法。更直观地讲,比如我们调用了ticketService.sellTicket()方法,那么,按照这个逻辑,我们会打印出四条记录:

[plain]  view plain  copy
 print ? 在CODE上查看代码片 派生到我的代码片
  1. 售票............  
  2. 售票............  
  3. 售票............  
  4. 售票............  
这样我们肯定不是我们需要的结果!!!!因为按照我们的理解,只应该有一条"售票............"才对。真实的Spring的方法调用过程能够控制这个逻辑按照我们的思路执行,Spring将这个整个方法调用过程连同若干个Advice组成的拦截器链组合成ReflectiveMethodInvocation对象,让我们来看看这一执行逻辑是怎么控制的:

[java]  view plain  copy
 print ? 在CODE上查看代码片 派生到我的代码片
  1. public class ReflectiveMethodInvocation implements ProxyMethodInvocation, Cloneable {  
  2.   
  3.     protected final Object proxy;  
  4.   
  5.     protected final Object target;  
  6.   
  7.     protected final Method method;  
  8.   
  9.     protected Object[] arguments;  
  10.   
  11.     private final Class<?> targetClass;  
  12.   
  13.     /** 
  14.      * Lazily initialized map of user-specific attributes for this invocation. 
  15.      */  
  16.     private Map<String, Object> userAttributes;  
  17.   
  18.     /** 
  19.      * List of MethodInterceptor and InterceptorAndDynamicMethodMatcher 
  20.      * that need dynamic checks. 
  21.      */  
  22.     protected final List<?> interceptorsAndDynamicMethodMatchers;  
  23.   
  24.     /** 
  25.      * Index from 0 of the current interceptor we're invoking. 
  26.      * -1 until we invoke: then the current interceptor. 
  27.      */  
  28.     private int currentInterceptorIndex = -1;  
  29.   
  30.   
  31.     /** 
  32.      * Construct a new ReflectiveMethodInvocation with the given arguments. 
  33.      * @param proxy the proxy object that the invocation was made on 
  34.      * @param target the target object to invoke 
  35.      * @param method the method to invoke 
  36.      * @param arguments the arguments to invoke the method with 
  37.      * @param targetClass the target class, for MethodMatcher invocations 
  38.      * @param interceptorsAndDynamicMethodMatchers interceptors that should be applied, 
  39.      * along with any InterceptorAndDynamicMethodMatchers that need evaluation at runtime. 
  40.      * MethodMatchers included in this struct must already have been found to have matched 
  41.      * as far as was possibly statically. Passing an array might be about 10% faster, 
  42.      * but would complicate the code. And it would work only for static pointcuts. 
  43.      */  
  44.     protected ReflectiveMethodInvocation(  
  45.             Object proxy, Object target, Method method, Object[] arguments,  
  46.             Class<?> targetClass, List<Object> interceptorsAndDynamicMethodMatchers) {  
  47.   
  48.         this.proxy = proxy;//proxy对象  
  49.         this.target = target;//真实的realSubject对象  
  50.         this.targetClass = targetClass;//被代理的类类型  
  51.         this.method = BridgeMethodResolver.findBridgedMethod(method);//方法引用  
  52.         this.arguments = AopProxyUtils.adaptArgumentsIfNecessary(method, arguments);//调用参数  
  53.         this.interceptorsAndDynamicMethodMatchers = interceptorsAndDynamicMethodMatchers;//Advice拦截器链  
  54.     }  
  55.   
  56.   
  57.     @Override  
  58.     public final Object getProxy() {  
  59.         return this.proxy;  
  60.     }  
  61.   
  62.     @Override  
  63.     public final Object getThis() {  
  64.         return this.target;  
  65.     }  
  66.   
  67.     @Override  
  68.     public final AccessibleObject getStaticPart() {  
  69.         return this.method;  
  70.     }  
  71.   
  72.     /** 
  73.      * Return the method invoked on the proxied interface. 
  74.      * May or may not correspond with a method invoked on an underlying 
  75.      * implementation of that interface. 
  76.      */  
  77.     @Override  
  78.     public final Method getMethod() {  
  79.         return this.method;  
  80.     }  
  81.   
  82.     @Override  
  83.     public final Object[] getArguments() {  
  84.         return (this.arguments != null ? this.arguments : new Object[0]);  
  85.     }  
  86.   
  87.     @Override  
  88.     public void setArguments(Object... arguments) {  
  89.         this.arguments = arguments;  
  90.     }  
  91.   
  92.   
  93.     @Override  
  94.     public Object proceed() throws Throwable {  
  95.         //  没有拦截器,则直接调用Joinpoint上的method,即直接调用MethodInvocation We start with an index of -1 and increment early.  
  96.         if (this.currentInterceptorIndex == this.interceptorsAndDynamicMethodMatchers.size() - 1) {  
  97.             return invokeJoinpoint();  
  98.         }  
  99.                 // 取得第拦截器链上第N个拦截器   
  100.         Object interceptorOrInterceptionAdvice =  
  101.                 this.interceptorsAndDynamicMethodMatchers.get(++this.currentInterceptorIndex);  
  102.         //PointcutInterceptor会走这个逻辑  
  103.                 if (interceptorOrInterceptionAdvice instanceof InterceptorAndDynamicMethodMatcher) {  
  104.             // Evaluate dynamic method matcher here: static part will already have  
  105.             // been evaluated and found to match.  
  106.             InterceptorAndDynamicMethodMatcher dm =  
  107.                     (InterceptorAndDynamicMethodMatcher) interceptorOrInterceptionAdvice;  
  108.             //当前拦截器是符合拦截规则,每个拦截器可以定义是否特定的类和方法名是否符合拦截规则  
  109.                         //实际上PointCut定义的方法签名最后会转换成这个MethodMatcher,并置于拦截器中  
  110.                         if (dm.methodMatcher.matches(this.method, this.targetClass, this.arguments)) {  
  111.                  //符合拦截规则,调用拦截器invoke()   
  112.                              return dm.interceptor.invoke(this);  
  113.             }  
  114.             else {  
  115.                 // Dynamic matching failed.  
  116.                 // Skip this interceptor and invoke the next in the chain.  
  117.                                 // 当前方法不需要拦截器操作,则直接往前推进  
  118.                                 return proceed();  
  119.             }  
  120.         }  
  121.         else {  
  122.             // It's an interceptor, so we just invoke it: The pointcut will have  
  123.             // been evaluated statically before this object was constructed.  
  124.                         //直接调用拦截器,  
  125.                         return ((MethodInterceptor) interceptorOrInterceptionAdvice).invoke(this);  
  126.         }  
  127.     }  
  128.   
  129.     /** 
  130.      * Invoke the joinpoint using reflection. 
  131.      * Subclasses can override this to use custom invocation. 
  132.      * @return the return value of the joinpoint 
  133.      * @throws Throwable if invoking the joinpoint resulted in an exception 
  134.      */  
  135.     protected Object invokeJoinpoint() throws Throwable {  
  136.         return AopUtils.invokeJoinpointUsingReflection(this.target, this.method, this.arguments);  
  137.     }  

上述的代码比较冗杂,解释起来比较繁琐,请看下面一张图,你就知道这段代码的思路了:



实例分析

根据上面的执行链上的逻辑,我们将我们上面举的例子的输出结果在整理一下:

Advice拦截器的添加顺序:

[java]  view plain  copy
 print ? 在CODE上查看代码片 派生到我的代码片
  1. proxyFactoryBean.addAdvice(afterReturningAdvice);  
  2. proxyFactoryBean.addAdvice(aroundAdvice);  
  3. proxyFactoryBean.addAdvice(throwsAdvice);  
  4. proxyFactoryBean.addAdvice(beforeAdvice);  
第一个拦截器:AfterReturningAdvice

第一个添加的是afterReturningAdivce,它所处的位置是第一个拦截器,执行的操作就是:

[java]  view plain  copy
 print ? 在CODE上查看代码片 派生到我的代码片
  1. @Override  
  2. public Object invoke(MethodInvocation mi) throws Throwable {  
  3.     Object retVal = mi.proceed();  
  4.     this.advice.afterReturning(retVal, mi.getMethod(), mi.getArguments(), mi.getThis());  
  5.     return retVal;  
  6. }  
也就是说,先完成MethodInvocation的proceed()方法再执行相应的advice;而调用了mi.proceed()方法,导致了当前的调用链后移,进行和后续的操作,也就是说,AfterReturningAdvice只能等到整个拦截器链上所有执行完毕后才会生效,所以: AFTER_RETURNING:本次服务已结束.... 这句话排在了最后:


第二个拦截器:AroundAdvice

[java]  view plain  copy
 print ? 在CODE上查看代码片 派生到我的代码片
  1. @Override  
  2. public Object invoke(MethodInvocation invocation) throws Throwable {  
  3.     System.out.println("AROUND_ADVICE:BEGIN....");  
  4.     Object returnValue = invocation.proceed();  
  5.     System.out.println("AROUND_ADVICE:END.....");  
  6.     return returnValue;  
  7. }  
现在执行到了第二个拦截器,首先输出了"AROUND_ADVICE:BEGIN......",接着调用Invocation.proceed(),等到剩余的执行完后,再输出"AROUND_ADVICE:END.....":



第三个拦截器:ThrowsAdvice:

ThrowsAdvice拦截器的处理模式是:

[java]  view plain  copy
 print ? 在CODE上查看代码片 派生到我的代码片
  1. @Override  
  2. public Object invoke(MethodInvocation mi) throws Throwable {  
  3.     try {  
  4.            //先执行invocation.proceed();     
  5.                       return mi.proceed();  
  6.     }  
  7.     catch (Throwable ex) {  
  8.                       //捕捉错误,调用afterThrowing()方法  
  9.                        Method handlerMethod = getExceptionHandler(ex);  
  10.         if (handlerMethod != null) {  
  11.             invokeHandlerMethod(mi, ex, handlerMethod);  
  12.         }  
  13.         throw ex;  
  14.     }  
  15. }  

上述的逻辑是,先执行Invocation.proceed();如果这个过程中抛出异常,则调用ThrowsAdvice。

第四个拦截器:BeforeAdvice:

这个拦截器的工作逻辑如下:

[java]  view plain  copy
 print ? 在CODE上查看代码片 派生到我的代码片
  1. @Override  
  2. public Object invoke(MethodInvocation mi) throws Throwable {  
  3.     this.advice.before(mi.getMethod(), mi.getArguments(), mi.getThis() );//先执行Advice  
  4.     return mi.proceed();//后执行Invocation  
  5. }  

综上所有的拦截器过程,我们就能理解,为什么我们刚开始的输出为什么是下面这样了:



6、PointCut与Advice的结合------Adivce的条件执行

上面我们提供了几个Adivce,你会发现,这些Advice是无条件地加入了我们创建的对象中。无论调用Target的任何方法,这些Advice都会被触发到。

那么,我们可否告诉Advice,只让它对特定的方法或特定类起作用呢? 这个实际上是要求我们添加一个过滤器,如果满足条件,则Advice生效,否则无效。Spring将这个过滤器抽象成如下的接口:

[java]  view plain  copy
 print ? 在CODE上查看代码片 派生到我的代码片
  1. public interface MethodMatcher {  
  2.   
  3.     /** 
  4.      * 提供方法签名和所属的Class类型,判断是否支持  
  5.          * Perform static checking whether the given method matches. If this 
  6.      * returns {@code false} or if the {@link #isRuntime()} method 
  7.      * returns {@code false}, no runtime check (i.e. no. 
  8.      * {@link #matches(java.lang.reflect.Method, Class, Object[])} call) will be made. 
  9.      * @param method the candidate method 
  10.      * @param targetClass the target class (may be {@code null}, in which case 
  11.      * the candidate class must be taken to be the method's declaring class) 
  12.      * @return whether or not this method matches statically 
  13.      */  
  14.     boolean matches(Method method, Class<?> targetClass);  
  15.   
  16.     /** 
  17.      * Is this MethodMatcher dynamic, that is, must a final call be made on the 
  18.      * {@link #matches(java.lang.reflect.Method, Class, Object[])} method at 
  19.      * runtime even if the 2-arg matches method returns {@code true}? 
  20.      * <p>Can be invoked when an AOP proxy is created, and need not be invoked 
  21.      * again before each method invocation, 
  22.      * @return whether or not a runtime match via the 3-arg 
  23.      * {@link #matches(java.lang.reflect.Method, Class, Object[])} method 
  24.      * is required if static matching passed 
  25.      */  
  26.     boolean isRuntime();  
  27.   
  28.     /** 
  29.      * Check whether there a runtime (dynamic) match for this method, 
  30.      * which must have matched statically. 
  31.      * <p>This method is invoked only if the 2-arg matches method returns 
  32.      * {@code true} for the given method and target class, and if the 
  33.      * {@link #isRuntime()} method returns {@code true}. Invoked 
  34.      * immediately before potential running of the advice, after any 
  35.      * advice earlier in the advice chain has run. 
  36.      * @param method the candidate method 
  37.      * @param targetClass the target class (may be {@code null}, in which case 
  38.      * the candidate class must be taken to be the method's declaring class) 
  39.      * @param args arguments to the method 
  40.      * @return whether there's a runtime match 
  41.      * @see MethodMatcher#matches(Method, Class) 
  42.      */  
  43.     boolean matches(Method method, Class<?> targetClass, Object... args);  
  44.   
  45.   
  46.     /** 
  47.      * Canonical instance that matches all methods. 
  48.      */  
  49.     MethodMatcher TRUE = TrueMethodMatcher.INSTANCE;  
  50.   
  51. }  

将这个匹配器MethodMatcher和拦截器Interceptor 结合到一起,就构成了一个新的类InterceptorAndDynamicMethodMatcher :

[java]  view plain  copy
 print ? 在CODE上查看代码片 派生到我的代码片
  1. /** 
  2.  * Internal framework class, combining a MethodInterceptor instance 
  3.  * with a MethodMatcher for use as an element in the advisor chain. 
  4.  * 
  5.  * @author Rod Johnson 
  6.  */  
  7. class InterceptorAndDynamicMethodMatcher {  
  8.   
  9.     final MethodInterceptor interceptor;  
  10.   
  11.     final MethodMatcher methodMatcher;  
  12.   
  13.     public InterceptorAndDynamicMethodMatcher(MethodInterceptor interceptor, MethodMatcher methodMatcher) {  
  14.         this.interceptor = interceptor;  
  15.         this.methodMatcher = methodMatcher;  
  16.     }  
  17.   
  18. }  
我们再将上述的包含整个拦截器执行链逻辑的ReflectiveMethodInvocation实现的核心代码在过一遍:

[java]  view plain  copy
 print ? 在CODE上查看代码片 派生到我的代码片
  1. @Override  
  2. public Object proceed() throws Throwable {  
  3.     //  We start with an index of -1 and increment early.  
  4.     if (this.currentInterceptorIndex == this.interceptorsAndDynamicMethodMatchers.size() - 1) {  
  5.         return invokeJoinpoint();  
  6.     }  
  7.   
  8.     Object interceptorOrInterceptionAdvice =  
  9.             this.interceptorsAndDynamicMethodMatchers.get(++this.currentInterceptorIndex);  
  10.     //起到一定的过滤作用,如果不匹配,则直接skip  
  11.                if (interceptorOrInterceptionAdvice instanceof InterceptorAndDynamicMethodMatcher) {  
  12.         // Evaluate dynamic method matcher here: static part will already have  
  13.         // been evaluated and found to match.  
  14.         InterceptorAndDynamicMethodMatcher dm =  
  15.                 (InterceptorAndDynamicMethodMatcher) interceptorOrInterceptionAdvice;  
  16.         //满足匹配规则,则拦截器Advice生效  
  17.                        if (dm.methodMatcher.matches(this.method, this.targetClass, this.arguments)) {  
  18.             return dm.interceptor.invoke(this);  
  19.         }  
  20.         else {  
  21.             // Dynamic matching failed.  
  22.             // Skip this interceptor and invoke the next in the chain.  
  23.                                //拦截器尚未生效,直接skip  
  24.                                return proceed();  
  25.         }  
  26.     }  
  27.     else {  
  28.         // It's an interceptor, so we just invoke it: The pointcut will have  
  29.         // been evaluated statically before this object was constructed.  
  30.         return ((MethodInterceptor) interceptorOrInterceptionAdvice).invoke(this);  
  31.     }  
  32. }  

实战:

我们现在实现一个PointcutAdisor,PointcutAdvisor表示拥有某个Pointcut的Advisor。

[java]  view plain  copy
 print ? 在CODE上查看代码片 派生到我的代码片
  1. package org.luanlouis.meditations.thinkinginspring.aop;  
  2.   
  3. import org.aopalliance.aop.Advice;  
  4. import org.springframework.aop.Pointcut;  
  5. import org.springframework.aop.PointcutAdvisor;  
  6.   
  7. /** 
  8.  * 实现一个PointcutAdvisor,通过提供的Pointcut,对Advice的执行进行过滤 
  9.  * Created by louis on 2016/4/16. 
  10.  */  
  11. public class FilteredAdvisor implements PointcutAdvisor {  
  12.   
  13.     private Pointcut pointcut;  
  14.     private Advice advice;  
  15.   
  16.     public FilteredAdvisor(Pointcut pointcut, Advice advice) {  
  17.         this.pointcut = pointcut;  
  18.         this.advice = advice;  
  19.     }  
  20.   
  21.     /** 
  22.      * Get the Pointcut that drives this advisor. 
  23.      */  
  24.     @Override  
  25.     public Pointcut getPointcut() {  
  26.         return pointcut;  
  27.     }  
  28.   
  29.     @Override  
  30.     public Advice getAdvice() {  
  31.         return advice;  
  32.     }  
  33.   
  34.     @Override  
  35.     public boolean isPerInstance() {  
  36.         return false;  
  37.     }  
  38. }  

[java]  view plain  copy
 print ? 在CODE上查看代码片 派生到我的代码片
  1. package org.luanlouis.meditations.thinkinginspring.aop;  
  2.   
  3. import org.aopalliance.aop.Advice;  
  4. import org.springframework.aop.aspectj.AspectJExpressionPointcut;  
  5. import org.springframework.aop.framework.ProxyFactoryBean;  
  6.   
  7. /** 
  8.  * 通过ProxyFactoryBean 手动创建 代理对象 
  9.  * Created by louis on 2016/4/14. 
  10.  */  
  11. public class App {  
  12.   
  13.     public static void main(String[] args) throws Exception {  
  14.   
  15.         //1.针对不同的时期类型,提供不同的Advice  
  16.         Advice beforeAdvice = new TicketServiceBeforeAdvice();  
  17.         Advice afterReturningAdvice = new TicketServiceAfterReturningAdvice();  
  18.         Advice aroundAdvice = new TicketServiceAroundAdvice();  
  19.         Advice throwsAdvice = new TicketServiceThrowsAdvice();  
  20.   
  21.         RailwayStation railwayStation = new RailwayStation();  
  22.   
  23.         //2.创建ProxyFactoryBean,用以创建指定对象的Proxy对象  
  24.         ProxyFactoryBean proxyFactoryBean = new ProxyFactoryBean();  
  25.        //3.设置Proxy的接口  
  26.         proxyFactoryBean.setInterfaces(TicketService.class);  
  27.         //4. 设置RealSubject  
  28.         proxyFactoryBean.setTarget(railwayStation);  
  29.         //5.使用JDK基于接口实现机制的动态代理生成Proxy代理对象,如果想使用CGLIB,需要将这个flag设置成true  
  30.         proxyFactoryBean.setProxyTargetClass(true);  
  31.   
  32.         //5. 添加不同的Advice  
  33.   
  34.         proxyFactoryBean.addAdvice(afterReturningAdvice);  
  35.         proxyFactoryBean.addAdvice(aroundAdvice);  
  36.         proxyFactoryBean.addAdvice(throwsAdvice);  
  37.         //proxyFactoryBean.addAdvice(beforeAdvice);  
  38.         proxyFactoryBean.setProxyTargetClass(false);  
  39.   
  40.         //手动创建一个pointcut,专门拦截sellTicket方法  
  41.         AspectJExpressionPointcut pointcut = new AspectJExpressionPointcut();  
  42.         pointcut.setExpression("execution( * sellTicket(..))");  
  43.         //传入创建的beforeAdvice和pointcut  
  44.         FilteredAdvisor sellBeforeAdvior = new FilteredAdvisor(pointcut,beforeAdvice);  
  45.         //添加到FactoryBean中  
  46.         proxyFactoryBean.addAdvisor(sellBeforeAdvior);  
  47.           
  48.         //通过ProxyFactoryBean生成  
  49.         TicketService ticketService = (TicketService) proxyFactoryBean.getObject();  
  50.         ticketService.sellTicket();  
  51.         System.out.println("---------------------------");  
  52.         ticketService.inquire();  
  53.   
  54.     }  
  55.   
  56.   
  57. }  

这个时候,你会看到输出:

从结果中你可以清晰地看到,我们可以对某一个Advisor(即Advice)添加一个pointcut限制,这样就可以针对指定的方法执行Advice了!本例中使用了PointcutAdvisor,实际上,带底层代码中,Spring会将PointcutAdvisor转换成InterceptorAndDynamicMethodMatcher 参与ReflectiveMethodInvocation关于拦截器链的执行逻辑:

[java]  view plain  copy
 print ? 在CODE上查看代码片 派生到我的代码片
  1. public class DefaultAdvisorChainFactory implements AdvisorChainFactory, Serializable {  
  2.   
  3.     @Override  
  4.     public List<Object> getInterceptorsAndDynamicInterceptionAdvice(  
  5.             Advised config, Method method, Class<?> targetClass) {  
  6.   
  7.         // This is somewhat tricky... We have to process introductions first,  
  8.         // but we need to preserve order in the ultimate list.  
  9.         List<Object> interceptorList = new ArrayList<Object>(config.getAdvisors().length);  
  10.         Class<?> actualClass = (targetClass != null ? targetClass : method.getDeclaringClass());  
  11.         boolean hasIntroductions = hasMatchingIntroductions(config, actualClass);  
  12.         AdvisorAdapterRegistry registry = GlobalAdvisorAdapterRegistry.getInstance();  
  13.                   
  14.         for (Advisor advisor : config.getAdvisors()) {  
  15.                                 //PointcutAdvisor向 InterceptorAndDynamicMethodMatcher 的转换    
  16.                                if (advisor instanceof PointcutAdvisor) {  
  17.                 // Add it conditionally.  
  18.                 PointcutAdvisor pointcutAdvisor = (PointcutAdvisor) advisor;  
  19.                 if (config.isPreFiltered() || pointcutAdvisor.getPointcut().getClassFilter().matches(actualClass)) {  
  20.                     MethodInterceptor[] interceptors = registry.getInterceptors(advisor);  
  21.                     MethodMatcher mm = pointcutAdvisor.getPointcut().getMethodMatcher();  
  22.                     if (MethodMatchers.matches(mm, method, actualClass, hasIntroductions)) {  
  23.                         if (mm.isRuntime()) {  
  24.                             // Creating a new object instance in the getInterceptors() method  
  25.                             // isn't a problem as we normally cache created chains.  
  26.                             for (MethodInterceptor interceptor : interceptors) {  
  27.                                 interceptorList.add(new InterceptorAndDynamicMethodMatcher(interceptor, mm));  
  28.                             }  
  29.                         }  
  30.                         else {  
  31.                             interceptorList.addAll(Arrays.asList(interceptors));  
  32.                         }  
  33.                     }  
  34.                 }  
  35.             }  
  36.             else if (advisor instanceof IntroductionAdvisor) {  
  37.                 IntroductionAdvisor ia = (IntroductionAdvisor) advisor;  
  38.                 if (config.isPreFiltered() || ia.getClassFilter().matches(actualClass)) {  
  39.                     Interceptor[] interceptors = registry.getInterceptors(advisor);  
  40.                     interceptorList.addAll(Arrays.asList(interceptors));  
  41.                 }  
  42.             }  
  43.             else {  
  44.                 Interceptor[] interceptors = registry.getInterceptors(advisor);  
  45.                 interceptorList.addAll(Arrays.asList(interceptors));  
  46.             }  
  47.         }  
  48.   
  49.         return interceptorList;  
  50.     }  
  51.   
  52.     /** 
  53.      * Determine whether the Advisors contain matching introductions. 
  54.      */  
  55.     private static boolean hasMatchingIntroductions(Advised config, Class<?> actualClass) {  
  56.         for (int i = 0; i < config.getAdvisors().length; i++) {  
  57.             Advisor advisor = config.getAdvisors()[i];  
  58.             if (advisor instanceof IntroductionAdvisor) {  
  59.                 IntroductionAdvisor ia = (IntroductionAdvisor) advisor;  
  60.                 if (ia.getClassFilter().matches(actualClass)) {  
  61.                     return true;  
  62.                 }  
  63.             }  
  64.         }  
  65.         return false;  
  66.     }  
  67.   
  68. }  


7、总结

            至此,你已经了解了Spring的AOP的精髓,以及Spring的整个工作机制。我个人认为,想要理解Spring AOP,你需要从ProxyFactoryBean 开始,逐步地分析整个代理的构建过程:

            1. 代理对象是怎么生成的(JDK or Cglib)

            2. Advice链(即拦截器链)的构造过程以及执行机制

            3. 如何在Advice上添加pointcut,并且这个pointcut是如何工作的(实际上起到的过滤作用)

      

           最后再讲一下性能问题,如上面描述的,Spring创建Proxy的过程逻辑虽然很清晰,但是你也看到,对于我们每一个方法调用,都会经过非常复杂的层层Advice拦截判断,是否需要拦截处理,这个开销是非常大的。记得Spring的documentation介绍,如果使用Spring的AOP,对项目而言会造成10%的性能消耗,So,用AOP之前要仔细考虑一下性能问题~~~~~


             



作者的话

     本文使用的源码,已经托管到Github上,读者可以自行clone查看测验~

      源码地址:https://github.com/LuanLouis/thinking-in-spring.git ,请fetch branch : aop-principle   分支~


本文关于Spring AOP的设计原理仅是本人个人的见解和看法,如有任何疑问和错误,请不吝指出,敬请赐教,共同进步!


;