Spring AOP學習筆記04:AOP核心實現之創建代理

  上文中,我們分析了對所有增強器的獲取以及獲取匹配的增強器,在本文中我們就來分析一下Spring AOP中另一部分核心邏輯–代理的創建。這部分邏輯的入口是在wrapIfNecessary()方法中緊接着增強器的獲取之後的createProxy():

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

    ProxyFactory proxyFactory = new ProxyFactory();
    // 獲取當前類中相關屬性
    proxyFactory.copyFrom(this);
    // 決定對於給定的bean是否應該使用targetClass而不是它的接口進行代理
    if (!shouldProxyTargetClass(beanClass, beanName)) {
        // Must allow for introductions; can't just set interfaces to
        // the target's interfaces only.
        Class<?>[] targetInterfaces = ClassUtils.getAllInterfacesForClass(beanClass, this.proxyClassLoader);
        for (Class<?> targetInterface : targetInterfaces) {
            // 添加代理接口
            proxyFactory.addInterface(targetInterface);
        }
    }

    Advisor[] advisors = buildAdvisors(beanName, specificInterceptors);
    for (Advisor advisor : advisors) {
        // 加入增強器
        proxyFactory.addAdvisor(advisor);
    }
    // 設置要代理的類
    proxyFactory.setTargetSource(targetSource);
    // 定製代理
    customizeProxyFactory(proxyFactory);
    // 用來控制代理工廠被配置之後,是否還允許修改通知
    // 默認值為false(即在代理被配置之後,不允許修改代理的配置)
    proxyFactory.setFrozen(this.freezeProxy);
    if (advisorsPreFiltered()) {
        proxyFactory.setPreFiltered(true);
    }

    return proxyFactory.getProxy(this.proxyClassLoader);
}

  對於代理類的創建及處理,Spring委託給了ProxyFactory進行處理,而在上面的函數中主要是對ProxyFactory的初始化操作,為真正的代理創建做準備,初始化包括如下內容:

  • 獲取當前中的屬性;
  • 添加代理接口;
  • 封裝Advisor並加入到ProxyFactory中;
  • 設置要代理的類;
  • 對代理工廠進行定製化處理,供子類實現;
  • 進行獲取代理操作;

  其中封裝Advisor並加入到ProxyFactory中以及創建代理是兩個相對繁瑣的過程,可以通過ProxyFactory提供的addAdvisor方法直接將增強器置入代理創建工廠中,但是將攔截器封裝為增強器還是需要一定的邏輯的。

protected Advisor[] buildAdvisors(String beanName, Object[] specificInterceptors) {
    // 解析註冊的所有interceptorName
    Advisor[] commonInterceptors = resolveInterceptorNames();

    List<Object> allInterceptors = new ArrayList<Object>();
    if (specificInterceptors != null) {
        // 加入攔截器
        allInterceptors.addAll(Arrays.asList(specificInterceptors));
        if (commonInterceptors != null) {
            if (this.applyCommonInterceptorsFirst) {
                allInterceptors.addAll(0, Arrays.asList(commonInterceptors));
            }
            else {
                allInterceptors.addAll(Arrays.asList(commonInterceptors));
            }
        }
    }
    if (logger.isDebugEnabled()) {
        int nrOfCommonInterceptors = (commonInterceptors != null ? commonInterceptors.length : 0);
        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++) {
        // 將攔截器進行包裝轉化為Advisor
        advisors[i] = this.advisorAdapterRegistry.wrap(allInterceptors.get(i));
    }
    return advisors;
}

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類型則使用DefaultPointcutAdvisor封裝
        return new DefaultPointcutAdvisor(advice);
    }
    // 如果存在Advisor的適配器那麼也同樣需要進行封裝
    for (AdvisorAdapter adapter : this.adapters) {
        // Check that it is supported.
        if (adapter.supportsAdvice(advice)) {
            return new DefaultPointcutAdvisor(advice);
        }
    }
    throw new UnknownAdviceTypeException(advice);
}

  因為Spring中涉及過多的攔截器、增強器、增強方法等方式來對邏輯進行增強,所以非常有必要將增強器封裝成Advisor來進行代理的創建,完成了增強的封裝過程,那麼接下來就是最重要的一步–代理的創建與獲取。

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

1. 創建代理

protected final synchronized AopProxy createAopProxy() {
    if (!this.active) {
        activate();
    }
    // 創建代理
    return getAopProxyFactory().createAopProxy(this);
}

public AopProxy createAopProxy(AdvisedSupport config) throws AopConfigException {
    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.");
        }
        if (targetClass.isInterface()) {
            return new JdkDynamicAopProxy(config);
        }
        return CglibProxyFactory.createCglibProxy(config);
    }
    else {
        return new JdkDynamicAopProxy(config);
    }
}

  到這裏已經完成了代理的創建了,不管我們之前是否有閱讀過Spring的源碼,但是應該或多或少都聽說過對於Spring的代理中JDKProxy的實現CglibProxy的實現。Spring是如果選取的呢?現在我們就從源碼的角度分析,看看到底Spring是如何選擇代理方式的。

  從上面代碼中的判斷條件可以看到3個方面影響着Spring的判斷:

  • optimize:用來控制通過CGLIB創建的代理是否使用激進的優化策略。除非完全了解AOP代理如何處理優化,否則不推薦用戶使用這個設置。目前這個屬性僅用於CGLIB代理,對於JDK動態代理(默認代理)無效。
  • proxyTargetClass:這個屬性為true時,目標類本身被代理而不是目標類的接口,並且使用CGLIB方式創建代理,xml文件配置方式為:<aop:aspectj-autoproxy proxy-target-class=”true”/>。
  • hasNoUserSuppliedProxyInterfaces:是否存在代理接口。

  下面是對JDK與Cglib方式的總結:

  • 如果目標對象實現了接口,默認情況下會採用JDK的動態代理實現AOP;
  • 如果目標對象實現了接口,可以強制使用CGLIB實現AOP;
  • 如果目標對象沒有實現接口,則必須採用CGLIB方式實現AOP,Spring會自動切換;

如何強制使用CGLIB實現AOP?

  • 添加CGLIB庫,Spring_HOME/cglib/*.jar
  • 在Spring配置文件中加入<aop:aspectj-autoproxy proxy-target-class=”true”/>

JDK動態代理和CGLIB字節碼生成的區別?

  • JDK動態代理只能對實現了接口的類生成代理,而不能針對類。
  • CGLIB是針對類實現代理,主要是對指定的類生成一個子類,覆蓋其中的方法,因為是繼承,所以該類或方法最好不要聲明成final。

 

2. 獲取代理

  確定了使用哪種代理方式之後便可以進行代理的創建了,Spring中主要使用了兩種方式來實現代理的創建:JDK動態代理、cglib,我們一一來解析。

2.1 JDK動態代理方式

  這裏直接定位到JdkDynamicAopProxy中的getProxy():

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

  JDK動態代理的使用關鍵是創建自定義的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;
    Class<?> targetClass = null;
    Object target = null;

    try {
        // 處理equals方法
        if (!this.equalsDefined && AopUtils.isEqualsMethod(method)) {
            return equals(args[0]);
        }
        // 處理hash方法
        if (!this.hashCodeDefined && AopUtils.isHashCodeMethod(method)) {
            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) {
            oldProxy = AopContext.setCurrentProxy(proxy);
            setProxyContext = true;
        }

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

        // 獲取當前方法的攔截器鏈
        List<Object> chain = this.advised.getInterceptorsAndDynamicInterceptionAdvice(method, targetClass);

        if (chain.isEmpty()) {
            // 如果沒有任何攔截器鏈則直接調用切點方法
            retVal = AopUtils.invokeJoinpointUsingReflection(target, method, args);
        }
        else {
            // 將攔截器封裝在ReflectiveMethodInvocation,以便於使用其proceed進行鏈式調用攔截器
            invocation = new ReflectiveMethodInvocation(proxy, target, method, args, targetClass, chain);
            // 執行攔截器鏈
            retVal = invocation.proceed();
        }

        // 返回結果
        Class<?> returnType = method.getReturnType();
        if (retVal != null && retVal == target && returnType.isInstance(proxy) && !RawTargetAccess.class.isAssignableFrom(method.getDeclaringClass())) {
            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);
        }
    }
}

  上面的invoke()函數最主要的工作就是創建了一個攔截器鏈,並使用ReflectiveMethodInvocation類進行了鏈的封裝,而在ReflectiveMethodInvocation類的proceed方法中實現了攔截器的逐一調用,那麼我們就繼續來探究,在proceed方法中是怎麼實現諸如前置增強在目標方法前調用以及後置增強在目標方法后調用的邏輯的。

public Object proceed() throws Throwable {
    //    執行完所有增強后執行切點方法
    if (this.currentInterceptorIndex == this.interceptorsAndDynamicMethodMatchers.size() - 1) {
        return invokeJoinpoint();
    }
    // 獲取下一個要執行的攔截器
    Object interceptorOrInterceptionAdvice =
            this.interceptorsAndDynamicMethodMatchers.get(++this.currentInterceptorIndex);
    if (interceptorOrInterceptionAdvice instanceof InterceptorAndDynamicMethodMatcher) {
        // 動態匹配
        InterceptorAndDynamicMethodMatcher dm =
                (InterceptorAndDynamicMethodMatcher) interceptorOrInterceptionAdvice;
        if (dm.methodMatcher.matches(this.method, this.targetClass, this.arguments)) {
            return dm.interceptor.invoke(this);
        }
        else {
            // 若未匹配則不執行攔截器,調用攔截器鏈中下一個
            return proceed();
        }
    }
    else {
        // 普通攔截器,直接調用。將this作為參數傳入以保證當前實例中調用鏈的執行
        return ((MethodInterceptor) interceptorOrInterceptionAdvice).invoke(this);
    }
}

  ReflectiveMethodInvocation的主要職責是維護一個鏈式調用的計數器,記錄著當前調用鏈的位置,以便鏈可以有序地進行下去。其實在這個方法中並沒有我們設想的維護各種增強的順序,但是細心的讀者可能會發現,這部分工作其實是委託給了各個增強器來實現,前面有說到。

2.2 Cglib方式

  完成CGLIB代理的類是委託給CglibAopProxy類去實現的,我們來一探究竟。根據前面的分析,我們容易判斷出來,CglibAopProxy的入口應該也是在getProxy():

public Object getProxy(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);
            }
        }

        // 驗證Class
        validateClassIfNecessary(proxySuperClass);

        // 創建及配置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 MemorySafeUndeclaredThrowableStrategy(UndeclaredThrowableException.class));
        enhancer.setInterceptDuringConstruction(false);
        // 設置攔截器
        Callback[] callbacks = getCallbacks(rootClass);
        Class<?>[] types = new Class<?>[callbacks.length];
        for (int x = 0; x < types.length; x++) {
            types[x] = callbacks[x].getClass();
        }
        enhancer.setCallbackFilter(new ProxyCallbackFilter(
                this.advised.getConfigurationOnlyCopy(), this.fixedInterceptorMap, this.fixedInterceptorOffset));
        enhancer.setCallbackTypes(types);
        enhancer.setCallbacks(callbacks);

        // 生成代理類及創建代理對象
        Object proxy;
        if (this.constructorArgs != null) {
            proxy = enhancer.create(this.constructorArgTypes, this.constructorArgs);
        }
        else {
            proxy = enhancer.create();
        }

        return proxy;
    }
    catch (CodeGenerationException ex) {
        catch若干異常。。。
    }
}

  上面的函數中就是一個完整創建Enhancer的過程,詳細可以參考Enhancer的文檔,這裏最重要的是通過getCallbacks()方法設置攔截器鏈。

private Callback[] getCallbacks(Class<?> rootClass) throws Exception {
    // 對於expose-proxy屬性的處理
    boolean exposeProxy = this.advised.isExposeProxy();
    boolean isFrozen = this.advised.isFrozen();
    boolean isStatic = this.advised.getTargetSource().isStatic();

    // 將攔截器封裝在DynamicAdvisedInterceptor中
    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());
    }

    // 將攔截器加入到callback中
    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 optimisations 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<String, Integer>(methods.length);

        // TODO: small memory optimisation 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屬性封裝在DynamicAdvisedInterceptor並加入在callbacks中,這麼做的目的是什麼呢?在CGLIB中對於方法的攔截是通過將自定義的攔截器(實現了MethodInterceptor接口的類)加入Callback中並在調用代理時直接激活攔截器中的intercept()方法來實現的,而在getCallback()方法中正好有這一部分功能的實現,DynamicAdvisedInterceptor繼承自MethodInterceptor,加入Callback中后,在再次調用代理時會直接調用其intercept()方法,由此推斷,對於CGLIB方式實現的代理,其核心邏輯應該是在DynamicAdvisedInterceptor中的intercept()方法中的:

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;
        if (chain.isEmpty() && Modifier.isPublic(method.getModifiers())) {
            // 如果攔截器鏈為空則直接激活原方法
            retVal = methodProxy.invoke(target, args);
        }
        else {
            // 鏈式調用
            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);
        }
    }
}

  這裏的實現與JDK動態代理方式實現代理中的invoke方法大同小異,都是首先構造攔截器鏈,然後封裝此鏈進行串聯調用,不同的是在JDK動態代理的方式中是直接構造ReflectiveMethodInvocation,而在cglib中則是使用CglibMethodInvocation,其是繼承自ReflectiveMethodInvocation,但是proceed()方法並沒有重寫。

 

3. 總結

  本文着重分析了Spring AOP實現原理中代理對象的創建過程,在bean的初始化過程中會執行Spring的後置處理器,這裡會去判斷這個bean是否需要增強,如果需要則會根據Aspect中定義的增強信息,對指定bean進行增強,也就是創建一個代理對象。對代理對象的創建有兩種方式,一種是通過JDK動態代理的方式,另一種是通過cglib的方式。

 

本站聲明:網站內容來源於博客園,如有侵權,請聯繫我們,我們將及時處理

【其他文章推薦】

※自行創業缺乏曝光? 網頁設計幫您第一時間規劃公司的形象門面

網頁設計一頭霧水該從何著手呢? 台北網頁設計公司幫您輕鬆架站!

※想知道最厲害的網頁設計公司"嚨底家"!

※幫你省時又省力,新北清潔一流服務好口碑

※別再煩惱如何寫文案,掌握八大原則!

※產品缺大量曝光嗎?你需要的是一流包裝設計!

您可能也會喜歡…