Spring Aop之Jdk代理實現原理詳解

       Jdk代理,也稱爲動態代理,其代理目標對象的方式是生成一個與目標對象實現同一個接口的類,該類的構造函數中會傳入一個InvocationHandler類型的對象。由於InvocationHandler對象是用戶自定義的織入了切面邏輯的類,於是在須要使用目標對象的地方,只須要將生成的代理類的對象傳入便可。又由於生成的代理類與目標類都實現了同一接口,於是從語法上其是沒有任何問題的。另外一方面,在傳入代理類對象以後,代理類經過調用構造函數傳入的InvocationHandler.invoke()方法,從而動態的調用目標類的方法,最終利用這種方式織入了代理邏輯。java

       在講解Spring Aop如何實現動態代理以前,建議讀者先去閱讀本人上一篇文章Spring Aop之Cglib實現原理詳解,由於Cglib代理和Jdk代理織入切面邏輯的方式是相似的,只是生成代理類的方式不同,而且本文中部分方法的實現原理在上一篇文章中已經進行了詳細的講解,這裏就再也不贅述。函數

1. 代理對象的構造

       前面咱們講到,Spring Aop使用AopProxy.getProxy()方法獲取代理對象的,而JdkDynamicAopProxy則已經實現了該接口,於是咱們能夠直接閱讀其getProxy()方法的源碼:this

public Object getProxy(@Nullable ClassLoader classLoader) {
    if (logger.isDebugEnabled()) {
        logger.debug("Creating JDK dynamic proxy: target source is " 
            + this.advised.getTargetSource());
    }
    // 完善代理對象須要實現的接口,主要是會默認增長三個須要實現的接口:SpringProxy,
    // Advised和DecoratingProxy。這三個接口的做用主要以下:
    // SpringProxy:該接口沒有任何方法,主要用於標識當前對象是Spring生成的代理對象;
    // Advised:用於封裝生成代理對象所須要的全部信息;
    // DecoratingProxy:其有一個getDecoratedClass()方法,用於返回當前代理對象的目標對象的Class類型
    Class<?>[] proxiedInterfaces = AopProxyUtils
        .completeProxiedInterfaces(this.advised, true);
    // 找到接口中是否包含有equals()和hashCode()方法,並進行標識
    findDefinedEqualsAndHashCodeMethods(proxiedInterfaces);
    // 使用動態代理生成代理對象
    return Proxy.newProxyInstance(classLoader, proxiedInterfaces, this);
}

       上述方法邏輯其實比較簡單,主要就是首先獲取生成代理對象所須要實現的全部接口;而後判斷接口中是否包含有equals()和hashCode()方法,由於這將用於判斷生成的代理類是使用用於定義的equals()和hashCode()方法仍是使用自動生成的方法;最後就是經過動態代理生成代理對象,這裏須要注意的是JdkDynamicAopProxy不只實現了AopProxy接口還實現了InvocationHandler接口,於是這裏生成代理對象的時候傳入的InvocationHandler對象是this。.net

2. 切面邏輯的織入

       因爲JdkDynamicAopProxy已經實現了InvocationHandler接口,於是代理邏輯的織入就是在JdkDynamicAopProxy.invoke()方法中,這裏咱們直接閱讀器源碼:debug

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)) {
            // 若是當前方法是equals()方法,而且接口中並未定義該方法,就使用自動生成的equals()方法
            return equals(args[0]);
        } else if (!this.hashCodeDefined && AopUtils.isHashCodeMethod(method)) {
            // 若是當前方法是hashCode()方法,而且接口中並未定義該方法,就使用自動生成的hashCode()方法
            return hashCode();
        } else if (method.getDeclaringClass() == DecoratingProxy.class) {
            // 若是當前方法是Spring織入的DecoratingProxy接口中的方法,則返回目標對象的Class類型
            return AopProxyUtils.ultimateTargetClass(this.advised);
        } else if (!this.advised.opaque && method.getDeclaringClass().isInterface() &&
                 method.getDeclaringClass().isAssignableFrom(Advised.class)) {
            // 若是當前方法是Spring織入的Advised接口中的方法,
            // 則使用反射調用當前advised對象中的相關方法
            return AopUtils.invokeJoinpointUsingReflection(this.advised, method, args);
        }

        Object retVal;
        if (this.advised.exposeProxy) {
            // 若是設置了須要暴露代理對象,則將當前對象設置到AopContext中
            oldProxy = AopContext.setCurrentProxy(proxy);
            setProxyContext = true;
        }

        target = targetSource.getTarget();
        Class<?> targetClass = (target != null ? target.getClass() : null);

        // 獲取當前方法須要織入的切面邏輯的調用鏈
        List<Object> chain = this.advised
            .getInterceptorsAndDynamicInterceptionAdvice(method, targetClass);

        if (chain.isEmpty()) {
            // 若是切面邏輯的調用鏈爲空,則對方法參數進行類型轉換處理,
            // 而且經過反射直接調用目標對象的方法
            Object[] argsToUse = AopProxyUtils.adaptArgumentsIfNecessary(method, args);
            retVal = AopUtils.invokeJoinpointUsingReflection(target, method, argsToUse);
        } else {
            // 獲取目標對象的調用鏈邏輯,而且對該鏈進行調用
            invocation = new ReflectiveMethodInvocation(proxy,
                target, method, args, targetClass, chain);
            retVal = invocation.proceed();
        }

        Class<?> returnType = method.getReturnType();
        if (retVal != null && retVal == target &&
            returnType != Object.class && returnType.isInstance(proxy) &&
            !RawTargetAccess.class.isAssignableFrom(method.getDeclaringClass())) {
            // 判斷返回值若是爲目標對象,而且當前方法的返回值類型是當前代理對象的類型,那麼就將
            // 當前代理對象返回。這裏的邏輯的實際意思簡單的說就是,若是返回值是目標對象,那麼
            // 就將當前代理對象返回
            retVal = proxy;
        } else if (retVal == null && returnType != Void.TYPE 
                   && returnType.isPrimitive()) {
            // 若是返回值知足其爲空,不是Void類型,而且是基本數據類型,那麼就拋出異常,
            // 由於基本數據類型的返回值必然不爲空
            throw new AopInvocationException("Null return value from advice does not " 
                + " match primitive return type for: " + method);
        }
        return retVal;
    } finally {
        if (target != null && !targetSource.isStatic()) {
            // 若是TargetSource不是靜態的,則調用其releaseTarget()方法將生成的目標對象釋放
            targetSource.releaseTarget(target);
        }
        if (setProxyContext) {
            // 處理AopContext中保存的當前代理對象
            AopContext.setCurrentProxy(oldProxy);
        }
    }
}

       能夠看到,在進行代理邏輯的織入的時候,首先會進行以下判斷:①當前方法是否爲equals()或hashCode()方法,若是是,而且接口中並未要求子類實現這些方法,那麼就會調用自動生成的方法;②當前方法是否爲Spring織入的DecoratingProxy接口中的方法,若是是,則將目標對象的Class類型返回;③判斷目標方法是否爲Spring織入的Advised中的方法,若是是,則調用當前advised對象中相應的方法。而後就會獲取當前方法須要織入的代理邏輯的調用鏈。接着就會將目標對象和調用鏈邏輯封裝爲ReflectiveMethodInvocation,並進行調用。最後對調用的返回值進行一些基本判斷,而且返回。代理

3. 小結

       本文首先對Jdk代理進行了簡單的介紹,而後介紹了Spring Aop是如何調用將Jdk代理的Proxy引入而且生成代理對象的,最後對調用鏈的生成,以及切面邏輯的織入方式進行了講解。關於調用鏈的生成以及切面邏輯的織入,因爲使用的方式和Cglib是同樣的,於是這裏並無對其細節進行過多描述。code

相關文章
相關標籤/搜索