Cglib 與 JDK動態代理

AOP 代理的兩種實現:

  • jdk是代理接口,私有方法必然不會存在在接口裏,所以就不會被攔截到;
  • cglib是子類,private的方法照樣不會出現在子類裏,也不能被攔截。

JDK 動態代理。

具體有如下四步驟:

  1. 通過實現 InvocationHandler 接口創建自己的調用處理器;
  2. 通過爲 Proxy 類指定 ClassLoader 對象和一組 interface 來創建動態代理類;
  3. 通過反射機制獲得動態代理類的構造函數,其唯一參數類型是調用處理器接口類型;
  4. 通過構造函數創建動態代理類實例,構造時調用處理器對象作爲參數被傳入。

示例

創建業務接口

public interface UserService {
    /**
     * 需要增強的方法
     */
    void add();
}

創建業務接口 實現類

public class UserServiceImpl implements UserService {
    @Override
    public void add() {
        System.out.println("-------------業務邏輯方法 add ------------");
    }
}

創建自定義的 InvocationHandler,用於對接口提供的方法進行增強

public class MyInvocationHandler implements InvocationHandler {
    /**
     * 需要增強的對象
     */
    private Object target;

    public MyInvocationHandler(Object target) {
        this.target = target;
    }

    /**
     * 執行目標對象
     */
    @Override
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
        System.out.println("-------------方法執行前的增強邏輯 ------------");
        Object result = method.invoke(target, args);
        System.out.println("-------------方法執行後的增強邏輯 ------------");
        return result;
    }

    public Object getProxy() {
        return Proxy.newProxyInstance(Thread.currentThread().getContextClassLoader(), target.getClass().getInterfaces(), this);
    }
}

測試類

public class ProxyTest {
    @Test
    public void contextTest() {
        // 實例化目標對象
        UserService userService = new UserServiceImpl();
        // 實例化 InvocationHandler
        MyInvocationHandler invocationHandler = new MyInvocationHandler(userService);
        // 生成代理對象
        UserService proxy = (UserService) invocationHandler.getProxy();
        // 輸出代理類的class
        ProxySourceClassUtil.writeClassToDisk("C:\\Users\\yuhao.wang3\\Desktop\\" + proxy.getClass().getSimpleName() + ".class", proxy.getClass().getSimpleName(), UserService.class);
        // 調用代理對象的方法
        proxy.add();
    }
}

輸出結果:

Connected to the target VM, address: '127.0.0.1:60738', transport: 'socket'
-------------方法執行前的增強邏輯 ------------
-------------業務邏輯方法 add ------------
-------------方法執行後的增強邏輯 ------------
Disconnected from the target VM, address: '127.0.0.1:60738', transport: 'socket'

用起來很簡單,其實’這基本上就 AOP 的一個簡單實現了,在目標對象的方法執行之前和
執行之後進行了增強。 Spring的AOP實現其實也是用了 Proxy 和 InvocationHandler。在整個創建過程中InvocationHandler的創建最爲核心,在自定義的InvocationHandler中需要重新3個函數:

  1. 構造函數,將代理的對象傳入。
  2. invoke方法,此方法中實現了AOP增強的所有邏輯。
  3. getProxy方法,此方千篇一律,但是必不可少。

反編譯代理類結果

package com.xiaolyuh.aop.jdk;

import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
import java.lang.reflect.UndeclaredThrowableException;

// 代理類會去實現我們的接口
public final class Proxy4 extends Proxy implements UserService {
    // 解析所有的方法
    private static Method m1;
    private static Method m2;
    private static Method m3;
    private static Method m0;

    public Proxy4() throws {
        super(paramInvocationHandler);
    }

    public final boolean equals() throws {
        try {
            return ((Boolean) this.h.invoke(this, m1, new Object[]{paramObject})).booleanValue();
        } catch (RuntimeException localRuntimeException) {
            throw localRuntimeException;
        } catch (Throwable localThrowable) {
            throw new UndeclaredThrowableException(localThrowable);
        }
    }

    public final String toString() throws {
        try {
            return ((String) this.h.invoke(this, m2, null));
        } catch (RuntimeException localRuntimeException) {
            throw localRuntimeException;
        } catch (Throwable localThrowable) {
            throw new UndeclaredThrowableException(localThrowable);
        }
    }

    public final void add() throws {
        try {
            // 通過InvocationHandler的invoke方法去執行增強和原有方法邏輯
            this.h.invoke(this, m3, null);
            return;
        } catch (RuntimeException localRuntimeException) {
            throw localRuntimeException;
        } catch (Throwable localThrowable) {
            throw new UndeclaredThrowableException(localThrowable);
        }
    }

    public final int hashCode() throws {
        try {
            return ((Integer) this.h.invoke(this, m0, null)).intValue();
        } catch (RuntimeException localRuntimeException) {
            throw localRuntimeException;
        } catch (Throwable localThrowable) {
            throw new UndeclaredThrowableException(localThrowable);
        }
    }

    static {
        try {
            // 解析所有的method出來
            m1 = Class.forName("java.lang.Object").getMethod("equals", new Class[]{Class.forName("java.lang.Object")});
            m2 = Class.forName("java.lang.Object").getMethod("toString", new Class[0]);
            m3 = Class.forName("com.xiaolyuh.aop.jdk.UserService").getMethod("add", new Class[0]);
            m0 = Class.forName("java.lang.Object").getMethod("hashCode", new Class[0]);
            return;
        } catch (NoSuchMethodException localNoSuchMethodException) {
            throw new NoSuchMethodError(localNoSuchMethodException.getMessage());
        } catch (ClassNotFoundException localClassNotFoundException) {
            throw new NoClassDefFoundError(localClassNotFoundException.getMessage());
        }
    }
}

從結果我們可以看出,代理類會實現我們的接口,並會實現我們接口中的方法。然後通過InvocationHandler的invoke方法去執行增強邏輯和原有方法邏輯。在invoke中我們可以使用反射去執行原有邏輯,並在方法執行前後加上自己的增強邏輯。

JdkDynamicAopProxy

JdkDynamicAopProxy是Spring中JDK動態代理的實現,它也實現了InvocationHandler接口。核心方法:

  1. getProxy:獲取代理對象,這個和上面的示例幾乎是一樣的
  2. invoke:實現了AOP的核心邏輯

源碼:

final class JdkDynamicAopProxy implements AopProxy, InvocationHandler, Serializable {

	...

	/** Config used to configure this proxy(對增強器的支持) */
	private final AdvisedSupport advised;

	...


	public JdkDynamicAopProxy(AdvisedSupport config) throws AopConfigException {
		Assert.notNull(config, "AdvisedSupport must not be null");
		if (config.getAdvisors().length == 0 && config.getTargetSource() == AdvisedSupport.EMPTY_TARGET_SOURCE) {
			throw new AopConfigException("No advisors and no TargetSource specified");
		}
		this.advised = config;
	}


	@Override
	public Object getProxy() {
		return getProxy(ClassUtils.getDefaultClassLoader());
	}

	@Override
	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, true);
		findDefinedEqualsAndHashCodeMethods(proxiedInterfaces);
		// 返回代理對象
		return Proxy.newProxyInstance(classLoader, proxiedInterfaces, this);
	}

	...

	/**
	 * Implementation of {@code InvocationHandler.invoke}.
	 * <p>Callers will see exactly the exception thrown by the target,
	 * unless a hook method throws an exception.
	 */
	@Override
	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)) {
				// The target does not implement the equals(Object) method itself.
				return equals(args[0]);
			}
			// hashCode 方法處理
			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;
			}

			// May be null. Get as late as possible to minimize the time we "own" the target,
			// in case it comes from a pool.
			target = targetSource.getTarget();
			if (target != null) {
				targetClass = target.getClass();
			}

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

			if (chain.isEmpty()) {
				// 如果沒有攔截鏈那麼直接調用切點方法
				Object[] argsToUse = AopProxyUtils.adaptArgumentsIfNecessary(method, args);
				retVal = AopUtils.invokeJoinpointUsingReflection(target, method, argsToUse);
			}
			else {
				// 將攔截器封裝在ReflectiveMethodInvocation中,以便使用proceed方法執行攔截鏈
				invocation = new ReflectiveMethodInvocation(proxy, target, method, args, targetClass, 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);
			}
		}
	}
	...
}

GCLIB代理

cglib(Code Generation Library)是一個強大的,高性能,高質量的Code生成類庫。它可以在運行期擴展Java類與實現Java接口。

  • cglib封裝了asm,可以在運行期動態生成新的class(子類)。
  • cglib用於AOP,jdk中的proxy必須基於接口,cglib卻沒有這個限制。

示例

需要代理的類

public class EnhancerDemo {

    public void test() {
        System.out.println("-------------業務邏輯方法 test ------------");
    }
}

MethodInterceptor的實現類(增強器)

import org.springframework.cglib.proxy.MethodInterceptor;
import org.springframework.cglib.proxy.MethodProxy;

import java.lang.reflect.Method;

public class MethodInterceptorImpl implements MethodInterceptor {

    @Override
    public Object intercept(Object object, Method method, Object[] args, MethodProxy methodProxy) throws Throwable {
        System.out.println("-------------方法執行前的增強邏輯 ------------" + method);
        Object result = methodProxy.invokeSuper(object, args);
        System.out.println("-------------方法執行後的增強邏輯 ------------" + method);
        return result;
    }
}

測試類:

public class EnhancerTest {

    @Test
    public void contextTest() {

        System.setProperty(DebuggingClassWriter.DEBUG_LOCATION_PROPERTY, "D:\\class");
        Enhancer enhancer = new Enhancer();
        enhancer.setSuperclass(EnhancerDemo.class);
        enhancer.setCallback(new MethodInterceptorImpl());

        EnhancerDemo proxy = (EnhancerDemo) enhancer.create();

        proxy.test();
        System.out.println(proxy);
    }
}

執行結果

Connected to the target VM, address: '127.0.0.1:61217', transport: 'socket'
-------------方法執行前的增強邏輯 ------------public void com.xiaolyuh.aop.cglib.EnhancerDemo.test()
-------------業務邏輯方法 test ------------
-------------方法執行後的增強邏輯 ------------public void com.xiaolyuh.aop.cglib.EnhancerDemo.test()
-------------方法執行前的增強邏輯 ------------public java.lang.String java.lang.Object.toString()
-------------方法執行前的增強邏輯 ------------public native int java.lang.Object.hashCode()
-------------方法執行後的增強邏輯 ------------public native int java.lang.Object.hashCode()
-------------方法執行後的增強邏輯 ------------public java.lang.String java.lang.Object.toString()
com.xiaolyuh.aop.cglib.EnhancerDemo$$EnhancerByCGLIB$$da6c48f9@7a187f14
Disconnected from the target VM, address: '127.0.0.1:61217', transport: 'socket'

可以看到 System.out.println(porxy); 首先調用了 toString() 方法,然後又調用了 hashCode() ,生成的對象爲 EnhancerDemo$$EnhancerByCGLIB$$da6c48f9@7a187f14的實例,這個類是運行時由 CGLIB 產生。

反編譯代理結果

在測試類的第一行加上下面語句,那麼在cglib中生成的class文件將會持久化到硬盤。https://www.cnblogs.com/cruze/p/3847968.html

// 該設置用於輸出cglib動態代理產生的類
System.setProperty(DebuggingClassWriter.DEBUG_LOCATION_PROPERTY, "D:\\class");  
// 該設置用於輸出jdk動態代理產生的類
System.getProperties().put("sun.misc.ProxyGenerator.saveGeneratedFiles", "true");   

反編譯結果:

package com.xiaolyuh.aop.cglib;

import java.lang.reflect.Method;
import org.springframework.cglib.core.ReflectUtils;
import org.springframework.cglib.core.Signature;
import org.springframework.cglib.proxy.Callback;
import org.springframework.cglib.proxy.Factory;
import org.springframework.cglib.proxy.MethodInterceptor;
import org.springframework.cglib.proxy.MethodProxy;

public class EnhancerDemo$$EnhancerByCGLIB$$da6c48f9 extends EnhancerDemo implements Factory {
    private boolean CGLIB$BOUND;
    public static Object CGLIB$FACTORY_DATA;
    private static final ThreadLocal CGLIB$THREAD_CALLBACKS;
    private static final Callback[] CGLIB$STATIC_CALLBACKS;
    private MethodInterceptor CGLIB$CALLBACK_0;
    private static Object CGLIB$CALLBACK_FILTER;
    private static final Method CGLIB$test$0$Method;
    private static final MethodProxy CGLIB$test$0$Proxy;
    private static final Object[] CGLIB$emptyArgs;
    private static final Method CGLIB$equals$1$Method;
    private static final MethodProxy CGLIB$equals$1$Proxy;
    private static final Method CGLIB$toString$2$Method;
    private static final MethodProxy CGLIB$toString$2$Proxy;
    private static final Method CGLIB$hashCode$3$Method;
    private static final MethodProxy CGLIB$hashCode$3$Proxy;
    private static final Method CGLIB$clone$4$Method;
    private static final MethodProxy CGLIB$clone$4$Proxy;

    static void CGLIB$STATICHOOK1() {
        CGLIB$THREAD_CALLBACKS = new ThreadLocal();
        CGLIB$emptyArgs = new Object[0];
        Class var0 = Class.forName("com.xiaolyuh.aop.cglib.EnhancerDemo$$EnhancerByCGLIB$$da6c48f9");
        Class var1;
        Method[] var10000 = ReflectUtils.findMethods(new String[]{"equals", "(Ljava/lang/Object;)Z", "toString", "()Ljava/lang/String;", "hashCode", "()I", "clone", "()Ljava/lang/Object;"}, (var1 = Class.forName("java.lang.Object")).getDeclaredMethods());
        CGLIB$equals$1$Method = var10000[0];
        CGLIB$equals$1$Proxy = MethodProxy.create(var1, var0, "(Ljava/lang/Object;)Z", "equals", "CGLIB$equals$1");
        CGLIB$toString$2$Method = var10000[1];
        CGLIB$toString$2$Proxy = MethodProxy.create(var1, var0, "()Ljava/lang/String;", "toString", "CGLIB$toString$2");
        CGLIB$hashCode$3$Method = var10000[2];
        CGLIB$hashCode$3$Proxy = MethodProxy.create(var1, var0, "()I", "hashCode", "CGLIB$hashCode$3");
        CGLIB$clone$4$Method = var10000[3];
        CGLIB$clone$4$Proxy = MethodProxy.create(var1, var0, "()Ljava/lang/Object;", "clone", "CGLIB$clone$4");
        CGLIB$test$0$Method = ReflectUtils.findMethods(new String[]{"test", "()Ljava/lang/String;"}, (var1 = Class.forName("com.xiaolyuh.aop.cglib.EnhancerDemo")).getDeclaredMethods())[0];
        CGLIB$test$0$Proxy = MethodProxy.create(var1, var0, "()Ljava/lang/String;", "test", "CGLIB$test$0");
    }

    final String CGLIB$test$0() {
        return super.test();
    }

    public final String test() {
        MethodInterceptor var10000 = this.CGLIB$CALLBACK_0;
        if (var10000 == null) {
            CGLIB$BIND_CALLBACKS(this);
            var10000 = this.CGLIB$CALLBACK_0;
        }

        return var10000 != null ? (String)var10000.intercept(this, CGLIB$test$0$Method, CGLIB$emptyArgs, CGLIB$test$0$Proxy) : super.test();
    }

    final boolean CGLIB$equals$1(Object var1) {
        return super.equals(var1);
    }

    public final boolean equals(Object var1) {
        MethodInterceptor var10000 = this.CGLIB$CALLBACK_0;
        if (var10000 == null) {
            CGLIB$BIND_CALLBACKS(this);
            var10000 = this.CGLIB$CALLBACK_0;
        }

        if (var10000 != null) {
            Object var2 = var10000.intercept(this, CGLIB$equals$1$Method, new Object[]{var1}, CGLIB$equals$1$Proxy);
            return var2 == null ? false : (Boolean)var2;
        } else {
            return super.equals(var1);
        }
    }

    final String CGLIB$toString$2() {
        return super.toString();
    }

    public final String toString() {
        MethodInterceptor var10000 = this.CGLIB$CALLBACK_0;
        if (var10000 == null) {
            CGLIB$BIND_CALLBACKS(this);
            var10000 = this.CGLIB$CALLBACK_0;
        }

        return var10000 != null ? (String)var10000.intercept(this, CGLIB$toString$2$Method, CGLIB$emptyArgs, CGLIB$toString$2$Proxy) : super.toString();
    }

    final int CGLIB$hashCode$3() {
        return super.hashCode();
    }

    public final int hashCode() {
        MethodInterceptor var10000 = this.CGLIB$CALLBACK_0;
        if (var10000 == null) {
            CGLIB$BIND_CALLBACKS(this);
            var10000 = this.CGLIB$CALLBACK_0;
        }

        if (var10000 != null) {
            Object var1 = var10000.intercept(this, CGLIB$hashCode$3$Method, CGLIB$emptyArgs, CGLIB$hashCode$3$Proxy);
            return var1 == null ? 0 : ((Number)var1).intValue();
        } else {
            return super.hashCode();
        }
    }

    final Object CGLIB$clone$4() throws CloneNotSupportedException {
        return super.clone();
    }

    protected final Object clone() throws CloneNotSupportedException {
        MethodInterceptor var10000 = this.CGLIB$CALLBACK_0;
        if (var10000 == null) {
            CGLIB$BIND_CALLBACKS(this);
            var10000 = this.CGLIB$CALLBACK_0;
        }

        return var10000 != null ? var10000.intercept(this, CGLIB$clone$4$Method, CGLIB$emptyArgs, CGLIB$clone$4$Proxy) : super.clone();
    }

    public static MethodProxy CGLIB$findMethodProxy(Signature var0) {
        String var10000 = var0.toString();
        switch(var10000.hashCode()) {
        case -508378822:
            if (var10000.equals("clone()Ljava/lang/Object;")) {
                return CGLIB$clone$4$Proxy;
            }
            break;
        case 225925469:
            if (var10000.equals("test()Ljava/lang/String;")) {
                return CGLIB$test$0$Proxy;
            }
            break;
        case 1826985398:
            if (var10000.equals("equals(Ljava/lang/Object;)Z")) {
                return CGLIB$equals$1$Proxy;
            }
            break;
        case 1913648695:
            if (var10000.equals("toString()Ljava/lang/String;")) {
                return CGLIB$toString$2$Proxy;
            }
            break;
        case 1984935277:
            if (var10000.equals("hashCode()I")) {
                return CGLIB$hashCode$3$Proxy;
            }
        }

        return null;
    }

    public EnhancerDemo$$EnhancerByCGLIB$$da6c48f9() {
        CGLIB$BIND_CALLBACKS(this);
    }

    public static void CGLIB$SET_THREAD_CALLBACKS(Callback[] var0) {
        CGLIB$THREAD_CALLBACKS.set(var0);
    }

    public static void CGLIB$SET_STATIC_CALLBACKS(Callback[] var0) {
        CGLIB$STATIC_CALLBACKS = var0;
    }

    private static final void CGLIB$BIND_CALLBACKS(Object var0) {
        EnhancerDemo$$EnhancerByCGLIB$$da6c48f9 var1 = (EnhancerDemo$$EnhancerByCGLIB$$da6c48f9)var0;
        if (!var1.CGLIB$BOUND) {
            var1.CGLIB$BOUND = true;
            Object var10000 = CGLIB$THREAD_CALLBACKS.get();
            if (var10000 == null) {
                var10000 = CGLIB$STATIC_CALLBACKS;
                if (var10000 == null) {
                    return;
                }
            }

            var1.CGLIB$CALLBACK_0 = (MethodInterceptor)((Callback[])var10000)[0];
        }

    }

    public Object newInstance(Callback[] var1) {
        CGLIB$SET_THREAD_CALLBACKS(var1);
        EnhancerDemo$$EnhancerByCGLIB$$da6c48f9 var10000 = new EnhancerDemo$$EnhancerByCGLIB$$da6c48f9();
        CGLIB$SET_THREAD_CALLBACKS((Callback[])null);
        return var10000;
    }

    public Object newInstance(Callback var1) {
        CGLIB$SET_THREAD_CALLBACKS(new Callback[]{var1});
        EnhancerDemo$$EnhancerByCGLIB$$da6c48f9 var10000 = new EnhancerDemo$$EnhancerByCGLIB$$da6c48f9();
        CGLIB$SET_THREAD_CALLBACKS((Callback[])null);
        return var10000;
    }

    public Object newInstance(Class[] var1, Object[] var2, Callback[] var3) {
        CGLIB$SET_THREAD_CALLBACKS(var3);
        EnhancerDemo$$EnhancerByCGLIB$$da6c48f9 var10000 = new EnhancerDemo$$EnhancerByCGLIB$$da6c48f9;
        switch(var1.length) {
        case 0:
            var10000.<init>();
            CGLIB$SET_THREAD_CALLBACKS((Callback[])null);
            return var10000;
        default:
            throw new IllegalArgumentException("Constructor not found");
        }
    }

    public Callback getCallback(int var1) {
        CGLIB$BIND_CALLBACKS(this);
        MethodInterceptor var10000;
        switch(var1) {
        case 0:
            var10000 = this.CGLIB$CALLBACK_0;
            break;
        default:
            var10000 = null;
        }

        return var10000;
    }

    public void setCallback(int var1, Callback var2) {
        switch(var1) {
        case 0:
            this.CGLIB$CALLBACK_0 = (MethodInterceptor)var2;
        default:
        }
    }

    public Callback[] getCallbacks() {
        CGLIB$BIND_CALLBACKS(this);
        return new Callback[]{this.CGLIB$CALLBACK_0};
    }

    public void setCallbacks(Callback[] var1) {
        this.CGLIB$CALLBACK_0 = (MethodInterceptor)var1[0];
    }

    static {
        CGLIB$STATICHOOK1();
    }
}

從結果上我們可以看出Cglib是使用繼承的方式實現的動態代理。關鍵代碼:

public final String test() {
	MethodInterceptor var10000 = this.CGLIB$CALLBACK_0;
	if (var10000 == null) {
		CGLIB$BIND_CALLBACKS(this);
		var10000 = this.CGLIB$CALLBACK_0;
	}

	return var10000 != null ? (String)var10000.intercept(this, CGLIB$test$0$Method, CGLIB$emptyArgs, CGLIB$test$0$Proxy) : super.test();
}

從上面的代碼我們可以發現方法的執行會委託給MethodInterceptor的intercept方法。從而實現對方法的增強。

由於 Cglib 是使用繼承方式,所有final類是不能使用cglib代理的,會直接拋出異常,final方法也將不會被代理,因爲不能覆蓋,不會直接拋出異常。

CglibAopProxy

CglibAopProxy是Spring中Cglib動態代理的實現,在getProxy方法中完成了對Enhancer的創建和封裝。在getProxy方法中getCallbacks(rootClass);方法會將攔截鏈封裝成DynamicAdvisedInterceptor對象,並放到Cglib的回調函數中。源碼如下:

@Override
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, classLoader);

		// 創建以及配置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);

		// 生成代理類並創建代理實例
		return createProxyClassAndInstance(enhancer, callbacks);
	}
	...
}


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).
	// 將攔截鏈封裝到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());
	}

	// 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[] {
			// 將攔截鏈加入到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<String, Integer>(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;
}

原理區別:

java動態代理是利用反射機制生成一個實現代理接口的匿名類,在調用具體方法前調用InvokeHandler來處理。而cglib動態代理是利用asm開源包,對代理對象類的class文件加載進來,通過修改其字節碼生成子類來處理。

  1. 如果目標對象實現了接口,默認情況下會採用JDK的動態代理實現AOP
  2. 如果目標對象實現了接口,可以強制使用CGLIB實現AOP
  3. 如果目標對象沒有實現了接口,必須採用CGLIB庫,spring會自動在JDK動態代理和CGLIB之間轉換

Cglib 與 JDK動態代理的運行性能比較

結論:從 jdk6 到 jdk7、jdk8 ,動態代理的性能得到了顯著的提升,尤其是JDK7和JDK8性能表現都比cglib好,而 cglib 的表現並未跟上,甚至可能會略微下降。所以建議儘量使用 JDK 的動態代理。

源碼

https://github.com/wyh-spring-ecosystem-student/spring-boot-student/tree/releases

spring-boot-student-spring 工程

發佈了204 篇原創文章 · 獲贊 153 · 訪問量 86萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章