spring AOP源码分析(三)

佐手、 提交于 2020-02-23 05:56:52

在上一篇文章 spring AOP源码分析(二)中,我们已经知道如何生成一个代理对象了,那么当代理对象调用代理方法时,增强行为也就是拦截器是如何发挥作用的呢?接下来我们将介绍JDK动态代理和cglib这两种方式下,拦截器调用的实现。

一 JDK动态代理拦截器调用的实现:

我们知道,在生成代理对象时,相关的拦截器已经配置到代理对象中了。Proxy.newProxyInstance(classLoader, proxiedInterfaces, this); 这行代码是用于生成代理对象的,this代表InvocationHandler接口,此处是指JdkDynamicAopProxy类,

因为JdkDynamicAopProxy实现了InvocationHandler接口。当生成的代理对象调用代理方法时,会触发InvocationHandler接口中invoke方法的调用,而增强行为的发生或者说对目标对象方法的拦截动作就是在这个方法中。我们进入JdkDynamicAopProxy

类的invoke方法:

/**
     * Implementation of {@code InvocationHandler.invoke}.
     * <p>Callers will see exactly the exception thrown by the target,
     * unless a hook method throws an exception.
     */
    @Override
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
        MethodInvocation invocation;
        Object oldProxy = null;
        boolean setProxyContext = false;

        TargetSource targetSource = this.advised.targetSource;
        Class<?> targetClass = null;
        Object target = null;

        try {            // 如果目标对象没有实现Object的equals方法
            if (!this.equalsDefined && AopUtils.isEqualsMethod(method)) {
                // The target does not implement the equals(Object) method itself.
                return equals(args[0]);
            }            // 如果目标对象没有实现Object的hashCode方法
            else if (!this.hashCodeDefined && AopUtils.isHashCodeMethod(method)) {
                // The target does not implement the hashCode() method itself.
                return hashCode();
            }
            else if (method.getDeclaringClass() == DecoratingProxy.class) {
                // There is only getDecoratedClass() declared -> dispatch to proxy config.
                return AopProxyUtils.ultimateTargetClass(this.advised);
            }
            else if (!this.advised.opaque && method.getDeclaringClass().isInterface() &&
                    method.getDeclaringClass().isAssignableFrom(Advised.class)) {
                // Service invocations on ProxyConfig with the proxy config...
                return AopUtils.invokeJoinpointUsingReflection(this.advised, method, args);
            }

            Object retVal;

            if (this.advised.exposeProxy) {
                // Make invocation available if necessary.
                oldProxy = AopContext.setCurrentProxy(proxy);
                setProxyContext = true;
            }

            // May be null. Get as late as possible to minimize the time we "own" the target,
            // in case it comes from a pool.            // 获取目标对象
            target = targetSource.getTarget();
            if (target != null) {
                targetClass = target.getClass();
            }

            // Get the interception chain for this method.            // 获取拦截器链
            List<Object> chain = this.advised.getInterceptorsAndDynamicInterceptionAdvice(method, targetClass);

            // Check whether we have any advice. If we don't, we can fallback on direct
            // reflective invocation of the target, and avoid creating a MethodInvocation.
            if (chain.isEmpty()) {                // 如果拦截器为空,那么直接调用目标对象的目标方法 进入该方法
                // We can skip creating a MethodInvocation: just invoke the target directly
                // Note that the final invoker must be an InvokerInterceptor so we know it does
                // nothing but a reflective operation on the target, and no hot swapping or fancy proxying.
                Object[] argsToUse = AopProxyUtils.adaptArgumentsIfNecessary(method, args);
                retVal = AopUtils.invokeJoinpointUsingReflection(target, method, argsToUse);
            }
            else {                // 否则,需要先调用拦截器然后再调用目标方法,通过构造一个ReflectiveMethodInvocation来实现
                // We need to create a method invocation...
                invocation = new ReflectiveMethodInvocation(proxy, target, method, args, targetClass, chain);
                // Proceed to the joinpoint through the interceptor chain.                // 沿着拦截器链前行 进入该方法
                retVal = invocation.proceed();
            }

            // Massage return value if necessary.
            Class<?> returnType = method.getReturnType();
            if (retVal != null && retVal == target &&
                    returnType != Object.class && returnType.isInstance(proxy) &&
                    !RawTargetAccess.class.isAssignableFrom(method.getDeclaringClass())) {
                // Special case: it returned "this" and the return type of the method
                // is type-compatible. Note that we can't help if the target sets
                // a reference to itself in another returned object.
                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()) {
                // Must have come from TargetSource.
                targetSource.releaseTarget(target);
            }
            if (setProxyContext) {
                // Restore old proxy.
                AopContext.setCurrentProxy(oldProxy);
            }
        }
    }

当没有拦截器时,我们进入invokeJoinpointUsingReflection这个方法,可以看到通过反射的方式直接调用目标对象方法

/**
     * Invoke the given target via reflection, as part of an AOP method invocation.
     * @param target the target object
     * @param method the method to invoke
     * @param args the arguments for the method
     * @return the invocation result, if any
     * @throws Throwable if thrown by the target method
     * @throws org.springframework.aop.AopInvocationException in case of a reflection error
     */
    public static Object invokeJoinpointUsingReflection(Object target, Method method, Object[] args)
            throws Throwable {

        // Use reflection to invoke the method.
        try {
            ReflectionUtils.makeAccessible(method);            // 通过反射的方式直接调用目标对象方法
            return method.invoke(target, args);
        }
        catch (InvocationTargetException ex) {
            // Invoked method threw a checked exception.
            // We must rethrow it. The client won't see the interceptor.
            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);
        }
    }

当有拦截器时,我们进入invocation.proceed()方法,这个方法就是AOP的核心部分了,AOP是如何完成对目标对象的增强的?这些实现封装在AOP拦截器链中,由一个个具体的拦截器实现的,就在这个方法中。

@Override
    public Object proceed() throws Throwable {
        //    We start with an index of -1 and increment early.        // 从索引为-1的拦截器开始调用,按顺序递增,直到没有拦截器了,然后开始调用目标对象的方法
        if (this.currentInterceptorIndex == this.interceptorsAndDynamicMethodMatchers.size() - 1) {
            return invokeJoinpoint();
        }
        // 沿着定义好的拦截器链进行获取然后逐个处理
        Object interceptorOrInterceptionAdvice =
                this.interceptorsAndDynamicMethodMatchers.get(++this.currentInterceptorIndex);
        if (interceptorOrInterceptionAdvice instanceof InterceptorAndDynamicMethodMatcher) {
            // Evaluate dynamic method matcher here: static part will already have
            // been evaluated and found to match.            // 这里是触发匹配判断的地方,如果和定义的pointcut匹配,那么这个advice将得到执行
            InterceptorAndDynamicMethodMatcher dm =
                    (InterceptorAndDynamicMethodMatcher) interceptorOrInterceptionAdvice;
            if (dm.methodMatcher.matches(this.method, this.targetClass, this.arguments)) {
                return dm.interceptor.invoke(this);
            }
            else {
                // Dynamic matching failed.
                // Skip this interceptor and invoke the next in the chain.
                return proceed();
            }
        }
        else {
            // It's an interceptor, so we just invoke it: The pointcut will have
            // been evaluated statically before this object was constructed.            // 如果是一个interceptor,那么直接调用这个interceptor的invoke方法 进入此方法来分析通知(拦截器)是如何起作用的
            return ((MethodInterceptor) interceptorOrInterceptionAdvice).invoke(this);
        }
    }

进入MethodBeforeAdviceInterceptor类的invoke方法,就是前置通知调用的方法:

@Override
    public Object invoke(MethodInvocation mi) throws Throwable {
        this.advice.before(mi.getMethod(), mi.getArguments(), mi.getThis() ); // 此处就是发生的切面增强行为
        return mi.proceed(); //递归调用proceed方法,然后进入下一个拦截器的处理
    }

进入AspectJAfterAdvice类的invoke方法,就是后置通知调用的方法:

@Override
    public Object invoke(MethodInvocation mi) throws Throwable {
        try {
            return mi.proceed(); //递归调用proceed方法
        }
        finally {
            invokeAdviceMethod(getJoinPointMatch(), null, null); //此处就是发生切面增强行为的地方
        }
    }

接下来我们考虑另外一个问题:在xml中定义的通知是如何配置到代理对象中的拦截器链中的?

我们知道,我们是通过 Object interceptorOrInterceptionAdvice = this.interceptorsAndDynamicMethodMatchers.get(++this.currentInterceptorIndex);这行代码获取拦截器的,所以所有的拦截器都在interceptorsAndDynamicMethodMatchers这个list集合中,那么

这个集合从哪个地方获取的呢?我们可以进入JdkDynamicAopProxy类的invoke方法,有这么一行代码:List<Object> chain = this.advised.getInterceptorsAndDynamicInterceptionAdvice(method, targetClass);用于获取这个代理方法的拦截器链,进入此方法:

    public List<Object> getInterceptorsAndDynamicInterceptionAdvice(Method method, Class<?> targetClass) {         // 这里使用cache获取已有的interceptor链,如果是第一次,需要手动生成,这里是使用AdvisorChainFactory来生成interceptor链的,默认是DefaultAdvisorChainFactory
        MethodCacheKey cacheKey = new MethodCacheKey(method);
        List<Object> cached = this.methodCache.get(cacheKey);
        if (cached == null) {
            cached = this.advisorChainFactory.getInterceptorsAndDynamicInterceptionAdvice(
                    this, method, targetClass);
            this.methodCache.put(cacheKey, cached);
        }
        return cached;
    }

DefaultAdvisorChainFactory 由名字可知,这是一个生成通知器链的工厂。进入getInterceptorsAndDynamicInterceptionAdvice这个方法:

@Override
    public List<Object> getInterceptorsAndDynamicInterceptionAdvice(
            Advised config, Method method, Class<?> targetClass) {
        // 所有的advistor在config中已经持有了,可以直接使用 
        // This is somewhat tricky... We have to process introductions first,
        // but we need to preserve order in the ultimate list.
        List<Object> interceptorList = new ArrayList<Object>(config.getAdvisors().length);
        Class<?> actualClass = (targetClass != null ? targetClass : method.getDeclaringClass());
        boolean hasIntroductions = hasMatchingIntroductions(config, actualClass);
        AdvisorAdapterRegistry registry = GlobalAdvisorAdapterRegistry.getInstance();

        for (Advisor advisor : config.getAdvisors()) {
            if (advisor instanceof PointcutAdvisor) {
                // Add it conditionally.
                PointcutAdvisor pointcutAdvisor = (PointcutAdvisor) advisor;
                if (config.isPreFiltered() || pointcutAdvisor.getPointcut().getClassFilter().matches(actualClass)) {                    //通过AdvisorAdapterRegistry注册器,把从config中获取的advistor进行适配,从而获得拦截器,再把它放入List中。这就是拦截器注册的过程。
                    MethodInterceptor[] interceptors = registry.getInterceptors(advisor);
                    MethodMatcher mm = pointcutAdvisor.getPointcut().getMethodMatcher();
                    if (MethodMatchers.matches(mm, method, actualClass, hasIntroductions)) {
                        if (mm.isRuntime()) {
                            // Creating a new object instance in the getInterceptors() method
                            // isn't a problem as we normally cache created chains.
                            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)) {
                    Interceptor[] interceptors = registry.getInterceptors(advisor);
                    interceptorList.addAll(Arrays.asList(interceptors));
                }
            }
            else {
                Interceptor[] interceptors = registry.getInterceptors(advisor);
                interceptorList.addAll(Arrays.asList(interceptors));
            }
        }

        return interceptorList;
    }

以上就是JDK动态代理springAOP实现增强行为的过程,对于cglib这种方式,此处就不做分析。

《springAOP源码分析一》

《springAOP源码分析二》

标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!