zoukankan      html  css  js  c++  java
  • springAOP源码分析之篇三:代理对象的执行

    JdkDynamicAopProxy 实现了InvocationHandler接口
    当使用jdk动态代理生成的代理对象在执行的时候回执行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方法的处理
                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 {
                    // 否则需要需要先调用拦截器链再调用目标方法,通过构建一个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.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);
                }
            }
        }
        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);
            }
        }

     下面分析有拦截器链的情况下:进入

    proceed方法
        // 通过递归调用proceed方法来把拦截器中的所有的增加全部执行完
        @Override
        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);
            }
        }

     下面进入方法getInterceptorsAndDynamicInterceptionAdvice看如何构建拦截器链

    /**
         * Determine a list of {@link org.aopalliance.intercept.MethodInterceptor} objects
         * for the given method, based on this configuration.
         * @param method the proxied method
         * @param targetClass the target class
         * @return List of MethodInterceptors (may also include InterceptorAndDynamicMethodMatchers)
         */
        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;
        }
    下面进入方法
    getInterceptorsAndDynamicInterceptionAdvice
    
    
        @Override
        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;
        }
  • 相关阅读:
    重新学习C#系列-02.静态类、静态字段和静态方法
    Appcan学习笔记(3)——tabview 静止页面左右滑动切换
    Appcan学习笔记(2)——子页面调用父页面的方法
    Appcan学习笔记(1)——父页面调用子页面的方法
    重新学习C#系列-01.方法参数
    WP8.1 Runtime应用利用HttpClient初始化数据的一些考虑
    C# socket通讯使用域名的方法
    RSA私钥加密
    RSA公钥加密
    13位时间戳转换成标准时间C#代码
  • 原文地址:https://www.cnblogs.com/histlyb/p/9485802.html
Copyright © 2011-2022 走看看