Spring AOP代理的创建过程

hresh 574 0

Spring AOP代理的创建过程

紧接着上文,在获取了所有对应 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);
            }
        }
    }

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

Spring AOP代理的创建过程

对此我有一个疑问:在创建代理之前,即执行 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 MethodInterceptor, BeforeAdvice, Serializable {
    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 MethodInterceptor, AfterAdvice, Serializable {
    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一文中的案例,其中包含前置通知、后置通知和环绕通知,执行流程如下:

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 MethodInterceptor, PriorityOrdered, Serializable {
    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 源码深度解析》- 郝佳

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

发表评论 取消回复
表情 图片 链接 代码

分享