aop源码解析四-代理方法的调用

来源:互联网 发布:suse 软件源 编辑:程序博客网 时间:2024/06/08 08:00

JdkDynamicAopProxy实现了InvocationHandler接口 那么方法的实现我们看下invoke方法

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 {            if (!this.equalsDefined && AopUtils.isEqualsMethod(method)) {                // The target does not implement the equals(Object) method itself.                return equals(args[0]);            }            if (!this.hashCodeDefined && AopUtils.isHashCodeMethod(method)) {                // The target does not implement the hashCode() method itself.                return hashCode();            }            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.                retVal = AopUtils.invokeJoinpointUsingReflection(target, method, args);            }            else {                // 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.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);            }        }    }

实现AfterThrowing``AfterReturning``After``Arond``Before这些切面方法的调用是通过责任链来实现的 把这些切面方法组装成一个责任链 然后循环调用 AfterXXX类切面是怎么实现在方法调用后实现的 Before又是怎么实现在方法调用前调用的 是我们感兴趣的地方

构造责链

    public List<Object> getInterceptorsAndDynamicInterceptionAdvice(Method method, Class targetClass) {        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;    }        public List<Object> getInterceptorsAndDynamicInterceptionAdvice(            Advised config, Method method, Class targetClass) {        // 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);        boolean hasIntroductions = hasMatchingIntroductions(config, targetClass);        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(targetClass)) {                    MethodInterceptor[] interceptors = registry.getInterceptors(advisor);                    MethodMatcher mm = pointcutAdvisor.getPointcut().getMethodMatcher();                    if (MethodMatchers.matches(mm, method, targetClass, 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(targetClass)) {                    Interceptor[] interceptors = registry.getInterceptors(advisor);                    interceptorList.addAll(Arrays.asList(interceptors));                }            }            else {                Interceptor[] interceptors = registry.getInterceptors(advisor);                interceptorList.addAll(Arrays.asList(interceptors));            }        }        return interceptorList;    }

advised是构造的proxyFactory对象 getInterceptorsAndDynamicInterceptionAdvice方法把method作为缓存的key缓存method所对应的责任链 能够节省时间的开销
我们前面提到的那些切面都是PointcutAdvisor类型的切面 根据切点信息过滤 判断是否应该对该目标方法增强 最后返回的责任链大概是这样的返回的责任链

注意图中的切面的顺序 这是很重要一点 对于方法的执行时刻来说是至关重要的一点 这个顺序在寻找出advisor的时候就已经排好顺序了

如果责任链是空的就直接调用目标方法 如果非空的话 构造一个ReflectiveMethodInvocation对象 这个对象其实就是一个工具类(责任链对象) 是相关信息的封装 这样的实现能让方法看起来更简洁 看下ReflectiveMethodInvocationproceed方法

    public Object proceed() throws Throwable {        //  We start with an index of -1 and increment early.        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.            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.            return ((MethodInterceptor) interceptorOrInterceptionAdvice).invoke(this);        }    }

责任链的执行方式就是不断的调用责任链条中子节点的方法 同时把责任链对象自己传递进去 这样就可以在子节点方法中循环调用 使链条一个接一个的调用 一般通过下标的方式记录执行的子节点的位置 目标方法总是最后一个调用(可不是最后一个执行!!!) 这样可能就给读者一个困惑 目标方法最后一个调用 那么那些afterxxx切面是怎么实现的呢? 我们后面会介绍到
下面是切面所对应的invoke方法

//AspectJAfterThrowingAdvicepublic Object invoke(MethodInvocation mi) throws Throwable {        try {            return mi.proceed();        }        catch (Throwable t) {            if (shouldInvokeOnThrowing(t)) {                invokeAdviceMethod(getJoinPointMatch(), null, t);            }            throw t;        }    }//AfterReturningAdviceInterceptorpublic Object invoke(MethodInvocation mi) throws Throwable {        Object retVal = mi.proceed();        this.advice.afterReturning(retVal, mi.getMethod(), mi.getArguments(), mi.getThis());        return retVal;    }//AspectJAfterAdvicepublic Object invoke(MethodInvocation mi) throws Throwable {        try {            return mi.proceed();        }        finally {            invokeAdviceMethod(getJoinPointMatch(), null, null);        }    }//AspectJAroundAdvice    public Object invoke(MethodInvocation mi) throws Throwable {        if (!(mi instanceof ProxyMethodInvocation)) {            throw new IllegalStateException("MethodInvocation is not a Spring ProxyMethodInvocation: " + mi);        }        ProxyMethodInvocation pmi = (ProxyMethodInvocation) mi;        ProceedingJoinPoint pjp = lazyGetProceedingJoinPoint(pmi);        JoinPointMatch jpm = getJoinPointMatch(pmi);        return invokeAdviceMethod(pjp, jpm, null, null);    }//MethodBeforeAdviceInterceptor    public Object invoke(MethodInvocation mi) throws Throwable {        this.advice.before(mi.getMethod(), mi.getArguments(), mi.getThis() );        return mi.proceed();    }

这是我按顺序列出的切面的调用 顺序为

  1. AfterThrowing
  2. AfterReturning
  3. After
  4. Around
  5. Before

如果我们对一个方法加了这5个方法增强 那么我们来分析一下执行的流程:

  • AspectJAfterThrowingAdvice##invoke用了try{}catch(){}的结构 看到这里是不是觉得有种焕然大悟的感觉 实现就是这么简单 在try结构体中调用责任链结构体的proceed方法 执行下一个方法 如果有异常抛出的话 会被catch结构体捕获到

  • AfterReturningAdviceInterceptor##invoke方法先调用责任链结构体的proceed方法 执行下一个方法 剩下的方法入栈 直到proceed方法取到返回值的时候出栈继续执行 这样就解决了在方法返回后执行的问题 在取到目标方法返回值后调用AfterReturningAdviceafterReturning(xxx)方法

    public void afterReturning(Object returnValue, Method method, Object[] args, Object target) throws Throwable {        if (shouldInvokeOnReturnValueOf(method, returnValue)) {            invokeAdviceMethod(getJoinPointMatch(), returnValue, null);        }    }
  • AspectJAfterAdvice#invoke方法用了try{}finnally{}结构体 在try结构体中继续调用下一个责任链的子节点 在finally结构体中调用增强方法

  • AspectJAroundAdvice##invoke方法相对复杂一些 我们需要在方法的执行前后实现增强 那么责任链的执行就需要我们去推动 spring需要提供一些参数供我们使用 例如ProceedingJoinPoint ProceedingJoinPoint构造方法中传递的是责任链结构体 这样就可以继续推动责任链的执行 而不会中断 AspectJAroundAdvice##invoke方法实现中直接调用了增强方法 而不是像其他切面一样 在invoke方法中调用mi.proceed(xxx)方法 这样一来 环绕通知作用在目标方法前面的增强就早于前置通知执行 环绕增强方法中的调用的proceed()会让责任链向下一个节点执行 剩下的方法体入栈

  • MethodBeforeAdviceInterceptor#invoke方法是在目标方法前执行的 invoke方法先调用了切面增强方法然后再让责任链继续执行

如果只有这5个增强方法的话 那么MethodBeforeAdviceInterceptor#invoke方法体中mi.proceed()方法就执行到责任链的结束了 这个时候就会调用目标方法了 如果有异常的话 会被AfterThrowing通知捕获到
目标方法执行完就会执行环绕通知中的后半部分代码 环绕通知执行完就会执行After通知的finally{}结构体 执行后置通知增强 后置通知执行完就会执行 AfterReturning入的剩余的方法体
这些就是代理方法的调用过程 也算是解决了心中的一个疑点 当然还有很大一部分内容没有涉及 例如方法参数的绑定等 就不再介绍了 干兴趣的可以自己debug探索

阅读全文
0 0
原创粉丝点击