原 荐 Spring Aop之Cglib实现原理详解

栏目: 编程工具 · 发布时间: 7年前

内容简介:Spring Aop实现对目标对象的代理,主要有两种方式:Jdk代理和Cglib代理。这两种代理的区别在于,Jdk代理与目标类都会实现同一个接口,并且在代理类中会调用目标类中被代理的方法,调用者实际调用的则是代理类的方法,通过这种方式我们就可以在代理类中织入切面逻辑;Jdk代理存在的问题在于目标类被代理的方法必须实现某个接口,Cglib代理则是为了解决这个问题而存在的,其实现代理的方式是通过为目标类动态生成一个子类,通过在子类中织入相应逻辑来达到织入代理逻辑的目的。关于Jdk代理和Cglib代理,其优缺点

Spring Aop实现对目标对象的代理,主要有两种方式:Jdk代理和Cglib代理。这两种代理的区别在于,Jdk代理与目标类都会实现同一个接口,并且在代理类中会调用目标类中被代理的方法,调用者实际调用的则是代理类的方法,通过这种方式我们就可以在代理类中织入切面逻辑;Jdk代理存在的问题在于目标类被代理的方法必须实现某个接口,Cglib代理则是为了解决这个问题而存在的,其实现代理的方式是通过为目标类动态生成一个子类,通过在子类中织入相应逻辑来达到织入代理逻辑的目的。

关于Jdk代理和Cglib代理,其优缺点主要在于:

  • Jdk代理生成的代理类只有一个,因而其编译速度是非常快的;而由于被代理的目标类是动态传入代理类中的,Jdk代理的执行效率相对来说低一点,这也是Jdk代理被称为动态代理的原因;
  • Cglib代理需要为每个目标类生成相应的子类,因而在实际运行过程中,其可能会生成非常多的子类,过多的子类始终不是太好的,因为这影响了虚拟机编译类的效率;但由于在调用过程中,代理类的方法是已经静态编译生成了的,因而Cglib代理的执行效率相对来说高一些。

本文主要讲解Spring Aop是如何通过Cglib代理实现将切面逻辑织入目标类的。

1. AopProxy织入对象生成

前面我们讲过,Spring Aop织入切面逻辑的入口方法是 AbstractAutoProxyCreator.createProxy() 方法,如下是该方法的源码:

protected Object createProxy(Class<?> beanClass, @Nullable String beanName,
        @Nullable Object[] specificInterceptors, TargetSource targetSource) {
    
    // 如果当前beanFactory实现了ConfigurableListableBeanFactory接口,则将需要被代理的
    // 对象暴露出来
    if (this.beanFactory instanceof ConfigurableListableBeanFactory) {
        AutoProxyUtils.exposeTargetClass((ConfigurableListableBeanFactory) 
            this.beanFactory, beanName, beanClass);
    }

    // 创建代理工厂
    ProxyFactory proxyFactory = new ProxyFactory();
    // 复制proxyTargetClass,exposeProxy等属性
    proxyFactory.copyFrom(this);

    // 如果当前设置了不使用Cglib代理目标类,则判断目标类是否设置了preserveTargetClass属性,
    // 如果设置了,则还是强制使用Cglib代理目标类;如果没有设置,则判断目标类是否实现了相关接口,
    // 没有设置,则还是使用Cglib代理。需要注意的是Spring默认使用的是Jdk代理来织入切面逻辑。
    if (!proxyFactory.isProxyTargetClass()) {
        // 判断目标类是否设置了preserveTargetClass属性
        if (shouldProxyTargetClass(beanClass, beanName)) {
            proxyFactory.setProxyTargetClass(true);
        } else {
            // 判断目标类是否实现了相关接口
            evaluateProxyInterfaces(beanClass, proxyFactory);
        }
    }

    // 将需要织入的切面逻辑都转换为Advisor对象
    Advisor[] advisors = buildAdvisors(beanName, specificInterceptors);
    proxyFactory.addAdvisors(advisors);
    proxyFactory.setTargetSource(targetSource);
    // 提供的hook方法,供子类实现以实现对代理工厂的定制
    customizeProxyFactory(proxyFactory);

    proxyFactory.setFrozen(this.freezeProxy);
    // 当前判断逻辑默认返回false,子类可进行重写,对于AnnotationAwareAspectJAutoProxyCreator,
    // 其重写了该方法返回true,因为其已经对获取到的Advisor进行了过滤,后面不需要在对目标类进行重新
    // 匹配了
    if (advisorsPreFiltered()) {
        proxyFactory.setPreFiltered(true);
    }

    // 生成代理类
    return proxyFactory.getProxy(getProxyClassLoader());
}

可以看到,在生成代理类之前,主要做了两件事:①判断使用Jdk代理还是Cglib代理;②设置相关的属性。这里我们继续看最后的 ProxyFactory.getProxy() 方法:

public Object getProxy(@Nullable ClassLoader classLoader) {
    // 首先获取AopProxy对象,其主要有两个实现:JdkDynamicAopProxy和ObjenesisCglibAopProxy,
    // 分别用于Jdk和Cglib代理类的生成,其getProxy()方法则用于获取具体的代理对象
    return createAopProxy().getProxy(classLoader);
}

上面的 createAopProxy() 方法可以理解为一个工厂方法,返回值是一个AopProxy类型的对象,其内部根据具体的条件生成相应的子类对象,即JdkDynamicAopProxy和ObjenesisCglibAopProxy。后面则通过调用 AopProxy.getProxy() 方法获取代理过的对象。如下是 createAopProxy() 方法的实现逻辑:

public AopProxy createAopProxy(AdvisedSupport config) throws AopConfigException {
    // 判断当前类是否需要进行运行时优化,或者是指定了使用Cglib代理的方式,再或者是目标类没有用户提供的
    // 相关接口,则使用Cglib代理实现代理逻辑的织入
    if (config.isOptimize() || config.isProxyTargetClass() || 
        hasNoUserSuppliedProxyInterfaces(config)) {
        Class<?> targetClass = config.getTargetClass();
        if (targetClass == null) {
            throw new AopConfigException("TargetSource cannot determine target class: " 
                + "Either an interface or a target is required for proxy creation.");
        }
        // 如果被代理的类是一个接口,或者被代理的类是使用Jdk代理生成的类,此时还是使用Jdk代理
        if (targetClass.isInterface() || Proxy.isProxyClass(targetClass)) {
            return new JdkDynamicAopProxy(config);
        }
        
        // 返回Cglib代理织入类对象
        return new ObjenesisCglibAopProxy(config);
    } else {
        // 返回Jdk代理织入类对象
        return new JdkDynamicAopProxy(config);
    }
}

这里可以看到,本文需要讲解的Cglib代理逻辑的织入就在 ObjenesisCglibAopProxy.getProxy() 方法中。

2. 代理逻辑的织入

关于代理逻辑的织入,其实现主体还是通过 Enhancer 来实现,即通过需要织入的Advisor列表,生成Callback对象,并将其设置到 Enhancer 对象中,最后通过 Enhancer 生成目标对象。如下是 AopProxy.getProxy() 方法的源码:

public Object getProxy(@Nullable ClassLoader classLoader) {
    if (logger.isDebugEnabled()) {
        logger.debug("Creating CGLIB proxy: target source is " 
            + this.advised.getTargetSource());
    }

    try {
        Class<?> rootClass = this.advised.getTargetClass();
        Assert.state(rootClass != null, 
                     "Target class must be available for creating a CGLIB proxy");

        // 判断当前类是否是已经通过Cglib代理生成的类,如果是的,则获取其原始父类,
        // 并将其接口设置到需要代理的接口中
        Class<?> proxySuperClass = rootClass;
        if (ClassUtils.isCglibProxyClass(rootClass)) {
            // 获取父类
            proxySuperClass = rootClass.getSuperclass();
            // 获取父类实现的接口,并将其设置到需要代理的接口中
            Class<?>[] additionalInterfaces = rootClass.getInterfaces();
            for (Class<?> additionalInterface : additionalInterfaces) {
                this.advised.addInterface(additionalInterface);
            }
        }

        // 对目标类进行检查,主要检查点有三个:
        // 1. 目标方法不能使用final修饰;
        // 2. 目标方法不能是private类型的;
        // 3. 目标方法不能是包访问权限的;
        // 这三个点满足任何一个,当前方法就不能被代理,此时该方法就会被略过
        validateClassIfNecessary(proxySuperClass, classLoader);

        // 创建Enhancer对象,并且设置ClassLoader
        Enhancer enhancer = createEnhancer();
        if (classLoader != null) {
            enhancer.setClassLoader(classLoader);
            if (classLoader instanceof SmartClassLoader &&
                ((SmartClassLoader) classLoader).isClassReloadable(proxySuperClass)) {
                enhancer.setUseCache(false);
            }
        }
        enhancer.setSuperclass(proxySuperClass);
        // 这里AopProxyUtils.completeProxiedInterfaces()方法的主要目的是为要生成的代理类
        // 增加SpringProxy,Advised,DecoratingProxy三个需要实现的接口。这里三个接口的作用如下:
        // 1. SpringProxy:是一个空接口,用于标记当前生成的代理类是Spring生成的代理类;
        // 2. Advised:Spring生成代理类所使用的属性都保存在该接口中,
        //    包括Advisor,Advice和其他相关属性;
        // 3. DecoratingProxy:该接口用于获取当前代理对象所代理的目标对象的Class类型。
        enhancer.setInterfaces(AopProxyUtils.completeProxiedInterfaces(this.advised));
        enhancer.setNamingPolicy(SpringNamingPolicy.INSTANCE);
        enhancer.setStrategy(new 
            ClassLoaderAwareUndeclaredThrowableStrategy(classLoader));

        // 获取当前需要织入到代理类中的逻辑
        Callback[] callbacks = getCallbacks(rootClass);
        Class<?>[] types = new Class<?>[callbacks.length];
        for (int x = 0; x < types.length; x++) {
            types[x] = callbacks[x].getClass();
        }

        // 设置代理类中各个方法将要使用的切面逻辑,这里ProxyCallbackFilter.accept()方法返回
        // 的整型值正好一一对应上面Callback数组中各个切面逻辑的下标,也就是说这里的CallbackFilter
        // 的作用正好指定了代理类中各个方法将要使用Callback数组中的哪个或哪几个切面逻辑
        enhancer.setCallbackFilter(new ProxyCallbackFilter(
            this.advised.getConfigurationOnlyCopy(), this.fixedInterceptorMap, 
            this.fixedInterceptorOffset));
        enhancer.setCallbackTypes(types);

        // 生成代理对象
        return createProxyClassAndInstance(enhancer, callbacks);
    } catch (CodeGenerationException | IllegalArgumentException ex) {
        throw new AopConfigException("Could not generate CGLIB subclass of class [" 
            + this.advised.getTargetClass() + "]: Common causes of this problem "  
            + "include using a final class or a non-visible class", ex);
    } catch (Throwable ex) {
        throw new AopConfigException("Unexpected AOP exception", ex);
    }
}

可以看到,这里的 AopProxy.getProxy() 方法就是生成代理对象的主干逻辑。上面的逻辑中主要有两个部分需要重点讲解:①如果获取Callback数组;②CallbackFilter的作用。关于第一点,我们后面会进行重点讲解,至于第二点,这里我们需要理解的就是CallbackFilter.accept()方法接收一个Method类型的参数,该参数也即当前要生成的代理逻辑的方法,这里的accept()方法将返回目标当前要织入代理逻辑的方法所需要使用的切面逻辑,也即Callback对象在Callback数组中的下标。关于CallbackFilter的使用原理,读者可以阅读 实战CGLib系列之proxy篇(二):回调过滤CallbackFilter 这篇文章。下面我们继续阅读 getCallbacks() 的源码:

private Callback[] getCallbacks(Class<?> rootClass) throws Exception {
    boolean exposeProxy = this.advised.isExposeProxy();
    boolean isFrozen = this.advised.isFrozen();
    boolean isStatic = this.advised.getTargetSource().isStatic();

    // 用户自定义的代理逻辑的主要织入类
    Callback aopInterceptor = new DynamicAdvisedInterceptor(this.advised);

    Callback targetInterceptor;
    // 判断如果要暴露代理对象,如果是,则使用AopContext设置将代理对象设置到ThreadLocal中
    // 用户则可以通过AopContext获取目标对象
    if (exposeProxy) {
        // 判断被代理的对象是否是静态的,如果是静态的,则将目标对象缓存起来,每次都使用该对象即可,
        // 如果目标对象是动态的,则在DynamicUnadvisedExposedInterceptor中每次都生成一个新的
        // 目标对象,以织入后面的代理逻辑
        targetInterceptor = isStatic ?
          new StaticUnadvisedExposedInterceptor(
            this.advised.getTargetSource().getTarget()) :
          new DynamicUnadvisedExposedInterceptor(this.advised.getTargetSource());
    } else {
        // 下面两个类与上面两个的唯一区别就在于是否使用AopContext暴露生成的代理对象
        targetInterceptor = isStatic ?
            new StaticUnadvisedInterceptor(this.advised.getTargetSource().getTarget()) :
        new DynamicUnadvisedInterceptor(this.advised.getTargetSource());
    }

    // 当前Callback用于一般的不用背代理的方法,这些方法
    Callback targetDispatcher = isStatic ?
        new StaticDispatcher(this.advised.getTargetSource().getTarget()) 
        : new SerializableNoOp();

    // 将获取到的callback组装为一个数组
    Callback[] mainCallbacks = new Callback[] {
        aopInterceptor,  // 用户自己定义的拦截器
        targetInterceptor,  // 根据条件是否暴露代理对象的拦截器
        new SerializableNoOp(),  // 不做任何操作的拦截器
        targetDispatcher, this.advisedDispatcher,  // 用于存储Advised对象的分发器
        new EqualsInterceptor(this.advised),  // 针对equals方法调用的拦截器
        new HashCodeInterceptor(this.advised)  // 针对hashcode方法调用的拦截器
    };

    Callback[] callbacks;
    // 如果目标对象是静态的,也即可以缓存的,并且切面逻辑的调用链是固定的,
    // 则对目标对象和整个调用链进行缓存
    if (isStatic && isFrozen) {
        Method[] methods = rootClass.getMethods();
        Callback[] fixedCallbacks = new Callback[methods.length];
        this.fixedInterceptorMap = new HashMap<>(methods.length);

        for (int x = 0; x < methods.length; x++) {
            // 获取目标对象的切面逻辑
            List<Object> chain = 
                this.advised.getInterceptorsAndDynamicInterceptionAdvice(
                methods[x], rootClass);
            fixedCallbacks[x] = new FixedChainStaticTargetInterceptor(
                chain, this.advised.getTargetSource().getTarget(), 
                this.advised.getTargetClass());
            // 对调用链进行缓存
            this.fixedInterceptorMap.put(methods[x].toString(), x);
        }

        // 将生成的静态调用链存入Callback数组中
        callbacks = new Callback[mainCallbacks.length + fixedCallbacks.length];
        System.arraycopy(mainCallbacks, 0, callbacks, 0, mainCallbacks.length);
        System.arraycopy(fixedCallbacks, 0, callbacks, mainCallbacks.length, 
            fixedCallbacks.length);
        // 这里fixedInterceptorOffset记录了当前静态的调用链的切面逻辑的起始位置,
        // 这里记录的用处在于后面使用CallbackFilter的时候,如果发现是静态的调用链,
        // 则直接通过该参数获取相应的调用链,而直接略过了前面的动态调用链
        this.fixedInterceptorOffset = mainCallbacks.length;
    } else {
        callbacks = mainCallbacks;
    }
    return callbacks;
}

这里的getCallbacks()方法主要做了三件事:①获取目标对象的动态调用链;②判断是否设置了exposeProxy属性,如果设置了,则生成一个可以暴露代理对象的Callback对象,否则生成一个不做任何处理直接调用目标对象的Callback对象;③判断目标对象是否是静态的,并且当前的切面逻辑是否是固定的,如果是,则将目标对象和调用链进行缓存,以便后续直接调用。这里需要说明的一个点在于第三点,因为在判断目标对象为静态对象,并且调用链是固定的时候,会将目标对象和调用链进行缓存,并且封装到指定的Callback对象中。这里读者可能会疑问为什么动态调用链和静态调用链都进行了缓存,这和前面讲解的CallbackFilter是息息相关的,因为上述代码最后使用fixedInterceptorOffset记录了当前静态调用链在数组中存储的位置,我们前面也讲了,Enhancer可以通过CallbackFilter返回的整数值来动态的指定从当前对象Callback数组中的第几个环绕逻辑开始织入,这里就会使用到fixedInterceptorOffset。从上述代码中可以看出,用户自定义的调用链是在DynamicAdvisedInterceptor中生成的(关于静态调用链的生成实际上是同样的逻辑,只不过静态调用链会被缓存),这里我们看看DynamicAdvisedInterceptor的实现源码:

public Object intercept(Object proxy, Method method, Object[] args, 
        MethodProxy methodProxy) throws Throwable {
    Object oldProxy = null;
    boolean setProxyContext = false;
    Object target = null;
    // 通过TargetSource获取目标对象
    TargetSource targetSource = this.advised.getTargetSource();
    try {
        // 判断如果需要暴露代理对象,则将当前代理对象设置到ThreadLocal中
        if (this.advised.exposeProxy) {
            oldProxy = AopContext.setCurrentProxy(proxy);
            setProxyContext = true;
        }

        target = targetSource.getTarget();
        Class<?> targetClass = (target != null ? target.getClass() : null);
        // 获取目标对象切面逻辑的环绕链
        List<Object> chain = this.advised
            .getInterceptorsAndDynamicInterceptionAdvice(method, targetClass);
        Object retVal;
        if (chain.isEmpty() && Modifier.isPublic(method.getModifiers())) {
            // 对参数进行处理,以使其与目标方法的参数类型一致,尤其对于数组类型,
            // 会单独处理其数据类型与实际类型一致
            Object[] argsToUse = AopProxyUtils.adaptArgumentsIfNecessary(method, args);
            // 因为没有切面逻辑需要织入,这里直接调用目标方法
            retVal = methodProxy.invoke(target, argsToUse);
        } else {
            // 通过生成的调用链,对目标方法进行环绕调用
            retVal = new CglibMethodInvocation(proxy, target, method, 
                args, targetClass, chain, methodProxy).proceed();
        }
        
        // 对返回值进行处理,如果返回值就是当前目标对象,那么将代理生成的代理对象返回;
        // 如果返回值为空,并且返回值类型是非void的基本数据类型,则抛出异常;
        // 如果上述两个条件都不符合,则直接将生成的返回值返回
        retVal = processReturnType(proxy, target, method, retVal);
        return retVal;
    } finally {
        // 如果目标对象不是静态的,则调用TargetSource.releaseTarget()方法释放目标对象
        if (target != null && !targetSource.isStatic()) {
            targetSource.releaseTarget(target);
        }
        
        // 将代理对象设置为前面(外层逻辑)调用设置的对象,以防止暴露出来的代理对象不一致
        if (setProxyContext) {
            AopContext.setCurrentProxy(oldProxy);
        }
    }
}

这里intercept()方法里主要逻辑有两点:①为目标对象生成切面逻辑调用链;②通过切面逻辑对目标对象进行环绕,并且进行调用。关于这两点,我们都会进行讲解,这里我们首先看看Cglib是如何生成调用链的,如下是 getInterceptorsAndDynamicInterceptionAdvice() 方法最终调用的源码,中间略过了部分比较简单的调用:

public List<Object> getInterceptorsAndDynamicInterceptionAdvice(
			Advised config, Method method, @Nullable Class<?> targetClass) {

    List<Object> interceptorList = new ArrayList<>(config.getAdvisors().length);
    Class<?> actualClass = (targetClass != null ? 
        targetClass : method.getDeclaringClass());
    // 判断切面逻辑中是否有IntroductionAdvisor类型的Advisor
    boolean hasIntroductions = hasMatchingIntroductions(config, actualClass);
    AdvisorAdapterRegistry registry = GlobalAdvisorAdapterRegistry.getInstance();

    for (Advisor advisor : config.getAdvisors()) {
        if (advisor instanceof PointcutAdvisor) {
            PointcutAdvisor pointcutAdvisor = (PointcutAdvisor) advisor;
            // 这里判断切面逻辑的调用链是否提前进行过过滤,如果进行过,则不再进行目标方法的匹配,
            // 如果没有,则再进行一次匹配。这里我们使用的AnnotationAwareAspectJAutoProxyCreator
            // 在生成切面逻辑的时候就已经进行了过滤,因而这里返回的是true,本文最开始也对这里进行了讲解
            if (config.isPreFiltered() || pointcutAdvisor.getPointcut()
                .getClassFilter().matches(actualClass)) {
                // 将Advisor对象转换为MethodInterceptor数组
                MethodInterceptor[] interceptors = registry.getInterceptors(advisor);
                MethodMatcher mm = pointcutAdvisor.getPointcut().getMethodMatcher();
                // 这里进行匹配的时候,首先会检查是否为IntroductionAwareMethodMatcher类型的
                // Matcher,如果是,则调用其定义的matches()方法进行匹配,如果不是,则直接调用
                // 当前切面的matches()方法进行匹配。这里由于前面进行匹配时可能存在部分在静态匹配时
                // 无法确认的方法匹配结果,因而这里调用是必要的,而对于能够确认的匹配逻辑,这里调用
                // 也是非常迅速的,因为前面已经对匹配结果进行了缓存
                if (MethodMatchers.matches(mm, method, actualClass, hasIntroductions)) {
                    // 判断如果是动态匹配,则使用InterceptorAndDynamicMethodMatcher对其进行封装
                    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;
            // 判断如果为IntroductionAdvisor类型的Advisor,则将调用链封装为Interceptor数组
            if (config.isPreFiltered() || ia.getClassFilter().matches(actualClass)) {
                Interceptor[] interceptors = registry.getInterceptors(advisor);
                interceptorList.addAll(Arrays.asList(interceptors));
            }
        } else {
            // 这里是提供的使用自定义的转换器对Advisor进行转换的逻辑,因为getInterceptors()方法中
            // 会使用相应的Adapter对目标Advisor进行匹配,如果能匹配上,通过其getInterceptor()方法
            // 将自定义的Advice转换为MethodInterceptor对象
            Interceptor[] interceptors = registry.getInterceptors(advisor);
            interceptorList.addAll(Arrays.asList(interceptors));
        }
    }

    return interceptorList;
}

这里获取调用链的逻辑其实比较简单,其最终的目的就是将Advisor数组一个一个的封装为Interceptor对象。在进行Advisor封装的时候,这里分为了三种类型:

  • 如果目标切面逻辑是一般的切面逻辑,即PointcutAdvisor,则会在运行时对目标方法进行动态匹配,因为前面可能存在还不能确认的是否应该应用切面逻辑的方法;
  • 如果切面逻辑是IntroductionAdvisor的,则将其封装为Interceptor类型的数组;
  • 如果以上两个都不是,说明切面逻辑可能是用户自定义的切面逻辑,这里就通过注册的AdvisorAdapter进行匹配,如果某个Adapter能够支持当前Advisor的转换,则调用其getInterceptor()方法将Advisor转换为MethodInterceptor返回。

下面我们看看Cglib是如何通过生成的切面调用链将目标对象进行环绕的。前面我们讲了,将切面逻辑进行织入的逻辑在 CglibMethodInvocation 中,实际上其调用逻辑在其 proceed() 方法中,这里我们直接看该方法的源码:

public Object proceed() throws Throwable {
    // 这里currentInterceptorIndex记录了当前调用链中正在调用的Intercepor的下标,该数值初始为-1
    if (this.currentInterceptorIndex == 
        this.interceptorsAndDynamicMethodMatchers.size() - 1) {
        // 如果调用链为空,则直接调用目标方法
        return invokeJoinpoint();
    }

    // 获取下一个需要织入的Interceptor逻辑
    Object interceptorOrInterceptionAdvice =
        this.interceptorsAndDynamicMethodMatchers.get(++this.currentInterceptorIndex);
    if (interceptorOrInterceptionAdvice instanceof InterceptorAndDynamicMethodMatcher) {
        InterceptorAndDynamicMethodMatcher dm =
            (InterceptorAndDynamicMethodMatcher) interceptorOrInterceptionAdvice;
        // 对动态的方法进行匹配,如果匹配成功,才进行调用,否则直接进行下一个Interceptor的调用
        if (dm.methodMatcher.matches(this.method, this.targetClass, this.arguments)) {
            return dm.interceptor.invoke(this);
        } else {
            return proceed();
        }
    } else {
        // 如果不需要进行动态匹配,则直接进行下一步的调用
        return ((MethodInterceptor) interceptorOrInterceptionAdvice).invoke(this);
    }
}

这里 proceed() 方法的逻辑比较简单,其使用一个索引记录了当前正在调用的Interceptor在调用链中的位置,并且依次对调用链进行调用,从而实现将切面逻辑织入目标对象的目的。这里最终对目标对象的调用的逻辑在 invokeJoinpoint() 方法中。

3. 小结

本文首先讲解Spring是如何通过配置的参数来选择使用哪种代理方式的,然后重点讲解了Spring Aop是如何使用Cglib代理实现代理逻辑的织入的。


以上所述就是小编给大家介绍的《原 荐 Spring Aop之Cglib实现原理详解》,希望对大家有所帮助,如果大家有任何疑问请给我留言,小编会及时回复大家的。在此也非常感谢大家对 码农网 的支持!

查看所有标签

猜你喜欢:

本站部分资源来源于网络,本站转载出于传递更多信息之目的,版权归原作者或者来源机构所有,如转载稿涉及版权问题,请联系我们

Agile Web Development with Rails 4

Agile Web Development with Rails 4

Sam Ruby、Dave Thomas、David Heinemeier Hansson / Pragmatic Bookshelf / 2013-10-11 / USD 43.95

Ruby on Rails helps you produce high-quality, beautiful-looking web applications quickly. You concentrate on creating the application, and Rails takes care of the details. Tens of thousands of deve......一起来看看 《Agile Web Development with Rails 4》 这本书的介绍吧!

JS 压缩/解压工具
JS 压缩/解压工具

在线压缩/解压 JS 代码

SHA 加密
SHA 加密

SHA 加密工具

HEX CMYK 转换工具
HEX CMYK 转换工具

HEX CMYK 互转工具