Spring5源碼之CglibAopProxy

這篇文章主要介紹了Spring5源碼之CglibAopProxy,通過Cglib代理使用示例來一步步剖析源碼。需要的朋友可以參考一下。

1、Cglib使用示例

Cglib是一個強大的高性能的代碼生成包。Cglib包的底層通過使用一個小而快的字節碼處理框架ASM,來轉換字節碼並生成新的類。除了Cglib包,腳本語言例如Groovy和BeanShell,也是使用ASM來生成Java字節碼。當然不鼓勵直接使用ASM,因爲它要求你必須對JVM內部(包括class文件的格式和指令集)都很熟悉。

  • 目標類MyEnhancer
package com.test.spring5code.cglib.enhancer;

import lombok.extern.slf4j.Slf4j;

/**
 * @Description: my Enhancer
 * @Author: Janson
 * @Date: 2020/5/1 22:50
 **/
@Slf4j
public class MyEnhancer {

    public void testCglib(){
        log.info("MyEnhancer testCglib");
    }
}
  • Cglib動態代理類MyMethodInterceptor
package com.test.spring5code.cglib.method;


import lombok.extern.slf4j.Slf4j;
import org.springframework.cglib.proxy.Enhancer;
import org.springframework.cglib.proxy.MethodInterceptor;
import org.springframework.cglib.proxy.MethodProxy;

import java.lang.reflect.Method;

/**
 * @Description: my MethodInterceptor
 * @Author: Janson
 * @Date: 2020/5/1 22:41
 **/
@Slf4j
public class MyMethodInterceptor implements MethodInterceptor {

    private static volatile MyMethodInterceptor instance;

    private MyMethodInterceptor() {
        // do nothing
    }

    public static MyMethodInterceptor getInstance() {
        if (instance == null) {
            synchronized (MyMethodInterceptor.class) {
                if (instance == null) {
                    instance = new MyMethodInterceptor();
                }
            }
        }
        return instance;
    }

    @Override
   public Object intercept(Object o, Method method, Object[] objects, MethodProxy methodProxy) throws Throwable {
       log.info("before invoke method:{}", method);
       Object result = methodProxy.invokeSuper(o, objects);
       log.info("after invoke method:{}", method);
       return result;
   }

   private Enhancer enhancer = new Enhancer();

   public <T> T getProxy(Class<T> clazz) {
       enhancer.setSuperclass(clazz);
       enhancer.setCallback(this);
       return (T) enhancer.create();
   }
}

  • Cglib測試類CglibPrxoyTest
package com.test.spring5code;

import com.test.spring5code.cglib.enhancer.MyEnhancer;
import com.test.spring5code.cglib.method.MyMethodInterceptor;
import lombok.extern.slf4j.Slf4j;
import org.junit.jupiter.api.Test;

/**
 * @Description: cglib proxy test
 * @Author: Janson
 * @Date: 2020/5/1 23:07
 **/
@Slf4j
public class CglibPrxoyTest {

    @Test
    public void testCglibProxy() {
        MyEnhancer proxy = MyMethodInterceptor.getInstance().getProxy(MyEnhancer.class);
        proxy.testCglib();
        log.info("MyEnhancer:{}", proxy);
    }
}
  • Cglib測試類CglibPrxoyTest輸出結果
23:17:04.708 [main] INFO com.test.spring5code.cglib.method.MyMethodInterceptor - before invoke method:public void com.test.spring5code.cglib.enhancer.MyEnhancer.testCglib()
23:17:04.719 [main] INFO com.test.spring5code.cglib.enhancer.MyEnhancer - MyEnhancer testCglib
23:17:04.719 [main] INFO com.test.spring5code.cglib.method.MyMethodInterceptor - after invoke method:public void com.test.spring5code.cglib.enhancer.MyEnhancer.testCglib()
23:17:04.719 [main] INFO com.test.spring5code.CglibPrxoyTest - MyEnhancer:com.test.spring5code.cglib.enhancer.MyEnhancer$$EnhancerByCGLIB$$c6f3e22@6ab7a896

從 log.info(“MyEnhancer:{}”, proxy)輸出結果來看,首先調用了toString方法,然後又調用了hashCode方法,生成對象的爲MyEnhancer$$EnhancerByCGLIB$$c6f3e22@6ab7a896,這個類是運行時由Cglib產生的。完成Cglib代理的類是委託給CglibAopProxy類去實現的。

2、CglibAopProxy

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

		// 驗證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只在上面的getCallbacks調用之後填充
		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 " + 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);
	}
}

以上方法完整地闡述了一個創建Spring中的Enhancer的過程,讀者可以參考Enhancer文檔查看每個步驟的含義,這裏最重要的是通過getCallbacks方法設置攔截器鏈。

3、getCallbacks

private Callback[] getCallbacks(Class<?> rootClass) throws Exception {
	// 用於優化選擇的參數
	boolean exposeProxy = this.advised.isExposeProxy();
	boolean isFrozen = this.advised.isFrozen();
	boolean isStatic = this.advised.getTargetSource().isStatic();
	
	// 選擇一個aop攔截器(用於aop調用)
	Callback aopInterceptor = new DynamicAdvisedInterceptor(this.advised);
	
	// 選擇一個直接命中目標的攔截器
	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 targetDispatcher = (isStatic ?
			new StaticDispatcher(this.advised.getTargetSource().getTarget()) : new SerializableNoOp());

	Callback[] mainCallbacks = new Callback[] {
			// 將攔截器加入Callback
			aopInterceptor,  
			targetInterceptor,  
			new SerializableNoOp(), 
			targetDispatcher, this.advisedDispatcher,
			new EqualsInterceptor(this.advised),
			new HashCodeInterceptor(this.advised)
	};

	Callback[] callbacks;

	// 如果目標是靜態的,並且通知鏈是凍結的,然後我們可以通過發送AOP調用來進行一些優化
	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++) {
			Method method = methods[x];
			List<Object> chain = this.advised.getInterceptorsAndDynamicInterceptionAdvice(method, rootClass);
			fixedCallbacks[x] = new FixedChainStaticTargetInterceptor(
					chain, this.advised.getTargetSource().getTarget(), this.advised.getTargetClass());
			this.fixedInterceptorMap.put(methods.toString(), x);
		}

		// 現在從mainCallbacks複製兩個回調並將fixedCallbacks放入callbacks數組中
		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;
}

4、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 = this.advised.getTargetSource();
	try {
		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();
		}
		retVal = processReturnType(proxy, target, method, retVal);
		return retVal;
	}
	finally {
		if (target != null && !targetSource.isStatic()) {
			targetSource.releaseTarget(target);
		}
		if (setProxyContext) {
			AopContext.setCurrentProxy(oldProxy);
		}
	}
}

上述的實現與JDK方式的實現代理的invoke方法大同小異,都是手洗構造鏈,然後封裝此鏈進行串聯調用,稍有些區別就是JDK找那個直接構造ReflectiveMethodInvocation,而在Cglib中使用CglibMethodInvocation。CglibMethodInvocation繼承自ReflectiveMethodInvocation,但是proceed方法並沒有重寫。

如果您覺得有幫助,歡迎點贊收藏哦 ~ ~ 多謝~

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章