spring源码深度解析---创建AOP代理之创建代理

创建代理

在获取了所有对应bean的增强后,便可以进行代理的创建了。回到AbstractAutoProxyCreator的wrapIfNecessary方法中,如下图所示:
这里写图片描述
这里就是创建代码的代码,我们进入到方法内部:

protected Object createProxy(Class<?> beanClass, @Nullable String beanName,
        @Nullable Object[] specificInterceptors, TargetSource targetSource) {

    if (this.beanFactory instanceof ConfigurableListableBeanFactory) {
        AutoProxyUtils.exposeTargetClass((ConfigurableListableBeanFactory) this.beanFactory, beanName, beanClass);
    }

    ProxyFactory proxyFactory = new ProxyFactory();
    //获取当前类中的属性
    proxyFactory.copyFrom(this);
    //检查proxyTargeClass设置以及preserveTargetClass属性  
    //决定对于给定的bean是否应该使用targetClass而不是他的接口代理
    if (!proxyFactory.isProxyTargetClass()) {
        if (shouldProxyTargetClass(beanClass, beanName)) {
            proxyFactory.setProxyTargetClass(true);
        }
        else {
            //用来添加代理接口
            evaluateProxyInterfaces(beanClass, proxyFactory);
        }
    }

    Advisor[] advisors = buildAdvisors(beanName, specificInterceptors);
    //加入增强器
    proxyFactory.addAdvisors(advisors);
    //设置要代理的类
    proxyFactory.setTargetSource(targetSource);
    //定制代理
    customizeProxyFactory(proxyFactory);
    //用来控制代理工厂被设置后是否还允许修改通知,缺省值为false
    proxyFactory.setFrozen(this.freezeProxy);
    if (advisorsPreFiltered()) {
        proxyFactory.setPreFiltered(true);
    }

    return proxyFactory.getProxy(getProxyClassLoader());
}

从上面代码我们看到对于代理类的创建及处理spring是委托给了ProxyFactory处理的,而在此函数中主要是对ProxyFactory的初始化操作,进而对郑州的创建代理做准备,这些初始化操作包括以下内容:
(1)获取当前类中的属性
(2)添加代理接口
下面是添加代理接口evaluateProxyInterfaces的函数:

    protected void evaluateProxyInterfaces(Class<?> beanClass, ProxyFactory proxyFactory) {
        Class<?>[] targetInterfaces = ClassUtils.getAllInterfacesForClass(beanClass, getProxyClassLoader());
        boolean hasReasonableProxyInterface = false;
        for (Class<?> ifc : targetInterfaces) {
            if (!isConfigurationCallbackInterface(ifc) && !isInternalLanguageInterface(ifc) &&
                    ifc.getMethods().length > 0) {
                hasReasonableProxyInterface = true;
                break;
            }
        }
        if (hasReasonableProxyInterface) {
            // Must allow for introductions; can't just set interfaces to the target's interfaces only.
            for (Class<?> ifc : targetInterfaces) {
                proxyFactory.addInterface(ifc);
            }
        }
        else {
            proxyFactory.setProxyTargetClass(true);
        }
    }

(3)封装Advisor并加入到ProxyFactory中
(4)设置要代理的类
(5)在spring中还为子类提供了定制的函数customizeProxyFactory,子类可以在此函数中进行对ProxyFactory的进一步封装
(6)进行获取代理操作
其中,封装Advisor并加入到ProxyFactory中以及创建代理是两个相对繁琐的过程,可以通过ProxyFactory提供的addAdvisor方法直接将增强器置入代理创建工厂中,但是将拦截器封装为增强器还是需要一定的逻辑的。继续看下buildAdvisors方法:

protected Advisor[] buildAdvisors(@Nullable String beanName, @Nullable Object[] specificInterceptors) {
    // Handle prototypes correctly...
    Advisor[] commonInterceptors = resolveInterceptorNames();

    List<Object> allInterceptors = new ArrayList<>();
    if (specificInterceptors != null) {
        allInterceptors.addAll(Arrays.asList(specificInterceptors));
        if (commonInterceptors.length > 0) {
            if (this.applyCommonInterceptorsFirst) {
                allInterceptors.addAll(0, Arrays.asList(commonInterceptors));
            }
            else {
                allInterceptors.addAll(Arrays.asList(commonInterceptors));
            }
        }
    }
    if (logger.isDebugEnabled()) {
        int nrOfCommonInterceptors = commonInterceptors.length;
        int nrOfSpecificInterceptors = (specificInterceptors != null ? specificInterceptors.length : 0);
        logger.debug("Creating implicit proxy for bean '" + beanName + "' with " + nrOfCommonInterceptors +
                " common interceptors and " + nrOfSpecificInterceptors + " specific interceptors");
    }
    Advisor[] advisors = new Advisor[allInterceptors.size()];
    for (int i = 0; i < allInterceptors.size(); i++) {
        advisors[i] = this.advisorAdapterRegistry.wrap(allInterceptors.get(i));
    }
    return advisors;
}

我们看到方法内部最后用到了wrap方法,继续跟踪代码:

public Advisor wrap(Object adviceObject) throws UnknownAdviceTypeException {
    //如果要封装的对象本身就是Advisor类型的那么无需坐过多处理  
    if(adviceObject instanceof Advisor)  
        return (Advisor)adviceObject;  
    //因为此封装只对Advisor和Advice两种类型的数据有效,如果不是将不能封装  
    if(!(adviceObject instanceof Advice))  
        throw new UnknownAdviceTypeException(adviceObject);  
    Advice advice = (Advice)adviceObject;  
    if(advice instanceof MethodInterceptor)  
        //如果是MethodInterceptor类型则使用DefaultPointcutrAdvisor封装  
        return new DefaultPointcutAdvisor(advice);  
    //如果存在Advisor类型的适配器那么也同样需要进行封装  
    for(Iterator i$ = adapters.iterator(); i$.hasNext();)  
    {  
        AdvisorAdapter adapter = (AdvisorAdapter)i$.next();  
        if(adapter.supportsAdvice(advice))  
            return new DefaultPointcutAdvisor(advice);  
    } 
    throw new UnknownAdviceTypeException(advice);
}

由于Spring中涉及过多的拦截器,增强器,增强方法等方式来对逻辑进行增强,所以非常有必要统一封装成Advisor来进行代理的创建,完成了增强的封装过程,那么解析最终的一部就是代理的创建驭获取了。如下方法:

    public Object getProxy(@Nullable ClassLoader classLoader) {
        return createAopProxy().getProxy(classLoader);
    }

3.1 创建代理

在上面的getProxy方法中createAopProxy方法,其实现是在DefaultAopProxyFactory中,我们进入到方法内:

protected final synchronized AopProxy createAopProxy() {
    if (!this.active) {
        activate();
    }
    return getAopProxyFactory().createAopProxy(this);
}

到此已经完成了代理的创建,不管我们之前是否有阅读过Spring的源码,但是都或多或少地听过对于Spirng的代理中JDKProxy的实现和CglibProxy的实现。Spring是如何选取的呢?网上的介绍到处都是,现在我们就从源代码的角度分析,看看到底Spring是如何选择代理方式的。
从if中的判断条件可以看到3个方面影响着Spring的判断:
(1)optimize:用来控制通过CGLIB创建的代理是否使用激进的优化策略。除非完全了解AOP代理是如何优化,否则不推荐用户使用这个设置,目前这个属性仅用于CGLIB代理,对于JDK动态代理(缺省代理)无效。
(2)proxyTargetClass:这个属性为treu时,目标类本身被代理而不是目标类的接口。如果这个属性值被设为true,CGLIB代理将被创建,。
(3)hasNoUserSuppliedProxyInterfaces:是否存在代理接口。
下面我们就简单的对JDK与CGlib创建代理的方式进行总结:
(1)如果目标对象实现了接口,默认情况下会采用JDK的动态代理实现AOP
(2)如果目标对实现了接口,可以强制使用CGLIB实现AOP
(3)如果目标对象没有实现接口,必须采用CGLIB库,Spring会自动在JDK动态代理和CGLIB代理直接转换。
如何强制使用CGLIB实现AOP?
(1)添加CGLIB依赖库
(2)在spring的配置文件中加入
JDK动态代理和CGLIB字节码生成的区别?
(1)JDK动态代理只能对实现了接口的类生成代理,而不能针对类
(2)CGLIB是针对类实现代理的,主要是对指定的类生成一个子类,覆盖其中的方法,因为是继承,所以该类或方法最好不要声明成final。

3.2 获取代理

确定了使用哪种代理方式后便可以进行代理的创建了,在进行代理创建分析前我们先回顾下两种代理的使用.
3.2.1 两种代理的使用
1. JDK动态代理的使用
首先创建一个业务接口,如下:

public interface OrderService {
    void pay(double money);
}

业务接口的实现类:

public class OrderServiceImpl implements OrderService {
    public void pay(double money) {
        System.out.println("Pay money:"+money);
    }
}

创建自定义的InvocationHandler,用于对接口实现的方法进行增强:

public class OrderInvocationHandler implements InvocationHandler {
    // 目标对象
    private Object target;

    public OrderInvocationHandler(Object target)
    {
        super();
        this.target= target;
    }

    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
        System.out.println("Before method");
        Object result = method.invoke(target,args);
        System.out.println("After method");
        return result;
    }
    public Object getProxy()
    {
        return Proxy.newProxyInstance(Thread.currentThread().getContextClassLoader(),target.getClass().getInterfaces(),this);
    }
}

测试方法,验证实现的增强是否生效:

public class InvocationTest {
    public static void main(String[] args) {
        OrderService orderService = new OrderServiceImpl();

        OrderInvocationHandler handler = new OrderInvocationHandler(orderService);

        OrderService proxy = (OrderService)handler.getProxy();
        proxy.pay(100);
    }
}

执行测试结果输出如下:
Before method
Pay money:100.0
After method
用起来很简单,其实这是基本上就是AOP的一个简单的实现了,在目标对象的方法执行之前和执行之后进行了增强。Spring的AOP实现其实也是用了Proxy的InvocationHandler这两个东西的。
我们再次来回顾一下使用JDK代理的方式,在整个创建的过程中,对于InvocationHandler的创建时最为核心的,在自定义的InvocationHandler中需要重写3个函数。
(1)构造函数,将代理的对象传入
(2)invoke方法,此方法中实现了AOP增强的所有逻辑
(3)getProxy方法,此方法千篇一律,但是必不可少
那么,我们看看Spring中的JDK代理实现是不是也是这么做的呢?继续之前的跟踪,到达的JdkDynamicAopProxy的getProxy。其方法实现如下:

    public Object getProxy(@Nullable ClassLoader classLoader) {
        if (logger.isDebugEnabled()) {
            logger.debug("Creating JDK dynamic proxy: target source is " + this.advised.getTargetSource());
        }
        Class<?>[] proxiedInterfaces = AopProxyUtils.completeProxiedInterfaces(this.advised, true);
        findDefinedEqualsAndHashCodeMethods(proxiedInterfaces);
        return Proxy.newProxyInstance(classLoader, proxiedInterfaces, this);
    }

通过之前的示例我们知道,JDKProxy的使用关键是创建自定义的InvocationHandler,而InvocationHandler中包含了需要覆盖的函数getProxy,而当前的方法正是完成了这个操作。在此确认一下JDKDynamicAopProxy也确实实现了InvocationHandler接口,那么我们就可以推断出,在JdkDynamicAopProxy中一定会有个invoke函数,并且JdkDynamicAopProxy会把AOP的核心逻辑写在其中。查看代码,果然有这样个函数:

public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
        MethodInvocation invocation;
        Object oldProxy = null;
        boolean setProxyContext = false;

        TargetSource targetSource = this.advised.targetSource;
        Object target = null;

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

            // Get as late as possible to minimize the time we "own" the target,
            // in case it comes from a pool.
            target = targetSource.getTarget();
            Class<?> targetClass = (target != null ? target.getClass() : null);

            // 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 {
                // 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);
            }
        }
    }

上面的函数中最主要的工作就是创建了一个拦截器链,并使用ReflectiveMethodInvocation类进行了链的封装,而在ReflectiveMethodInvocation类的proceed方法中实现了拦截器的逐一调用,那么我们继续来研究,在proceed方法中是怎么实现前置增强在目标方法前调用后置增强在目标方法后调用的逻辑呢?进入到proceed方法内:

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);
        }
    }

在proceed方法中,获取代码逻辑并没有我们想象得那么复杂,ReflectiveMethodInvocation中的主要职责是维护了链接调用的计数器,记录着当前调用链的位置,以便链可以有序地进行下去,那么在这个方法中并没有我们之前设想的维护各种增强的顺序,而是将此工作委托给了各个增强器,使各个增强器在内部进行逻辑实现。
2. CGLIB代理的使用
CGLIB是一个强大的高性能的代码生成包。它广泛的被许多AOP框架使用,例如Spring AOP和dynaop,为他们提供方法的Interception(拦截)。最流行的ORMapping工具Hibernate也是使用CGLIB来代理单端single-ended(多对一和一对一)关联。EasyMock和JMock是通过使用模仿(moke)对象来测试Java代码的包,他们都通过使用CGLIB来Wie那些没有借口的类创建模仿(moke)对象。
CGLIB包的底层通过使用一个小而快的字节码处理框架ASM,来转换字节码并生产新的类。除了CGLIB包脚本语言例如Groovy和BeanShell也是使用ASM来生成java的字节码。当然不鼓励直接使用ASM,因为它要求你必须对JVM内部结构包括class文件的格式和指令集都非常熟悉。
接下来我们就简单的回顾下CGLIB的使用。如下代码:

import org.omg.PortableInterceptor.Interceptor;
import org.springframework.cglib.proxy.Enhancer;
import org.springframework.cglib.proxy.MethodInterceptor;
import org.springframework.cglib.proxy.MethodProxy;

import java.lang.reflect.Method;

public class CGLIBTest {
    public static void main(String[] args) {
        Enhancer enhancer = new Enhancer();
        enhancer.setSuperclass(CGLIBTest.class);
        enhancer.setCallback(new MethodInterceptorImpl());

        CGLIBTest test = (CGLIBTest)enhancer.create();
        test.test();
        System.out.println(test);
    }

    public void test()
    {
        System.out.println("CGLIB Test");
    }

    private static class MethodInterceptorImpl implements MethodInterceptor
    {
        public Object intercept(Object o, Method method, Object[] objects, MethodProxy methodProxy) throws Throwable {
            System.out.println("Before invoke");
            Object result = methodProxy.invokeSuper(o,objects);
            System.out.println("After invoke");
            return result;
        }
    }
}

执行结果如下:
Before invoke
CGLIB Test
After invoke
Before invoke
Before invoke
After invoke
After invoke
com.yhl.myspring.demo.aop.CGLIBTest

EnhancerByCGLIB E n h a n c e r B y C G L I B
e4c5202c@78e03bb5
我们可以看到System.out.println(test)方法中,test先调用了toString()方法,然后又调用了hashCode方法,生成的对象为.CGLIBTest
EnhancerByCGLIB E n h a n c e r B y C G L I B
e4c5202c@78e03bb5的实例,这个类是运行时由CGLIB产生的。
完成了CGLIB代理的类是委托给CglibAopProxy类去实现的,接下来我们就详细分析下。
按照前面提供的示例,我们很容易判断出来,CglibAopProxy的入口应该是在getProxy,也就是说在CglibAopProxy类的getProxy方法中实现了Enhancer的创建及接口的封装。如下代码:

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");

        Class<?> proxySuperClass = rootClass;
        if (ClassUtils.isCglibProxyClass(rootClass)) {
            proxySuperClass = rootClass.getSuperclass();
            Class<?>[] additionalInterfaces = rootClass.getInterfaces();
            for (Class<?> additionalInterface : additionalInterfaces) {
                this.advised.addInterface(additionalInterface);
            }
        }

        // Validate the class, writing log messages as necessary.
        validateClassIfNecessary(proxySuperClass, classLoader);

        // Configure CGLIB Enhancer...
        Enhancer enhancer = createEnhancer();
        if (classLoader != null) {
            enhancer.setClassLoader(classLoader);
            if (classLoader instanceof SmartClassLoader &&
                    ((SmartClassLoader) classLoader).isClassReloadable(proxySuperClass)) {
                enhancer.setUseCache(false);
            }
        }
        enhancer.setSuperclass(proxySuperClass);
        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();
        }
        // fixedInterceptorMap only populated at this point, after getCallbacks call above
        enhancer.setCallbackFilter(new ProxyCallbackFilter(
                this.advised.getConfigurationOnlyCopy(), this.fixedInterceptorMap, this.fixedInterceptorOffset));
        enhancer.setCallbackTypes(types);

        // Generate the proxy class and create a proxy instance.
        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) {
        // TargetSource.getTarget() failed
        throw new AopConfigException("Unexpected AOP exception", ex);
    }
}

以上函数完整的阐述了一个创建spring中的Enhancer的过程,读者可以参考Enhancer的文档查看每个步骤的含义,这里最重要的是通过getCallbacks方法设置拦截器链,如下:

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

        // Choose an "aop" interceptor (used for AOP calls).
        Callback aopInterceptor = new DynamicAdvisedInterceptor(this.advised);

        // Choose a "straight to target" interceptor. (used for calls that are
        // unadvised but can return this). May be required to expose the proxy.
        Callback targetInterceptor;
        if (exposeProxy) {
            targetInterceptor = isStatic ?
                    new StaticUnadvisedExposedInterceptor(this.advised.getTargetSource().getTarget()) :
                    new DynamicUnadvisedExposedInterceptor(this.advised.getTargetSource());
        }
        else {
            targetInterceptor = isStatic ?
                    new StaticUnadvisedInterceptor(this.advised.getTargetSource().getTarget()) :
                    new DynamicUnadvisedInterceptor(this.advised.getTargetSource());
        }

        // Choose a "direct to target" dispatcher (used for
        // unadvised calls to static targets that cannot return this).
        Callback targetDispatcher = isStatic ?
                new StaticDispatcher(this.advised.getTargetSource().getTarget()) : new SerializableNoOp();

        Callback[] mainCallbacks = new Callback[] {
                aopInterceptor,  // for normal advice
                targetInterceptor,  // invoke target without considering advice, if optimized
                new SerializableNoOp(),  // no override for methods mapped to this
                targetDispatcher, this.advisedDispatcher,
                new EqualsInterceptor(this.advised),
                new HashCodeInterceptor(this.advised)
        };

        Callback[] callbacks;

        // If the target is a static one and the advice chain is frozen,
        // then we can make some optimizations by sending the AOP calls
        // direct to the target using the fixed chain for that method.
        if (isStatic && isFrozen) {
            Method[] methods = rootClass.getMethods();
            Callback[] fixedCallbacks = new Callback[methods.length];
            this.fixedInterceptorMap = new HashMap<>(methods.length);

            // TODO: small memory optimization here (can skip creation for methods with no advice)
            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);
            }

            // Now copy both the callbacks from mainCallbacks
            // and fixedCallbacks into the callbacks array.
            callbacks = new Callback[mainCallbacks.length + fixedCallbacks.length];
            System.arraycopy(mainCallbacks, 0, callbacks, 0, mainCallbacks.length);
            System.arraycopy(fixedCallbacks, 0, callbacks, mainCallbacks.length, fixedCallbacks.length);
            this.fixedInterceptorOffset = mainCallbacks.length;
        }
        else {
            callbacks = mainCallbacks;
        }
        return callbacks;
    }

在getCallback方法中spring考虑了很多情况。这里我们只需要理解最重用的就可以,比如advised属性封装在DynamicAdviserdInterceptor并加入在callbacks中。

  • 0
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值