Spring源码学习【六】AOP原理解析(二)拦截器链

目录

一、前言

二、源码学习


一、前言

通过上一篇 Spring源码学习【六】AOP原理解析(一)代理对象的生成 的学习,我们知道了Spring是通过后置处理器来生成代理对象的,且获取到代理对象后会阻止原Bean的默认实例化行为,从而将代理对象提供给用户使用,并通过代理对象实现对目标对象的增强,有了这些知识储备,我们继续以JdkDynamicAopProxy为例,学习一下代理对象是如何对目标对象进行增强的。

二、源码学习

回到上一篇JdkDynamicAopProxy类中,我们可以发现JdkDynamicAopProxy类实现了InvocationHandler接口,在利用Java反射机制创建代理对象的同时将传入了this对象引用,代码如下:

final class JdkDynamicAopProxy implements AopProxy, InvocationHandler, Serializable {
 
    @Override
    public Object getProxy(@Nullable ClassLoader classLoader) {
        ...
        return Proxy.newProxyInstance(classLoader, proxiedInterfaces, this);
    }
 
}

这里的InvocationHandler接口是代理对象需要实现的接口,其中定义了Invoke方法,用于以回调的方式拦截目标对象方法的调用,我们可以以JdkDynamicAopProxy为例学习invoke的实现,代码如下:

final class JdkDynamicAopProxy implements AopProxy, InvocationHandler, Serializable {
 
    @Override
    @Nullable
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
        MethodInvocation invocation;
        Object oldProxy = null;
        boolean setProxyContext = false;

        TargetSource targetSource = this.advised.targetSource;
        Object target = null;

        try {
            if (!this.equalsDefined && AopUtils.isEqualsMethod(method)) {
                // 目标对象未实现equals方法
                return equals(args[0]);
            }
            else if (!this.hashCodeDefined && AopUtils.isHashCodeMethod(method)) {
                // 目标对象未实现hashCode方法
                return hashCode();
            }
            else if (method.getDeclaringClass() == DecoratingProxy.class) {
                // 装饰模式代理
                return AopProxyUtils.ultimateTargetClass(this.advised);
            }
            else if (!this.advised.opaque && method.getDeclaringClass().isInterface() && method.getDeclaringClass().isAssignableFrom(Advised.class)) {
                return AopUtils.invokeJoinpointUsingReflection(this.advised, method, args);
            }
            Object retVal;
            if (this.advised.exposeProxy) {
                oldProxy = AopContext.setCurrentProxy(proxy);
                setProxyContext = true;
            }
            // 获取目标对象
            target = targetSource.getTarget();
            Class targetClass = (target != null ? target.getClass() : null);
            // 获取要执行的方法的拦截器链
            List chain = this.advised.getInterceptorsAndDynamicInterceptionAdvice(method, targetClass);
            if (chain.isEmpty()) {
                Object[] argsToUse = AopProxyUtils.adaptArgumentsIfNecessary(method, args);
                // 拦截器链空,则直接执行目标对象方法
                retVal = AopUtils.invokeJoinpointUsingReflection(target, method, argsToUse);
            }
            else {
                // 调用拦截器
                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())) {
                retVal = proxy;
            }
            else if (retVal == null && returnType != Void.TYPE && returnType.isPrimitive()) {
                throw new AopInvocationException("Null return value from advice does not match primitive return type for: " + method);
            }
            return retVal;
        }
        finally {
            if (target != null && !targetSource.isStatic()) {
                targetSource.releaseTarget(target);
            }
            if (setProxyContext) {
                AopContext.setCurrentProxy(oldProxy);
            }
        }
    }
 
} 
  

上面的代码中我们需要关注两个方面:其一,目标对象targer的方法调用;其二,拦截器的调用。

首先,看一看目标对象方法的调用,使用了Java的反射机制,具体实现在AopUtils类中,代码如下:

public abstract class AopUtils {

    @Nullable
    public static Object invokeJoinpointUsingReflection(@Nullable Object target, Method method, Object[] args) throws Throwable {
        // 通过反射调用方法
        try {
            ReflectionUtils.makeAccessible(method);
            return method.invoke(target, args);
        }
        catch (InvocationTargetException ex) {
            throw ex.getTargetException();
        }
        catch (IllegalArgumentException ex) {
            throw new AopInvocationException("AOP configuration seems to be invalid: tried calling method [" + method + "] on target [" + target + "]", ex);
        }
        catch (IllegalAccessException ex) {
            throw new AopInvocationException("Could not access method [" + method + "]", ex);
        }
    }

}

然后,看一看拦截器的调用,具体实现在ReflectiveMethodInvocation类中,代码如下:

public class ReflectiveMethodInvocation implements ProxyMethodInvocation, Cloneable {

    @Override
    @Nullable
    public Object proceed() throws Throwable {
        // index由-1开始调用拦截器,当所有拦截器调用完毕后再调用目标对象的方法
        if (this.currentInterceptorIndex == this.interceptorsAndDynamicMethodMatchers.size() - 1) {
            return invokeJoinpoint();
        }
        // 从interceptorsAndDynamicMethodMatchers中获取一个对象
        // 这个对象可能是一个匹配器或是一个拦截器
        Object interceptorOrInterceptionAdvice = this.interceptorsAndDynamicMethodMatchers.get(++this.currentInterceptorIndex);
        if (interceptorOrInterceptionAdvice instanceof InterceptorAndDynamicMethodMatcher) {
            // 取得匹配器则需要对目标方法进行匹配
            InterceptorAndDynamicMethodMatcher dm = (InterceptorAndDynamicMethodMatcher) interceptorOrInterceptionAdvice;
            if (dm.methodMatcher.matches(this.method, this.targetClass, this.arguments)) {
                // 匹配成功,调用拦截器
                return dm.interceptor.invoke(this);
            }
            else {
                // 匹配失败,跳过该拦截器,进行递归
                return proceed();
            }
        }
        else {
            // 直接取得了一个拦截器,那么无需匹配直接调用
            return ((MethodInterceptor) interceptorOrInterceptionAdvice).invoke(this);
        }
    }

    @Nullable
    protected Object invokeJoinpoint() throws Throwable {
        // 调用目标对象的方法
        return AopUtils.invokeJoinpointUsingReflection(this.target, this.method, this.arguments);
    }

}

到这里,我们就大体了解了拦截器链和目标方法的调用过程,在我们调用代理对象的目标方法时,会回调到代理对象的invode方法中,在这个方法中调用拦截器链,最终调用目标方法。在这个过程中,我们发现最终调用的拦截器链是由ReflectiveMethodInvocation持有的,拦截器链在构造方法中进行了初始化,如下所示:

protected final List interceptorsAndDynamicMethodMatchers;

/**
 * @param proxy 代理对象
 * @param target 目标对象
 * @param method 目标方法
 * @param arguments 目标方法参数
 * @param targetClass 目标类
 * @param interceptorsAndDynamicMethodMatchers 拦截器链
 */
protected ReflectiveMethodInvocation(Object proxy, @Nullable Object target, 
        Method method, @Nullable Object[] arguments, @Nullable Class targetClass, 
        List interceptorsAndDynamicMethodMatchers) {
    this.proxy = proxy;
    this.target = target;
    this.targetClass = targetClass;
    this.method = BridgeMethodResolver.findBridgedMethod(method);
    this.arguments = AopProxyUtils.adaptArgumentsIfNecessary(method, arguments);
    this.interceptorsAndDynamicMethodMatchers = interceptorsAndDynamicMethodMatchers;
} 
  

经过上一篇的分析,我们知道ReflectiveMethodInvocation是在JdkDynamicAopProxy的invoke方法中构造的,在构造ReflectiveMethodInvocation对象前,先获取了目标方法的拦截器链,代码如下:

List chain = this.advised.getInterceptorsAndDynamicInterceptionAdvice(method, targetClass);
invocation = new ReflectiveMethodInvocation(proxy, target, method, args, targetClass, chain); 
  

上面的这句代码十分重要,现在我们知道Spring是通过生成代理类来实现对目标对象的增强的,在执行目标对象的目标方法前,会首先执行代理对象中配置的一系列拦截器,这里便是获取了所有拦截器,接下来看一看具体的代码:

public class AdvisedSupport extends ProxyConfig implements Advised {

    /**
     * 获取拦截器链,可以看到这里使用了缓存,最终拦截器链的获取由AdvisorChainFactory接口的实现类
     * DefaultAdvisorChainFactory实现
     */
    public List getInterceptorsAndDynamicInterceptionAdvice(Method method, @Nullable Class targetClass) {
        MethodCacheKey cacheKey = new MethodCacheKey(method);
        List cached = this.methodCache.get(cacheKey);
        if (cached == null) {
            cached = this.advisorChainFactory.getInterceptorsAndDynamicInterceptionAdvice(this, method, targetClass);
            this.methodCache.put(cacheKey, cached);
        }
        return cached;
    }

} 
  

DefaultAdvisorChainFactory用于为目标方法创建拦截器链,代码如下:

public class DefaultAdvisorChainFactory implements AdvisorChainFactory, Serializable {

    /**
     * 创建拦截器链
     *
     */
    @Override
    public List getInterceptorsAndDynamicInterceptionAdvice(Advised config, Method method, @Nullable Class targetClass) {
        // 这里的config实际上之前创建的ProxyFactory,ProxyFactory间接实现了Advised接口
        List interceptorList = new ArrayList<>(config.getAdvisors().length);
        Class actualClass = (targetClass != null ? targetClass : method.getDeclaringClass());
        boolean hasIntroductions = hasMatchingIntroductions(config, actualClass);
        // 取得一个registry,这里使用了单例模式,用于注册通知适配器
        AdvisorAdapterRegistry registry = GlobalAdvisorAdapterRegistry.getInstance();
        for (Advisor advisor : config.getAdvisors()) {
            // 处理切入点通知,方法级别增强
            if (advisor instanceof PointcutAdvisor) {
                PointcutAdvisor pointcutAdvisor = (PointcutAdvisor) advisor;
                if (config.isPreFiltered() || pointcutAdvisor.getPointcut().getClassFilter().matches(actualClass)) {
                    // 通过registry取得拦截器
                    MethodInterceptor[] interceptors = registry.getInterceptors(advisor);
                    MethodMatcher mm = pointcutAdvisor.getPointcut().getMethodMatcher();
                    if (MethodMatchers.matches(mm, method, actualClass, hasIntroductions)) {
                        if (mm.isRuntime()) {
                            for (MethodInterceptor interceptor : interceptors) {
                                interceptorList.add(new InterceptorAndDynamicMethodMatcher(interceptor, mm));
                            }
                        }
                        else {
                            interceptorList.addAll(Arrays.asList(interceptors));
                        }
                    }
                }
            }
            // 处理引介通知,类级别增强
            else if (advisor instanceof IntroductionAdvisor) {
                IntroductionAdvisor ia = (IntroductionAdvisor) advisor;
                if (config.isPreFiltered() || ia.getClassFilter().matches(actualClass)) {
                    // 通过registry取得拦截器
                    Interceptor[] interceptors = registry.getInterceptors(advisor);
                    interceptorList.addAll(Arrays.asList(interceptors));
                }
            }
            else {
                // 通过registry取得拦截器
                Interceptor[] interceptors = registry.getInterceptors(advisor);
                interceptorList.addAll(Arrays.asList(interceptors));
            }
        }
        return interceptorList;
    }
} 
  

上面的代码中最终返回了一个方法拦截器的列表,在这个过程中,多次调用了AdvisorAdapterRegistry的getInterceptors(advisor)方法,下面深入到AdvisorAdapterRegistry接口的实现类DefaultAdvisorAdapterRegistry中看一看具体实现:

public class DefaultAdvisorAdapterRegistry implements AdvisorAdapterRegistry, Serializable {

    private final List adapters = new ArrayList<>(3);

    public DefaultAdvisorAdapterRegistry() {
        registerAdvisorAdapter(new MethodBeforeAdviceAdapter());
        registerAdvisorAdapter(new AfterReturningAdviceAdapter());
        registerAdvisorAdapter(new ThrowsAdviceAdapter());
    }


    @Override
    public Advisor wrap(Object adviceObject) throws UnknownAdviceTypeException {
        if (adviceObject instanceof Advisor) {
            return (Advisor) adviceObject;
        }
        if (!(adviceObject instanceof Advice)) {
            throw new UnknownAdviceTypeException(adviceObject);
        }
        Advice advice = (Advice) adviceObject;
        if (advice instanceof MethodInterceptor) {
            return new DefaultPointcutAdvisor(advice);
        }
        for (AdvisorAdapter adapter : this.adapters) {
            if (adapter.supportsAdvice(advice)) {
                return new DefaultPointcutAdvisor(advice);
            }
        }
        throw new UnknownAdviceTypeException(advice);
    }

    /**
     * 获取拦截器
     */
    @Override
    public MethodInterceptor[] getInterceptors(Advisor advisor) throws UnknownAdviceTypeException {
        List interceptors = new ArrayList<>(3);
        Advice advice = advisor.getAdvice();
        if (advice instanceof MethodInterceptor) {
            interceptors.add((MethodInterceptor) advice);
        }
        for (AdvisorAdapter adapter : this.adapters) {
            // 判断通知是否可被适配器理解
            // 实际上是对advice类型的判断,如AfterReturningAdvice等
            if (adapter.supportsAdvice(advice)) {
                interceptors.add(adapter.getInterceptor(advisor));
            }
        }
        if (interceptors.isEmpty()) {
            throw new UnknownAdviceTypeException(advisor.getAdvice());
        }
        return interceptors.toArray(new MethodInterceptor[0]);
    }

    /**
     * 注册通知适配器
     */
    @Override
    public void registerAdvisorAdapter(AdvisorAdapter adapter) {
        this.adapters.add(adapter);
    }

}

到这里,拦截器链就构造完成了,在这个过程中,通过适配器的支持,构造了不同的拦截器,在JdkDynamicAopProxy进行回调时则会根据配置的通知执行相应的拦截器链,从而达到增强目标对象的功能。

Spring的AOP模块是一个复杂的模块,这里仅仅简要分析了通过代理对象增强目标对象的原理和过程,还有更多的知识需要在实践中不断学习。

你可能感兴趣的:(Spring源码,Spring源码,AOP拦截器链)