• AOP源码分析-CglibAopProxy DynamicAdvisedInterceptor


    最近新公司在用Spring MVC,跟踪Spring的Service发现是通过动态代理来实现的,而公司的事务是配置在Service层。所以想看下Spring 的AOP的具体实现。本文源码基于Spring 4.0。
    

    我们可以使用debug跟踪一次Service调用的整体流程,可以清晰的看到一次流程处理:
    CglibAopProxy.intercept方法,该方法中通过

     this.advised.getInterceptorsAndDynamicInterceptionAdvice(method, targetClass);

    获取一个List拦截链,然后通过

    retVal = new CglibMethodInvocation(proxy, target, method, args, targetClass, chain, methodProxy).proceed();

    方法执行对应的拦截链进行执行处理。
    最后通过,

     processReturnType(proxy, target, method, retVal);

    处理返回值,并返回。
    整体过程完全采用动态代理模式来实现。最主要的代码如下:

    @Override
            public Object intercept(Object proxy, Method method, Object[] args, MethodProxy methodProxy) throws Throwable {
                Object oldProxy = null;
                boolean setProxyContext = false;
                Class<?> targetClass = null;
                Object target = null;
                try {
                    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 = getTarget();
                    if (target != null) {
                        targetClass = target.getClass();
                    }
                    List<Object> chain = this.advised.getInterceptorsAndDynamicInterceptionAdvice(method, targetClass);
                    Object retVal;
                    // Check whether we only have one InvokerInterceptor: that is,
                    // no real advice, but just reflective invocation of the target.
                    if (chain.isEmpty() && Modifier.isPublic(method.getModifiers())) {
                        // 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 = methodProxy.invoke(target, args);
                    }
                    else {
                        // We need to create a method invocation...
                        retVal = new CglibMethodInvocation(proxy, target, method, args, targetClass, chain, methodProxy).proceed();
                    }
                    retVal = processReturnType(proxy, target, method, retVal);
                    return retVal;
                }
                finally {
                    if (target != null) {
                        releaseTarget(target);
                    }
                    if (setProxyContext) {
                        // Restore old proxy.
                        AopContext.setCurrentProxy(oldProxy);
                    }
                }
            }

    代码看起来很简单。
    下面我们可以逐行对代码进行分析。
    方法签名:

    public Object intercept(Object proxy, Method method, Object[] args, MethodProxy methodProxy) throws Throwable

    可以看出,改方法传入代理对象,方法对象,参数以及方法代理。MethodProxy 包含我们的需要被代理的方法信息,包含方法完整签名。

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

    此处代码是判断代理是否可用,大概是这个意思,此处的代码不是很明白。

    target = getTarget();
                    if (target != null) {
                        targetClass = target.getClass();
                    }

    此处是获取目标类对象。
    下来是获取对应的链对象。

    List<Object> chain = this.advised.getInterceptorsAndDynamicInterceptionAdvice(method, targetClass);
        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;
        }

    在这个方法中,比较重要的应该是cacheKey的获取。

    /**
         * Simple wrapper class around a Method. Used as the key when
         * caching methods, for efficient equals and hashCode comparisons.
         */
        private static class MethodCacheKey {
            private final Method method;
            private final int hashCode;
            public MethodCacheKey(Method method) {
                this.method = method;
                this.hashCode = method.hashCode();
            }
            @Override
            public boolean equals(Object other) {
                if (other == this) {
                    return true;
                }
                MethodCacheKey otherKey = (MethodCacheKey) other;
                return (this.method == otherKey.method);
            }
            @Override
            public int hashCode() {
                return this.hashCode;
            }
        }
    }

    这个类比较简单,定义了对应的Method对象,以及Method对应的hashCode。

    List<Object> cached = this.methodCache.get(cacheKey);
        /** Cache with Method as key and advisor chain List as value */
        private transient Map<MethodCacheKey, List<Object>> methodCache;

    此处缓存了对应的拦截器链。如果为null,则通过factory实例化,并放入缓存。

    if (cached == null) {
                cached = this.advisorChainFactory.getInterceptorsAndDynamicInterceptionAdvice(
                        this, method, targetClass);
                this.methodCache.put(cacheKey, cached);
            }
    @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);
            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)) {
                        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;
        }

    这个方法虽然很长,但是实际内容还是相对比较简单。
    首先获取所有切点。

    config.getAdvisors()

    判断不同的切点类型,放入List。
    执行对应List方法。

    retVal = new CglibMethodInvocation(proxy, target, method, args, targetClass, chain, methodProxy).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);
            }
        }

    处理返回值:

    retVal = processReturnType(proxy, target, method, retVal);
                    return retVal;
    欢迎转载,但转载请注明原文链接[博客园: http://www.cnblogs.com/jingLongJun/]
    [CSDN博客:http://blog.csdn.net/mergades]。
    如相关博文涉及到版权问题,请联系本人。
  • 相关阅读:
    SQL优化之博客案例
    Drools之规则属性
    Android 8.0以上系统应用如何保活
    Android 8.0(api27)静态广播和动态广播接收问题
    Android开发 WorkManager详解
    使用EOS Camera Movie Record 软件在计算机上使用 Canon EOS DSLR相机录制视频 。
    关于使用AlarmManager的注意事项
    系统服务之定时服务(AlarmManager)
    Android定时器AlarmManager
    Android 代码混淆
  • 原文地址:https://www.cnblogs.com/jingLongJun/p/4491037.html
Copyright © 2020-2023  润新知