Spring AOP代理的生成

888 阅读35分钟

封装 Advisor创建代理获取代理获取目标方法的拦截器启动拦截器链执行目标方法总结参考文献

紧接着上文,在获取了所有对应 Bean 的增强器后,便可以进行代理的创建了。

回到 postProcesssAfterIntialization 方法中,在我们分析完 getAdvicesAndAdvisorsForBean()后,还有一个 createProxy 方法。

protected Object createProxy(Class<?> beanClass, @Nullable String beanName, @Nullable Object[] specificInterceptors, TargetSource targetSource) {
    if (this.beanFactory instanceof ConfigurableListableBeanFactory) {
        //指定自动代理Bean的原始目标类         AutoProxyUtils.exposeTargetClass((ConfigurableListableBeanFactory)this.beanFactory, beanName, beanClass);
    }

    ProxyFactory proxyFactory = new ProxyFactory();
    //获取当前类中相关属性
    proxyFactory.copyFrom(this);
    if (!proxyFactory.isProxyTargetClass()) {
        // 决定对于给定的bean是否应该使用targetClass而不是它的接口代理,
        // 检査 proxyTargetClass 设置以及 preserveTargetClass 属性
        if (this.shouldProxyTargetClass(beanClass, beanName)) {
            proxyFactory.setProxyTargetClass(true);
        } else {
            this.evaluateProxyInterfaces(beanClass, proxyFactory);
        }
    }

    Advisor[] advisors = this.buildAdvisors(beanName, specificInterceptors);
    // 加入增强器
    proxyFactory.addAdvisors(advisors);
    // 设置要代理的目标类
    proxyFactory.setTargetSource(targetSource);
    // 定制代理
    this.customizeProxyFactory(proxyFactory);
    // 用来控制代理工厂被配置之后,是否还允许修改通知。
    // 缺省值是false (即在代理被配置之后,不允许修改代理的配置)。
    proxyFactory.setFrozen(this.freezeProxy);
    if (this.advisorsPreFiltered()) {
        proxyFactory.setPreFiltered(true);
    }

    //真正创建代理的方法
    return proxyFactory.getProxy(this.getProxyClassLoader());
}

对于代理类的创建及处理,Spring 委托给了 ProxyFactory 去处理,而在此函数中主要是对 ProxyFactory 的初始化操作,进而对真正的创建代理做准备,这些初始化操作包括以下内容:

  1. 获取当前类中的属性。
  2. 添加代理接口。
  3. 封装 Advisor 并加入到 ProxyFactory 中。
  4. 设置要代理的类。
  5. customizeProxyFactory 函数定制代理。
  6. 进行获取代理操作。

封装 Advisor

其中,封装 Advisor 并加入到 ProxyFactory 中以及创建代理工作量比较大,所以我们就来看一下 buildAdvisors()

   protected Advisor[] buildAdvisors(@Nullable String beanName, @Nullable Object[] specificInterceptors) {
        Advisor[] commonInterceptors = this.resolveInterceptorNames();
        List<Object> allInterceptors = new ArrayList();
        if (specificInterceptors != null) {
            allInterceptors.addAll(Arrays.asList(specificInterceptors));
            if (commonInterceptors.length > 0) {
                if (this.applyCommonInterceptorsFirst) {
                    allInterceptors.addAll(0, Arrays.asList(commonInterceptors));
                } else {
                    allInterceptors.addAll(Arrays.asList(commonInterceptors));
                }
            }
        }

        int i;
        if (this.logger.isTraceEnabled()) {
            int nrOfCommonInterceptors = commonInterceptors.length;
            i = specificInterceptors != null ? specificInterceptors.length : 0;
            this.logger.trace("Creating implicit proxy for bean '" + beanName + "' with " + nrOfCommonInterceptors + " common interceptors and " + i + " specific interceptors");
        }

        Advisor[] advisors = new Advisor[allInterceptors.size()];

        for(i = 0; i < allInterceptors.size(); ++i) {
            advisors[i] = this.advisorAdapterRegistry.wrap(allInterceptors.get(i));
        }

        return advisors;
    }

上述方法中会涉及到适配器模式的应用,我们转到 DefaultAdvisorAdapterRegistry 类中,查看其 wrap 方法。

   public Advisor wrap(Object adviceObject) throws UnknownAdviceTypeException {
        if (adviceObject instanceof Advisor) {
            return (Advisor)adviceObject;
        } else if (!(adviceObject instanceof Advice)) {
            throw new UnknownAdviceTypeException(adviceObject);
        } else {
            Advice advice = (Advice)adviceObject;
            if (advice instanceof MethodInterceptor) {
                //如果是MethodInterceptor类型,则封装为DefaultPointcutAdvisor
                return new DefaultPointcutAdvisor(advice);
            } else {
                Iterator var3 = this.adapters.iterator();

                //如果存在Advisor的适配器则也需要进行封装
                AdvisorAdapter adapter;
                do {
                    if (!var3.hasNext()) {
                        throw new UnknownAdviceTypeException(advice);
                    }

                    adapter = (AdvisorAdapter)var3.next();
                } while(!adapter.supportsAdvice(advice));

                return new DefaultPointcutAdvisor(advice);
            }
        }
    }

关于这一部分,我进行了调试追踪,发现该方法的结果如下:

对此我有一个疑问:在创建代理之前,即执行 getAdvicesAndAdvisorsForBean()方法后,我们获取到的结果除了头部对象是 DefaultPointcutAdvisor 类型,其他三个是 Advisor 的实现类 InstantiationModelAwarePointcutAdvisorImpl 类型,执行 wrap 方法中 adviceObject instanceof Advisor 结果都为 true。那么该方法主要是针对什么情景下使用的呢?如果有大神知晓,请不吝赐教。

创建代理

封装完 Advisor 之后就准备进行代理的创建,这也是解析过程中最重要的一步。

    public Object getProxy(@Nullable ClassLoader classLoader) {
        return this.createAopProxy().getProxy(classLoader);
    }

在上面的 getProxy 方法中 createAopProxy 方法,其实现是在 ProxyCreatorSupport 中,其定义如下:

    protected final synchronized AopProxy createAopProxy() {
        if (!this.active) {
            this.activate();
        }

        return this.getAopProxyFactory().createAopProxy(this);
    }

    private void activate() {
        this.active = true;
        Iterator var1 = this.listeners.iterator();

        while(var1.hasNext()) {
            //启动监听器
            AdvisedSupportListener listener = (AdvisedSupportListener)var1.next();
            listener.activated(this);
        }

    }

再次跳转到 DefaultAopProxyFactory 类中,查看 createAopProxy 方法。

    public AopProxy createAopProxy(AdvisedSupport config) throws AopConfigException {
        if (!config.isOptimize() && !config.isProxyTargetClass() && !this.hasNoUserSuppliedProxyInterfaces(config)) {
            return new JdkDynamicAopProxy(config);
        } else {
            Class<?> targetClass = config.getTargetClass();
            if (targetClass == null) {
                throw new AopConfigException("TargetSource cannot determine target class: Either an interface or a target is required for proxy creation.");
            } else {
                //手动设置创建Cglib代理类后,如果目标bean是一个接口,则创建jdk代理类
                return (AopProxy)(!targetClass.isInterface() && !Proxy.isProxyClass(targetClass) ? new ObjenesisCglibAopProxy(config) : new JdkDynamicAopProxy(config));
            }
        }
    }

我们在 代理模式一文中知道 Spring 的代理是通过 JDKProxy 的实现或 CglibProxy 实现。Spring 是如何选取的呢?

从 if 中的判断条件可以看到3个方面影响着 Spring 的判断。

  • optimize:用来控制通过CGLIB创建的代理是否使用激进的优化策略,除非完全了解AOP代理如何处理优化,否则不推荐用户使用这个设置。目前这个属性仅用于CGLIB 代理,对于JDK动态代理(缺省代理)无效。
  • proxyTargetClass:这个属性为true时,目标类本身被代理而不是目标类的接口。如果这个属性值被设为true,CGLIB代理将被创建,设置方式:
  • hasNoUserSuppliedProxylnterfaces:是否存在代理接口

下面是对JDK与Cglib方式的总结。

  • 如果目标对象实现了接口,默认情况下会采用JDK的动态代理实现AOP。
  • 如果目标对象实现了接口,可以强制使用CGLIB实现AOP。
  • 如果目标对象没有实现了接口,必须采用CGLIB库,Spring会自动在JDK动态代理 和CGLIB之间转换。

如何强制使用CGLIB实现AOP?

(1)添加 CGLIB 库,Spring_HOME/cglib/*.jar。

(2)在 Spring 配置文件中加人。

JDK 动态代理和 CGLIB 字节码生成的区别?

JDK 动态代理只能对实现了接口的类生成代理,而不能针对类。

CGLIB 是针对类实现代理,主要是对指定的类生成一个子类,覆盖其中的方法,因为是继承,所以该类或方法最好不要声明成 final。

获取代理

本文主要介绍 JDK 动态代理类的实现,在此之前,有必要熟悉一下 JDK 代理使用示例,请看我以前的博文 代理模式

Spring 的 AOP 实现其实也是用了 Proxy和InvocationHandler 这两个东西的。

我们再次来回顾一下使用 JDK 代理的方式,在整个创建过程中,对于 InvocationHandler 的创建是最为核心的,关于 Proxy 的获取方法其实也可以放在 InvocationHandler 的实现类中。这样总结为3个函数:

  1. 构造函数,传入代理的对象。
  2. invoke 方法,此方法用于实现 AOP 增强的所有逻辑。
  3. getProxy 方法,即 Proxy.newProxyInstance()方法,必不可少。

接下来我们学习一下 JdkDynamicAopProxy 的源码。

    public JdkDynamicAopProxy(AdvisedSupport config) throws AopConfigException {
        Assert.notNull(config, "AdvisedSupport must not be null");
        if (config.getAdvisors().length == 0 && config.getTargetSource() == AdvisedSupport.EMPTY_TARGET_SOURCE) {
            throw new AopConfigException("No advisors and no TargetSource specified");
        } else {
            this.advised = config;
        }
    }

    public Object getProxy() {
        return this.getProxy(ClassUtils.getDefaultClassLoader());
    }

    public Object getProxy(@Nullable ClassLoader classLoader) {
        if (logger.isTraceEnabled()) {
            logger.trace("Creating JDK dynamic proxy: " + this.advised.getTargetSource());
        }

        Class<?>[] proxiedInterfaces = AopProxyUtils.completeProxiedInterfaces(this.advised, true);
        this.findDefinedEqualsAndHashCodeMethods(proxiedInterfaces);
        return Proxy.newProxyInstance(classLoader, proxiedInterfaces, this);
    }

    private void findDefinedEqualsAndHashCodeMethods(Class<?>[] proxiedInterfaces) {
        Class[] var2 = proxiedInterfaces;
        int var3 = proxiedInterfaces.length;

        for(int var4 = 0; var4 < var3; ++var4) {
            Class<?> proxiedInterface = var2[var4];
            Method[] methods = proxiedInterface.getDeclaredMethods();
            Method[] var7 = methods;
            int var8 = methods.length;

            for(int var9 = 0; var9 < var8; ++var9) {
                Method method = var7[var9];
                if (AopUtils.isEqualsMethod(method)) {
                    this.equalsDefined = true;
                }

                if (AopUtils.isHashCodeMethod(method)) {
                    this.hashCodeDefined = true;
                }

                if (this.equalsDefined && this.hashCodeDefined) {
                    return;
                }
            }
        }

    }

    @Nullable
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
        Object oldProxy = null;
        boolean setProxyContext = false;
        TargetSource targetSource = this.advised.targetSource;
        Object target = null;

        Integer var8;
        try {
            //equals方法判断
            if (!this.equalsDefined && AopUtils.isEqualsMethod(method)) {
                Boolean var18 = this.equals(args[0]);
                return var18;
            }

            //hash方法判断
            if (this.hashCodeDefined || !AopUtils.isHashCodeMethod(method)) {
                if (method.getDeclaringClass() == DecoratingProxy.class) {
                    Class var17 = AopProxyUtils.ultimateTargetClass(this.advised);
                    return var17;
                }

                Object retVal;
                if (!this.advised.opaque && method.getDeclaringClass().isInterface() && method.getDeclaringClass().isAssignableFrom(Advised.class)) {
                    retVal = AopUtils.invokeJoinpointUsingReflection(this.advised, method, args);
                    return retVal;
                }

                // 如果 expose-proxy 属性为 true,则暴露代理对象
                if (this.advised.exposeProxy) {
                    oldProxy = AopContext.setCurrentProxy(proxy);
                    setProxyContext = true;
                }

                target = targetSource.getTarget();
                Class<?> targetClass = target != null ? target.getClass() : null;
                 // 获取适合当前方法的拦截器
                List<Object> chain = this.advised.getInterceptorsAndDynamicInterceptionAdvice(method, targetClass);
                if (chain.isEmpty()) {// 如果拦截器链为空,则直接执行目标方法
                    Object[] argsToUse = AopProxyUtils.adaptArgumentsIfNecessary(method, args);
                    // 通过反射执行目标方法
                    retVal = AopUtils.invokeJoinpointUsingReflection(target, method, argsToUse);
                } else {
                    // 创建一个方法调用器,并将拦截器链传入其中
                    MethodInvocation invocation = new ReflectiveMethodInvocation(proxy, target, method, args, targetClass, chain);
                     // 执行拦截器链
                    retVal = invocation.proceed();
                }

                // 获取方法返回值类型
                Class<?> returnType = method.getReturnType();
                if (retVal != null && retVal == target && returnType != Object.class && returnType.isInstance(proxy) && !RawTargetAccess.class.isAssignableFrom(method.getDeclaringClass())) {
                    // 如果方法返回值为 this,即 return this; 则将代理对象 proxy 赋值给 retVal 
                    retVal = proxy;
                } else if (retVal == null && returnType != Void.TYPE && returnType.isPrimitive()) { // 如果返回值类型为基础类型,比如 int,long 等,当返回值为 null,抛出异常
                    throw new AopInvocationException("Null return value from advice does not match primitive return type for: " + method);
                }

                Object var12 = retVal;
                return var12;
            }

            var8 = this.hashCode();
        } finally {
            if (target != null && !targetSource.isStatic()) {
                targetSource.releaseTarget(target);
            }

            if (setProxyContext) {
                AopContext.setCurrentProxy(oldProxy);
            }

        }

        return var8;
    }

我们总结一下 invoke 方法的执行流程,如下:

  1. 检测 expose-proxy 是否为true,若为true,则暴露代理对象。
  2. 获取适合当前方法的拦截器。
  3. 如果拦截器链为空,则直接通过反射执行目标方法。
  4. 如果拦截器链不为空,则创建 ReflectiveMethodInvocation 对象。
  5. 调用 ReflectiveMethodInvocation 对象的 proceed()方法启动拦截器链。
  6. 处理返回值,并返回该值。

以上六个步骤,我们重点关注第2步和第5步的处理逻辑,下面先来分析获取拦截器链的过程。

获取目标方法的拦截器

getInterceptorsAndDynamicInterceptionAdvice()方法用来获取目标方法的拦截器,这是我们在 Spring AOP 中第一次提到拦截器,大家可能在别的地方使用过,拦截器用于对目标方法的调用进行拦截的一种工具。拦截器与我们之前获取的增强器有什么关系呢?带着这样的疑问,我们来分析 AdvisedSupport 类中的 getInterceptorsAndDynamicInterceptionAdvice 源码。

    public List<Object> getInterceptorsAndDynamicInterceptionAdvice(Method method, @Nullable Class<?> targetClass) {
        AdvisedSupport.MethodCacheKey cacheKey = new AdvisedSupport.MethodCacheKey(method);
        // 从缓存中获取
        List<Object> cached = (List)this.methodCache.get(cacheKey);
        // 缓存为空,则进行下一步处理
        if (cached == null) {
            // 获取所有的拦截器
            cached = this.advisorChainFactory.getInterceptorsAndDynamicInterceptionAdvice(this, method, targetClass);
            // 存入缓存
            this.methodCache.put(cacheKey, cached);
        }

        return cached;
    }

其中比较核心的方法是 getInterceptorsAndDynamicInterceptionAdvice(),在 DefaultAdvisorChainFactory 类中实现。

    public List<Object> getInterceptorsAndDynamicInterceptionAdvice(Advised config, Method method, @Nullable Class<?> targetClass) {
        // registry 为 DefaultAdvisorAdapterRegistry 类型
        AdvisorAdapterRegistry registry = GlobalAdvisorAdapterRegistry.getInstance();
        //获取目标方法对应的增强器
        Advisor[] advisors = config.getAdvisors();
        //声明拦截器列表
        List<Object> interceptorList = new ArrayList(advisors.length);
        //目标类
        Class<?> actualClass = targetClass != null ? targetClass : method.getDeclaringClass();
        Boolean hasIntroductions = null;
        Advisor[] var9 = advisors;
        int var10 = advisors.length;

        // 遍历增强器列表
        for(int var11 = 0; var11 < var10; ++var11) {
            Advisor advisor = var9[var11];
            if (advisor instanceof PointcutAdvisor) {
                PointcutAdvisor pointcutAdvisor = (PointcutAdvisor)advisor;
                //调用 ClassFilter 对 bean 类型进行匹配,无法匹配则说明当前增强器不适用于当前bean
                if (config.isPreFiltered() || pointcutAdvisor.getPointcut().getClassFilter().matches(actualClass)) {
                    MethodMatcher mm = pointcutAdvisor.getPointcut().getMethodMatcher();
                    boolean match;
                    // 通过方法匹配器对目标方法进行匹配
                    if (mm instanceof IntroductionAwareMethodMatcher) {
                        if (hasIntroductions == null) {
                            hasIntroductions = hasMatchingIntroductions(advisors, actualClass);
                        }

                        match = ((IntroductionAwareMethodMatcher)mm).matches(method, actualClass, hasIntroductions);
                    } else {
                        match = mm.matches(method, actualClass);
                    }

                    if (match) {
                        // 将 advisor 中的 advice 转成相应的拦截器
                        MethodInterceptor[] interceptors = registry.getInterceptors(advisor);
                        // 若 isRuntime 返回 true,则表明 MethodMatcher 要在运行时做一些检测
                        if (mm.isRuntime()) {
                            MethodInterceptor[] var17 = interceptors;
                            int var18 = interceptors.length;

                            for(int var19 = 0; var19 < var18; ++var19) {
                                MethodInterceptor interceptor = var17[var19];
                                interceptorList.add(new InterceptorAndDynamicMethodMatcher(interceptor, mm));
                            }
                        } else {
                            interceptorList.addAll(Arrays.asList(interceptors));
                        }
                    }
                }
            } else if (advisor instanceof IntroductionAdvisor) {
                IntroductionAdvisor ia = (IntroductionAdvisor)advisor;
                // IntroductionAdvisor 类型的增强器,仅需进行类级别的匹配即可
                if (config.isPreFiltered() || ia.getClassFilter().matches(actualClass)) {
                    Interceptor[] interceptors = registry.getInterceptors(advisor);
                    interceptorList.addAll(Arrays.asList(interceptors));
                }
            } else {
                Interceptor[] interceptors = registry.getInterceptors(advisor);
                interceptorList.addAll(Arrays.asList(interceptors));
            }
        }

        return interceptorList;
    }

    public MethodInterceptor[] getInterceptors(Advisor advisor) throws UnknownAdviceTypeException {
        List<MethodInterceptor> interceptors = new ArrayList(3);
        Advice advice = advisor.getAdvice();
        //若 advice 是 MethodInterceptor 类型的,直接添加到 interceptors 中即可
        //比如 AspectJAfterAdvice 就实现了 MethodInterceptor 接口
        if (advice instanceof MethodInterceptor) {
            interceptors.add((MethodInterceptor)advice);
        }

        Iterator var4 = this.adapters.iterator();

        //对于 AspectJMethodBeforeAdvice 等类型的通知,由于没有实现 MethodInterceptor接口,所以这里需要通过适配器进行转换
        //比如AspectJMethodBeforeAdvice类型会被转换为MethodBeforeAdviceInterceptor
        while(var4.hasNext()) {
            AdvisorAdapter adapter = (AdvisorAdapter)var4.next();
            if (adapter.supportsAdvice(advice)) {
                interceptors.add(adapter.getInterceptor(advisor));
            }
        }

        if (interceptors.isEmpty()) {
            throw new UnknownAdviceTypeException(advisor.getAdvice());
        } else {
            return (MethodInterceptor[])interceptors.toArray(new MethodInterceptor[0]);
        }
    }

以上便是获取拦截器的过程,不过好在逻辑不是很复杂,这里简单总结一下。

  1. 从缓存中获取目标方法的拦截器链。
  2. 若缓存为中,则调用 getInterceptorsAndDynamicInterceptionAdvice 获取拦截器链。
  3. 遍历增强器列表,如果是 PointcutAdvisor 类型的增强器,需要调用增强器所持有的切点对类和方法进行匹配,匹配成功说明应向当前方法织入通知逻辑卷。
  4. 调用 getInterceptors 方法对非 MethodInterceptor 类型的通知转换为拦截器。
  5. 返回拦截器链,并存入缓存中。

由于 Spring 中涉及过多的拦截器,增强器,增强方法等方式来对逻辑进行增强,AspectJAroundAdvice、AspectJAfterAdvice、AspectJAfterThrowingAdvice 这几个增强器都实现了 MethodInterceptor 接口,AspectJMethodBeforeAdvice 和AspectJAfterReturningAdvice 并没有实现 MethodInterceptor 接口,因此AspectJMethodBeforeAdvice 和AspectJAfterReturningAdvice不能满足MethodInterceptor 接口中的invoke方法,所以这里使用适配器模式将AspectJMethodBeforeAdvice 和 AspectJAfterReturningAdvice 转化成能满足需求的MethodInterceptor 实现类。

遍历 adapters,通过 adapter.supportsAdvice(advice)找到 advice 对应的适配器,adapter.getInterceptor(advisor) 将 advisor 转化成对应的 interceptor。

比如 AspectJMethodBeforeAdvice ,我们查看一下其对应的拦截器。

public class MethodBeforeAdviceInterceptor implements MethodInterceptorBeforeAdviceSerializable {
    private final MethodBeforeAdvice advice;

    public MethodBeforeAdviceInterceptor(MethodBeforeAdvice advice) {
        Assert.notNull(advice, "Advice must not be null");
        this.advice = advice;
    }

    public Object invoke(MethodInvocation mi) throws Throwable {
        //执行前置通知逻辑
        this.advice.before(mi.getMethod(), mi.getArguments(), mi.getThis());
        //调用proceed执行下一个拦截器
        return mi.proceed();
    }
}

代码比较简单,这里就不多说了。

现在我们已经获得了拦截器链,那么接下来要做的就是启动拦截器,我们继续向下分析代码,看看 Spring 是如何启动拦截器链的。

启动拦截器链

回到 JdkDynamicAopProxy 中,继续向下学习。我们先来说说 ReflectiveMethodInvocation,该类贯穿于拦截器链执行的始终,是非常核心的内容。该类的 proceed 方法用于启动拦截器链,下面我们看下该方法。

    public Object proceed() throws Throwable {
        //判断是不是所有的interceptor(也可以想像成advisor)都被执行完了。
         // 拦截器链中的最后一个拦截器执行完后,即可执行目标方法
        if (this.currentInterceptorIndex == this.interceptorsAndDynamicMethodMatchers.size() - 1) {
            return this.invokeJoinpoint();
        } else {
            // 如果Interceptor没有被全部执行完,就取出要执行的Interceptor,并执行。
            // currentInterceptorIndex先自增
            Object interceptorOrInterceptionAdvice = this.interceptorsAndDynamicMethodMatchers.get(++this.currentInterceptorIndex);
            // 如果Interceptor是PointCut类型
            if (interceptorOrInterceptionAdvice instanceof InterceptorAndDynamicMethodMatcher) {
                InterceptorAndDynamicMethodMatcher dm = (InterceptorAndDynamicMethodMatcher)interceptorOrInterceptionAdvice;
                Class<?> targetClass = this.targetClass != null ? this.targetClass : this.method.getDeclaringClass();
                // 如果当前方法符合Interceptor的PointCut限制,就执行Interceptor,如果不符合,则跳过并执行下一个Interceptor
                return dm.methodMatcher.matches(this.method, targetClass, this.arguments) ? dm.interceptor.invoke(this) : this.proceed();
            } else {
                // 如果Interceptor不是PointCut类型,就直接执行Interceptor里面的增强。
                return ((MethodInterceptor)interceptorOrInterceptionAdvice).invoke(this);
            }
        }
    }

从上述代码可知,ReflectiveMethodInvocation 中的 currentInterceptorIndex 充当拦截器链调用的计数器,记录着当前调用链接的位置 proceed 根据 currentInterceptorIndex 来确定当前应执行哪个拦截器,并在调用拦截器的 invoke 方法时,将自己作为参数传给该方法。 前置通知会在目标方法执行前执行,我们在前面也看了前置拦截器的源码,这里看一下后置拦截器的源码,如下:

public class AspectJAfterAdvice extends AbstractAspectJAdvice implements MethodInterceptorAfterAdviceSerializable {
    public AspectJAfterAdvice(Method aspectJBeforeAdviceMethod, AspectJExpressionPointcut pointcut, AspectInstanceFactory aif) {
        super(aspectJBeforeAdviceMethod, pointcut, aif);
    }

    public Object invoke(MethodInvocation mi) throws Throwable {
        Object var2;
        try {
            var2 = mi.proceed();
        } finally {
            //调用后置通知逻辑
            this.invokeAdviceMethod(this.getJoinPointMatch(), (Object)null, (Throwable)null);
        }

        return var2;
    }

    public boolean isBeforeAdvice() {
        return false;
    }

    public boolean isAfterAdvice() {
        return true;
    }
}

因为后置通知是在目标方法返回后执行,所以 AspectJAfterAdvice 先调用 mi.proceed()执行下一个拦截器逻辑,等下一个拦截器返回后,最后执行后置通知逻辑。如果大家不理解,我根据调试过程画了一张图,结合初识Spring AOP一文中的案例,其中包含前置通知、后置通知和环绕通知,执行流程如下:

关于执行过程中第一个拦截器 ExposeInvocationInterceptor,需要讲解一下。在Spring AOP创建代理之获取增强器文章末尾中,在介绍 extendAdvisors 方法时,有提及到拓展增强器列表,具体意图当时没有讲述,待会进行补充说明。这里再贴一下 extendAdvisors 方法的源码,如下:

    protected void extendAdvisors(List<Advisor> candidateAdvisors) {
        AspectJProxyUtils.makeAdvisorChainAspectJCapableIfNecessary(candidateAdvisors);
    }

    public static boolean makeAdvisorChainAspectJCapableIfNecessary(List<Advisor> advisors) {
        if (!advisors.isEmpty()) {
            boolean foundAspectJAdvice = false;
            Iterator var2 = advisors.iterator();

            while(var2.hasNext()) {
                Advisor advisor = (Advisor)var2.next();
                //检测 advisors 列表中是否存在 AspectJ 类型的 Advisor 或 Advice
                if (isAspectJAdvice(advisor)) {
                    foundAspectJAdvice = true;
                    break;
                }
            }

            if (foundAspectJAdvice && !advisors.contains(ExposeInvocationInterceptor.ADVISOR)) {
                //向 advisors 列表的首部添加 ExposeInvocationInterceptor.ADVISOR
                advisors.add(0, ExposeInvocationInterceptor.ADVISOR);
                return true;
            }
        }

        return false;
    }

如上,extendAdvisors 所调用的方法会向通知器列表首部添加 ExposeInvocationInterceptor.ADVISOR。现在我们再来看看 ExposeInvocationInterceptor 的源码,如下:

public final class ExposeInvocationInterceptor implements MethodInterceptorPriorityOrderedSerializable {
    public static final ExposeInvocationInterceptor INSTANCE = new ExposeInvocationInterceptor();
    public static final Advisor ADVISOR;
    private static final ThreadLocal<MethodInvocation> invocation;

    public static MethodInvocation currentInvocation() throws IllegalStateException {
        MethodInvocation mi = (MethodInvocation)invocation.get();
        if (mi == null) {
            throw new IllegalStateException("No MethodInvocation found: Check that an AOP invocation is in progress, and that the ExposeInvocationInterceptor is upfront in the interceptor chain. Specifically, note that advices with order HIGHEST_PRECEDENCE will execute before ExposeInvocationInterceptor!");
        } else {
            return mi;
        }
    }

    private ExposeInvocationInterceptor() {
    }

    public Object invoke(MethodInvocation mi) throws Throwable {
        MethodInvocation oldInvocation = (MethodInvocation)invocation.get();
        // 将 mi 设置到 ThreadLocal 中
        invocation.set(mi);

        Object var3;
        try {
            var3 = mi.proceed();
        } finally {
            invocation.set(oldInvocation);
        }

        return var3;
    }

    public int getOrder() {
        return -2147483647;
    }

    private Object readResolve() {
        return INSTANCE;
    }

    static {
        // 创建 DefaultPointcutAdvisor 匿名对象
        ADVISOR = new DefaultPointcutAdvisor(INSTANCE) {
            public String toString() {
                return ExposeInvocationInterceptor.class.getName() + ".ADVISOR";
            }
        };
        invocation = new NamedThreadLocal("Current AOP method invocation");
    }
}

如上,ExposeInvocationInterceptor.ADVISOR 经过 registry.getInterceptors() 方法(前面已分析过)处理后,即可得到 ExposeInvocationInterceptor。ExposeInvocationInterceptor 的作用是用于暴露 MethodInvocation 对象到 ThreadLocal 中,其名字也体现出了这一点。

关于拦截器链的执行流程,其实可以看成是一个递归的调用过程,通过 ReflectiveMethodInvocation 类中 Proceed 方法递归调用,顺序执行拦截器链中 AspectJAfterAdvice、 AspectJAroundAdvice 、 MethodBeforeAdviceInterceptor这几个拦截器,在拦截器中反射调用通知方法。说的再多,不如实际调试理解的透彻,建议不懂的朋友将这几个拦截器中的 invoke 方法都打上断点,自己亲自执行一遍。

最后说一下目标方法的执行,看一看发生在何处。

执行目标方法

在 proceed 方法中当 currentInterceptorIndex 计数满足条件时,将会执行 invokeJoinpoint 方法,即执行目标方法。我们来看一下源码。

    protected Object invokeJoinpoint() throws Throwable {
        return AopUtils.invokeJoinpointUsingReflection(this.target, this.method, this.arguments);
    }

    public static Object invokeJoinpointUsingReflection(@Nullable Object target, Method method, Object[] args) throws Throwable {
        try {
            ReflectionUtils.makeAccessible(method);
            return method.invoke(target, args);
        } catch (InvocationTargetException var4) {
            throw var4.getTargetException();
        } catch (IllegalArgumentException var5) {
            throw new AopInvocationException("AOP configuration seems to be invalid: tried calling method [" + method + "] on target [" + target + "]", var5);
        } catch (IllegalAccessException var6) {
            throw new AopInvocationException("Could not access method [" + method + "]", var6);
        }
    }

目标方法就是通过反射执行的,比较简单,在调试的过程中也可以发现。

总结

至此,关于 Spring AOP 源码的学习终于要结束了,关于 Spring 源码的学习大概花了40天的时间,进度比较慢,为此也没怎么学习别的事情。不过结局是好的,通过这次学习还是有很大的收获和成就感。由于技术尚浅,某些部分讲的不够透彻,或者有问题的,请大家见谅,如果可以的话希望能够指正一下,这里先说声谢谢啦。

参考文献

《Spring 源码深度解析》- 郝佳

适配器模式原理及实例介绍