AOP实现原理(基于JDK和基于CGLIB)

转自:《Spring设计思想》AOP实现原理(基于JDK和基于CGLIB)

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的方法时的各个阶段,插入对应的业务代码。

  1. package org.luanlouis.meditations.thinkinginspring.aop;
  2. /**
  3.  * 售票服务
  4.  * Created by louis on 2016/4/14.
  5.  */
  6. public interface TicketService {
  7.     //售票
  8.     public void sellTicket();
  9.     //问询
  10.     public void inquire();
  11.     //退票
  12.     public void withdraw();
  13. }

 

  1. package org.luanlouis.meditations.thinkinginspring.aop;
  2. /**
  3.  * RailwayStation 实现 TicketService
  4.  * Created by louis on 2016/4/14.
  5.  */
  6. public class RailwayStation implements TicketService {
  7.     public void sellTicket(){
  8.         System.out.println(“售票…………”);
  9.     }
  10.     public void inquire() {
  11.         System.out.println(“问询………….”);
  12.     }
  13.     public void withdraw() {
  14.         System.out.println(“退票………….”);
  15.     }
  16. }

 

  1. package org.luanlouis.meditations.thinkinginspring.aop;
  2. import org.springframework.aop.MethodBeforeAdvice;
  3. import java.lang.reflect.Method;
  4. /**
  5.  * 执行RealSubject对象的方法之前的处理意见
  6.  * Created by louis on 2016/4/14.
  7.  */
  8. public class TicketServiceBeforeAdvice implements MethodBeforeAdvice {
  9.     public void before(Method method, Object[] args, Object target) throws Throwable {
  10.         System.out.println(“BEFORE_ADVICE: 欢迎光临代售点….”);
  11.     }
  12. }

 

  1. package org.luanlouis.meditations.thinkinginspring.aop;
  2. import org.springframework.aop.AfterReturningAdvice;
  3. import java.lang.reflect.Method;
  4. /**
  5.  * 返回结果时后的处理意见
  6.  * Created by louis on 2016/4/14.
  7.  */
  8. public class TicketServiceAfterReturningAdvice implements AfterReturningAdvice {
  9.     @Override
  10.     public void afterReturning(Object returnValue, Method method, Object[] args, Object target) throws Throwable {
  11.         System.out.println(“AFTER_RETURNING:本次服务已结束….”);
  12.     }
  13. }

 

  1. package org.luanlouis.meditations.thinkinginspring.aop;
  2. import org.springframework.aop.ThrowsAdvice;
  3. import java.lang.reflect.Method;
  4. /**
  5.  * 抛出异常时的处理意见
  6.  * Created by louis on 2016/4/14.
  7.  */
  8. public class TicketServiceThrowsAdvice implements ThrowsAdvice {
  9.     public void afterThrowing(Exception ex){
  10.         System.out.println(“AFTER_THROWING….”);
  11.     }
  12.     public void afterThrowing(Method method, Object[] args, Object target, Exception ex){
  13.         System.out.println(“调用过程出错啦!!!!!”);
  14.     }
  15. }
  1. package org.luanlouis.meditations.thinkinginspring.aop;
  2. import org.aopalliance.intercept.MethodInterceptor;
  3. import org.aopalliance.intercept.MethodInvocation;
  4. import org.springframework.aop.aspectj.AspectJAroundAdvice;
  5. /**
  6.  *
  7.  * AroundAdvice
  8.  * Created by louis on 2016/4/15.
  9.  */
  10. public class TicketServiceAroundAdvice implements MethodInterceptor {
  11.     @Override
  12.     public Object invoke(MethodInvocation invocation) throws Throwable {
  13.         System.out.println(“AROUND_ADVICE:BEGIN….”);
  14.         Object returnValue = invocation.proceed();
  15.         System.out.println(“AROUND_ADVICE:END…..”);
  16.         return returnValue;
  17.     }
  18. }

 

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

 

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

 

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

你会看到,我们成功地创建了一个通过一个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()方法中。

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

 

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

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

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

 

 

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

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

比如我们上述的代码:

  1. //5. 添加不同的Advice
  2. proxyFactoryBean.addAdvice(afterReturningAdvice);
  3. proxyFactoryBean.addAdvice(aroundAdvice);
  4. proxyFactoryBean.addAdvice(throwsAdvice);
  5. proxyFactoryBean.addAdvice(beforeAdvice);
  6. proxyFactoryBean.setProxyTargetClass(false);
  7. //通过ProxyFactoryBean生成
  8. TicketService ticketService = (TicketService) proxyFactoryBean.getObject();
  9. ticketService.sellTicket();

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

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

  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.     private MethodBeforeAdvice advice;
  12.     /**
  13.      * Create a new MethodBeforeAdviceInterceptor for the given advice.
  14.      * @param advice the MethodBeforeAdvice to wrap
  15.      */
  16.     public MethodBeforeAdviceInterceptor(MethodBeforeAdvice advice) {
  17.         Assert.notNull(advice, “Advice must not be null”);
  18.         this.advice = advice;
  19.     }
  20.     @Override
  21.     public Object invoke(MethodInvocation mi) throws Throwable {
  22.         //在调用方法之前,先执行BeforeAdvice
  23.         this.advice.before(mi.getMethod(), mi.getArguments(), mi.getThis() );
  24.         return mi.proceed();
  25.     }
  26. }

 

  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.     private final AfterReturningAdvice advice;
  12.     /**
  13.      * Create a new AfterReturningAdviceInterceptor for the given advice.
  14.      * @param advice the AfterReturningAdvice to wrap
  15.      */
  16.     public AfterReturningAdviceInterceptor(AfterReturningAdvice advice) {
  17.         Assert.notNull(advice, “Advice must not be null”);
  18.         this.advice = advice;
  19.     }
  20.     @Override
  21.     public Object invoke(MethodInvocation mi) throws Throwable {
  22.         //先调用invocation
  23.         Object retVal = mi.proceed();
  24.         //调用成功后,调用AfterReturningAdvice
  25.         this.advice.afterReturning(retVal, mi.getMethod(), mi.getArguments(), mi.getThis());
  26.         return retVal;
  27.     }
  28. }

 

  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.     private static final String AFTER_THROWING = “afterThrowing”;
  25.     private static final Log logger = LogFactory.getLog(ThrowsAdviceInterceptor.class);
  26.     private final Object throwsAdvice;
  27.     /** Methods on throws advice, keyed by exception class */
  28.     private final Map<Class<?>, Method> exceptionHandlerMap = new HashMap<Class<?>, Method>();
  29.     /**
  30.      * Create a new ThrowsAdviceInterceptor for the given ThrowsAdvice.
  31.      * @param throwsAdvice the advice object that defines the exception
  32.      * handler methods (usually a {@link org.springframework.aop.ThrowsAdvice}
  33.      * implementation)
  34.      */
  35.     public ThrowsAdviceInterceptor(Object throwsAdvice) {
  36.         Assert.notNull(throwsAdvice, “Advice must not be null”);
  37.         this.throwsAdvice = throwsAdvice;
  38.         Method[] methods = throwsAdvice.getClass().getMethods();
  39.         for (Method method : methods) {
  40.             //ThrowsAdvice定义的afterThrowing方法是Handler方法
  41.             if (method.getName().equals(AFTER_THROWING) &&
  42.                     (method.getParameterTypes().length == 1 || method.getParameterTypes().length == 4) &&
  43.                     Throwable.class.isAssignableFrom(method.getParameterTypes()[method.getParameterTypes().length – 1])
  44.                 ) {
  45.                 // Have an exception handler
  46.                 this.exceptionHandlerMap.put(method.getParameterTypes()[method.getParameterTypes().length – 1], method);
  47.                 if (logger.isDebugEnabled()) {
  48.                     logger.debug(“Found exception handler method: “ + method);
  49.                 }
  50.             }
  51.         }
  52.         if (this.exceptionHandlerMap.isEmpty()) {
  53.             throw new IllegalArgumentException(
  54.                     “At least one handler method must be found in class [“ + throwsAdvice.getClass() + “]”);
  55.         }
  56.     }
  57.     public int getHandlerMethodCount() {
  58.         return this.exceptionHandlerMap.size();
  59.     }
  60.     /**
  61.      * Determine the exception handle method. Can return null if not found.
  62.      * @param exception the exception thrown
  63.      * @return a handler for the given exception type
  64.      */
  65.     private Method getExceptionHandler(Throwable exception) {
  66.         Class<?> exceptionClass = exception.getClass();
  67.         if (logger.isTraceEnabled()) {
  68.             logger.trace(“Trying to find handler for exception of type [“ + exceptionClass.getName() + “]”);
  69.         }
  70.         Method handler = this.exceptionHandlerMap.get(exceptionClass);
  71.         while (handler == null && exceptionClass != Throwable.class) {
  72.             exceptionClass = exceptionClass.getSuperclass();
  73.             handler = this.exceptionHandlerMap.get(exceptionClass);
  74.         }
  75.         if (handler != null && logger.isDebugEnabled()) {
  76.             logger.debug(“Found handler for exception of type [“ + exceptionClass.getName() + “]: “ + handler);
  77.         }
  78.         return handler;
  79.     }
  80.     @Override
  81.     public Object invoke(MethodInvocation mi) throws Throwable {
  82.         //使用大的try,先执行代码,捕获异常
  83.         try {
  84.             return mi.proceed();
  85.         }
  86.         catch (Throwable ex) {
  87.             //获取异常处理方法
  88.             Method handlerMethod = getExceptionHandler(ex);
  89.             //调用异常处理方法
  90.             if (handlerMethod != null) {
  91.                 invokeHandlerMethod(mi, ex, handlerMethod);
  92.             }
  93.             throw ex;
  94.         }
  95.     }
  96.     private void invokeHandlerMethod(MethodInvocation mi, Throwable ex, Method method) throws Throwable {
  97.         Object[] handlerArgs;
  98.         if (method.getParameterTypes().length == 1) {
  99.             handlerArgs = new Object[] { ex };
  100.         }
  101.         else {
  102.             handlerArgs = new Object[] {mi.getMethod(), mi.getArguments(), mi.getThis(), ex};
  103.         }
  104.         try {
  105.             method.invoke(this.throwsAdvice, handlerArgs);
  106.         }
  107.         catch (InvocationTargetException targetEx) {
  108.             throw targetEx.getTargetException();
  109.         }
  110.     }
  111. }

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

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

  1. 售票…………
  2. 售票…………
  3. 售票…………
  4. 售票…………

这样我们肯定不是我们需要的结果!!!!因为按照我们的理解,只应该有一条“售票…………”才对。真实的Spring的方法调用过程能够控制这个逻辑按照我们的思路执行,Spring将这个整个方法调用过程连同若干个Advice组成的拦截器链组合成ReflectiveMethodInvocation对象,让我们来看看这一执行逻辑是怎么控制的:

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

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

 

实例分析

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

Advice拦截器的添加顺序:

  1. proxyFactoryBean.addAdvice(afterReturningAdvice);
  2. proxyFactoryBean.addAdvice(aroundAdvice);
  3. proxyFactoryBean.addAdvice(throwsAdvice);
  4. proxyFactoryBean.addAdvice(beforeAdvice);

第一个拦截器:AfterReturningAdvice

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

  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

  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拦截器的处理模式是:

  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:

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

  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将这个过滤器抽象成如下的接口:

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

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

  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.     final MethodInterceptor interceptor;
  9.     final MethodMatcher methodMatcher;
  10.     public InterceptorAndDynamicMethodMatcher(MethodInterceptor interceptor, MethodMatcher methodMatcher) {
  11.         this.interceptor = interceptor;
  12.         this.methodMatcher = methodMatcher;
  13.     }
  14. }

我们再将上述的包含整个拦截器执行链逻辑的ReflectiveMethodInvocation实现的核心代码在过一遍:

  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.     Object interceptorOrInterceptionAdvice =
  8.             this.interceptorsAndDynamicMethodMatchers.get(++this.currentInterceptorIndex);
  9.     //起到一定的过滤作用,如果不匹配,则直接skip
  10.                if (interceptorOrInterceptionAdvice instanceof InterceptorAndDynamicMethodMatcher) {
  11.         // Evaluate dynamic method matcher here: static part will already have
  12.         // been evaluated and found to match.
  13.         InterceptorAndDynamicMethodMatcher dm =
  14.                 (InterceptorAndDynamicMethodMatcher) interceptorOrInterceptionAdvice;
  15.         //满足匹配规则,则拦截器Advice生效
  16.                        if (dm.methodMatcher.matches(this.method, this.targetClass, this.arguments)) {
  17.             return dm.interceptor.invoke(this);
  18.         }
  19.         else {
  20.             // Dynamic matching failed.
  21.             // Skip this interceptor and invoke the next in the chain.
  22.                                //拦截器尚未生效,直接skip
  23.                                return proceed();
  24.         }
  25.     }
  26.     else {
  27.         // It’s an interceptor, so we just invoke it: The pointcut will have
  28.         // been evaluated statically before this object was constructed.
  29.         return ((MethodInterceptor) interceptorOrInterceptionAdvice).invoke(this);
  30.     }
  31. }

实战:

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

  1. package org.luanlouis.meditations.thinkinginspring.aop;
  2. import org.aopalliance.aop.Advice;
  3. import org.springframework.aop.Pointcut;
  4. import org.springframework.aop.PointcutAdvisor;
  5. /**
  6.  * 实现一个PointcutAdvisor,通过提供的Pointcut,对Advice的执行进行过滤
  7.  * Created by louis on 2016/4/16.
  8.  */
  9. public class FilteredAdvisor implements PointcutAdvisor {
  10.     private Pointcut pointcut;
  11.     private Advice advice;
  12.     public FilteredAdvisor(Pointcut pointcut, Advice advice) {
  13.         this.pointcut = pointcut;
  14.         this.advice = advice;
  15.     }
  16.     /**
  17.      * Get the Pointcut that drives this advisor.
  18.      */
  19.     @Override
  20.     public Pointcut getPointcut() {
  21.         return pointcut;
  22.     }
  23.     @Override
  24.     public Advice getAdvice() {
  25.         return advice;
  26.     }
  27.     @Override
  28.     public boolean isPerInstance() {
  29.         return false;
  30.     }
  31. }

 

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

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

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

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

 

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的设计原理仅是本人个人的见解和看法,如有任何疑问和错误,请不吝指出,敬请赐教,共同进步!

此条目发表在java分类目录,贴了标签。将固定链接加入收藏夹。

发表评论

电子邮件地址不会被公开。 必填项已用*标注