代理模式是一種很常見的模式,本文主要分析cglib動態代理的過程
1. 舉例
使用cglib代理需要引入兩個包,maven的話包引入如下
<!-- https://mvnrepository.com/artifact/cglib/cglib --> <dependency> <groupId>cglib</groupId> <artifactId>cglib</artifactId> <version>3.3.0</version> </dependency> <!-- https://mvnrepository.com/artifact/org.ow2.asm/asm --> <dependency> <groupId>org.ow2.asm</groupId> <artifactId>asm</artifactId> <version>7.1</version> </dependency>
示例代碼
import net.sf.cglib.core.DebuggingClassWriter; import net.sf.cglib.core.KeyFactory; import net.sf.cglib.proxy.Callback; import net.sf.cglib.proxy.Enhancer; import net.sf.cglib.proxy.MethodInterceptor; import net.sf.cglib.proxy.MethodProxy; import java.lang.reflect.Method; /** * @Description: * @author: zhoum * @Date: 2019-12-05 * @Time: 9:36 */ public class CgProxyFactory implements MethodInterceptor { public <T>T getProxy(Class<T> c){ Enhancer enhancer = new Enhancer(); enhancer.setCallbacks(new Callback[]{this}); enhancer.setSuperclass(c); return (T)enhancer.create(); } @Override public Object intercept(Object obj , Method method , Object[] args , MethodProxy proxy) throws Throwable { System.out.println("執行前-------->"); Object o = proxy.invokeSuper(obj , args); System.out.println("執行后-------->"); return o; } public static void main(String[] args) { System.setProperty(DebuggingClassWriter.DEBUG_LOCATION_PROPERTY, "F:/DEBUG"); CgProxyFactory factory = new CgProxyFactory(); CgProxy proxy = factory.getProxy(CgProxy.class); proxy.say(); } } class CgProxy{ public String say(){ System.out.println("普通方法執行"); return "123"; } }
控制台輸出結果,可以看到方法已經被代理增強了
原理解析
1.Enhancer.create()方法
通過上面代碼,相信大家都能知道主要創建代理類的方法為Enhancer.create()方法,但是我們在執行這個方法之前設置了兩個值,可以分別看下方法體
setCallbacks(),即設置回調,我們創建出代理類后調用方法則是使用的這個回調接口,類似於jdk動態代理中的InvocationHandler
public void setCallbacks(Callback[] callbacks) { if (callbacks != null && callbacks.length == 0) { throw new IllegalArgumentException("Array cannot be empty"); } this.callbacks = callbacks; }
setSuperClass 即設置代理類,這兒可以看到做了個判斷,如果為interface則設置interfaces,如果是Object則設置為null(因為所有類都自動繼承Object),如果為普通class則設置class,可以看到cglib代理不光可以代理接口,也可以代理普通類
public void setSuperclass(Class superclass) { if (superclass != null && superclass.isInterface()) {
//設置代理接口 setInterfaces(new Class[]{ superclass }); } else if (superclass != null && superclass.equals(Object.class)) { // 未Object則用設置 this.superclass = null; } else {
//設置代理類 this.superclass = superclass; } }
public void setInterfaces(Class[] interfaces) {
this.interfaces = interfaces;
}
上面總結看來主要設置兩個我們需要用到的信息
public Object create() { //不作代理類限制 classOnly = false; //沒有構造參數類型 argumentTypes = null; //執行創建 return createHelper(); }
2.Enhancer.createHelper()方法
private Object createHelper() { //進行驗證 並確定CallBack類型 本方法是用的MethodInterceptor preValidate(); //獲取當前代理類的標識類Enhancer.EnhancerKey的代理 Object key = KEY_FACTORY.newInstance((superclass != null) ? superclass.getName() : null, ReflectUtils.getNames(interfaces), filter == ALL_ZERO ? null : new WeakCacheKey<CallbackFilter>(filter), callbackTypes, useFactory, interceptDuringConstruction, serialVersionUID); //設置當前enhancer的代理類的key標識 this.currentKey = key; //調用父類即 AbstractClassGenerator的創建代理類 Object result = super.create(key); return result; } private void preValidate() { if (callbackTypes == null) { //確定傳入的callback類型 callbackTypes = CallbackInfo.determineTypes(callbacks, false); validateCallbackTypes = true; } if (filter == null) { if (callbackTypes.length > 1) { throw new IllegalStateException("Multiple callback types possible but no filter specified"); } filter = ALL_ZERO; } } //最后是遍歷這個數組來確定 本方法是用的MethodInterceptor private static final CallbackInfo[] CALLBACKS = { new CallbackInfo(NoOp.class, NoOpGenerator.INSTANCE), new CallbackInfo(MethodInterceptor.class, MethodInterceptorGenerator.INSTANCE), new CallbackInfo(InvocationHandler.class, InvocationHandlerGenerator.INSTANCE), new CallbackInfo(LazyLoader.class, LazyLoaderGenerator.INSTANCE), new CallbackInfo(Dispatcher.class, DispatcherGenerator.INSTANCE), new CallbackInfo(FixedValue.class, FixedValueGenerator.INSTANCE), new CallbackInfo(ProxyRefDispatcher.class, DispatcherGenerator.PROXY_REF_INSTANCE), };
方法主要做了下驗證並確定Callback類型,我們使用的是MethodIntercepter。然后創建當前代理類的標識代理類,用這個標識代理類調用父類(AbstractClassGenerator)的create(key方法創建),我們主要分析下標識代理類創建的邏輯和后面父類創建我們需要的代理類邏輯。
標識代理類的創建類成員變量即KEY_FACTORY是創建代理類的核心,我們先分析下這個
3.1KEY_FACTORY
追蹤源碼可以看到,KEY_FACTORY在Enhancer的初始化即會創建一個final的靜態變量
private static final EnhancerKey KEY_FACTORY = (EnhancerKey)KeyFactory.create(EnhancerKey.class, KeyFactory.HASH_ASM_TYPE, null);
3.2Keyfactory_create方法
這兒可以看到使用key工廠創建出對應class的代理類,后面的KeyFactory_HASH_ASM_TYPE即代理類中創建HashCode方法的策略。我們接着點擊源碼查看
public static KeyFactory create(ClassLoader loader, Class keyInterface, KeyFactoryCustomizer customizer, List<KeyFactoryCustomizer> next) { //創建一個最簡易的代理類生成器 即只會生成HashCode equals toString newInstance方法 Generator gen = new Generator(); //設置接口為enhancerKey類型 gen.setInterface(keyInterface); if (customizer != null) { //添加定制器 gen.addCustomizer(customizer); } if (next != null && !next.isEmpty()) { for (KeyFactoryCustomizer keyFactoryCustomizer : next) { //添加定制器 gen.addCustomizer(keyFactoryCustomizer); } } //設置生成器的類加載器 gen.setClassLoader(loader); //生成enhancerKey的代理類 return gen.create(); }
3.3Generator的create方法
這兒創建了一個簡易的代理類生成器(KeyFactory的內部類Generator ,與Enhancer一樣繼承自抽象類AbstractClassGenerator)來生成我們需要的標識代理類,我們接着看gen.create()方法
public KeyFactory create() {
//設置了該生成器生成代理類的名字前綴,即我們的接口名Enhancer.enhancerKey setNamePrefix(keyInterface.getName()); return (KeyFactory)super.create(keyInterface.getName()); }
這兒可以看到調用的是父類AbstractClassGenerator的create方法,參數名為接口名
3.4 AbstractClassGenerator的create(Key)方法
protected Object create(Object key) { try { //獲取到當前生成器的類加載器 ClassLoader loader = getClassLoader(); //當前類加載器對應的緩存 緩存key為類加載器,緩存的value為ClassLoaderData 這個類后面會再講 Map<ClassLoader, ClassLoaderData> cache = CACHE; //先從緩存中獲取下當前類加載器所有加載過的類 ClassLoaderData data = cache.get(loader); //如果為空 if (data == null) { synchronized (AbstractClassGenerator.class) { cache = CACHE; data = cache.get(loader); //經典的防止並發修改 二次判斷 if (data == null) { //新建一個緩存Cache 並將之前的緩存Cache的數據添加進來 並將已經被gc回收的數據給清除掉 Map<ClassLoader, ClassLoaderData> newCache = new WeakHashMap<ClassLoader, ClassLoaderData>(cache); //新建一個當前加載器對應的ClassLoaderData 並加到緩存中 但ClassLoaderData中此時還沒有數據 data = new ClassLoaderData(loader); newCache.put(loader, data); //刷新全局緩存 CACHE = newCache; } } } //設置一個全局key this.key = key; //在剛創建的data(ClassLoaderData)中調用get方法 並將當前生成器, //以及是否使用緩存的標識穿進去 系統參數 System.getProperty("cglib.useCache", "true") //返回的是生成好的代理類的class信息 Object obj = data.get(this, getUseCache()); //如果為class則實例化class並返回 就是我們需要的代理類 if (obj instanceof Class) { return firstInstance((Class) obj); } //如果不是則說明是實體 則直接執行另一個方法返回實體 return nextInstance(obj); } catch (RuntimeException e) { throw e; } catch (Error e) { throw e; } catch (Exception e) { throw new CodeGenerationException(e); } }
這個方法可以看到主要為根據類加載器定義一個緩存,里面裝載了緩存的類信息,然后調用這個ClassLoaderData的get方法獲取到數據,如果為class信息 那么直接使用反射實例化,如果返回的是實體類,則解析實體類的信息,調用其newInstance方法重新生成一個實例(cglib的代理類都會生成newInstance方法)
具體根據class信息或者實體信息實例化數據都比較簡單,相信代碼大家都能看懂 ,這兒就不講解了。核心點還是在於如何根據生成器來返回代理類或者代理類信息,我們繼續查看data.get(this,getUseCache)
3.5data.get(this,getUseCache)
public Object get(AbstractClassGenerator gen, boolean useCache) { //如果不用緩存 (默認使用) if (!useCache) { //則直接調用生成器的命令 return gen.generate(ClassLoaderData.this); } else { //從緩存中獲取值 Object cachedValue = generatedClasses.get(gen); //解包裝並返回 return gen.unwrapCachedValue(cachedValue); } }
這兒可以看到 如果可以用緩存 則調用緩存,不能調用緩存則直接生成, 這兒我們先看調用緩存的,在看之前需要再看一個東西,就是3.4之中,我們設置了一個key為ClassLoader,值為ClassLoaderData的緩存,這兒我們new了一個ClassLoaderData 並將類加載器傳了進去 ,並且設置了這個Generator的key,我們看下new的邏輯
public ClassLoaderData(ClassLoader classLoader) { //判斷類加載器不能為空 if (classLoader == null) { throw new IllegalArgumentException("classLoader == null is not yet supported"); } //設置類加載器 弱引用 即在下次垃圾回收時就會進行回收 this.classLoader = new WeakReference<ClassLoader>(classLoader); //新建一個回調函數 這個回調函數的作用在於緩存中沒獲取到值時 調用傳入的生成的生成代理類並返回 Function<AbstractClassGenerator, Object> load = new Function<AbstractClassGenerator, Object>() { public Object apply(AbstractClassGenerator gen) { Class klass = gen.generate(ClassLoaderData.this); return gen.wrapCachedClass(klass); } }; //為這個ClassLoadData新建一個緩存類 這個loadingcache稍后會講 generatedClasses = new LoadingCache<AbstractClassGenerator, Object, Object>(GET_KEY, load); } private static final Function<AbstractClassGenerator, Object> GET_KEY = new Function<AbstractClassGenerator, Object>() { public Object apply(AbstractClassGenerator gen) { return gen.key; } };
可以看到每個類加載器都對應着一個代理類緩存對象 ,這里面定義了類加載器,緩存調用沒查詢到的調用函數,以及新建了一個LoadingCache來緩存這個類加載器對應的緩存,這兒傳入的兩個參數,load代表緩存查詢失敗時的回調函數,而GET_KEY則是回調時獲取調用生成器的key 即3.4中傳入的key 也即是我們的代理類標識符。 然后我們接着看generatedClasses.get(gen);的方法
3.6 generatedClasses.get(gen);
這個方法主要傳入代理類生成器 並根據代理類生成器獲取值返回。這兒主要涉及到的類就是LoadingCache,這個類可以看做是某個CLassLoader對應的所有代理類緩存庫,是真正緩存東西的地方。我們分析下這個類
package net.sf.cglib.core.internal; import java.util.concurrent.*; public class LoadingCache<K, KK, V> { protected final ConcurrentMap<KK, Object> map; protected final Function<K, V> loader; protected final Function<K, KK> keyMapper; public static final Function IDENTITY = new Function() { public Object apply(Object key) { return key; } }; //初始化類 kemapper代表獲取某個代理類生成器的標識,loader即緩存查找失敗后的回調函數 public LoadingCache(Function<K, KK> keyMapper, Function<K, V> loader) { this.keyMapper = keyMapper; this.loader = loader; //這個map是緩存代理類的地方 this.map = new ConcurrentHashMap<KK, Object>(); } @SuppressWarnings("unchecked") public static <K> Function<K, K> identity() { return IDENTITY; } //這兒key是代理類生成器 public V get(K key) { //獲取到代理類生成器的標識 final KK cacheKey = keyMapper.apply(key); //根據緩代理類生成器的標識獲取代理類 Object v = map.get(cacheKey); //如果結果不為空且不是FutureTask 即線程池中用於獲取返回結果的接口 if (v != null && !(v instanceof FutureTask)) { //直接返回 return (V) v; } //否則就是沒查詢到 或者還未處理完 return createEntry(key, cacheKey, v); } protected V createEntry(final K key, KK cacheKey, Object v) { //初始化任務task FutureTask<V> task; //初始化創建標識 boolean creator = false; if (v != null) { // 則說明這是一個FutureTask task = (FutureTask<V>) v; } else { //否則還沒開始創建這個代理類 直接創建任務 task = new FutureTask<V>(new Callable<V>() { public V call() throws Exception { //這兒會直接調用生成器的generate方法 return loader.apply(key); } }); //將這個任務推入緩存Map 如果對應key已經有則返回已經有的task, Object prevTask = map.putIfAbsent(cacheKey, task); //如果為null則代表還沒有創建 標識更新為true 且運行這個任務 if (prevTask == null) { // creator does the load creator = true; task.run(); } //如果是task 說明另一個線程已經創建了task else if (prevTask instanceof FutureTask) { task = (FutureTask<V>) prevTask; } //到這兒說明另一個線程已經執行完了 直接返回 else { return (V) prevTask; } //上面的一堆判斷主要是為了防止並發出現的問題 } V result; try { //到這兒說明任務執行完並拿到對應的代理類了 result = task.get(); } catch (InterruptedException e) { throw new IllegalStateException("Interrupted while loading cache item", e); } catch (ExecutionException e) { Throwable cause = e.getCause(); if (cause instanceof RuntimeException) { throw ((RuntimeException) cause); } throw new IllegalStateException("Unable to load cache item", cause); } //如果這次執行是新建的 if (creator) { //將之前的FutureTask緩存直接覆蓋為實際的代理類信息 map.put(cacheKey, result); } //返回結果 return result; } }
通過上面的分析可以得知,這個類主要作用是傳入代理類生成器,根據這個代理類生成器以及代理類生成器的key來獲取緩存,如果沒有獲取到則構建一個FutureTask來回調我們之前初始化時傳入的 回調函數,並調用其中的apply方法,而具體調用的則是我們傳入的代理類生成器的generate(LoadClassData)方法,將返回值覆蓋之前的FutureTask成為真正的緩存。所以這個類的主要作用還是緩存。 這樣則和3.5中不使用緩存時調用了一樣的方法。所以我們接着來分析生成方法 generate(ClassLoadData),這兒因為我們使用的代理類生成器是Genrator,該類沒有重寫generate方法,所以回到了父類AbstractClassGenerator的generate方法
3.7 AbstractClassGenerator.generate 方法
protected Class generate(ClassLoaderData data) { Class gen; Object save = CURRENT.get(); //當前的代理類生成器存入ThreadLocal中 CURRENT.set(this); try { //獲取到ClassLoader ClassLoader classLoader = data.getClassLoader(); //判斷不能為空 if (classLoader == null) { throw new IllegalStateException("ClassLoader is null while trying to define class " + getClassName() + ". It seems that the loader has been expired from a weak reference somehow. " + "Please file an issue at cglib's issue tracker."); } synchronized (classLoader) { //生成代理類名字 String name = generateClassName(data.getUniqueNamePredicate()); //緩存中存入這個名字 data.reserveName(name); //當前代理類生成器設置類名 this.setClassName(name); } //嘗試從緩存中獲取類 if (attemptLoad) { try { //要是能獲取到就直接返回了 即可能出現並發 其他線程已經加載 gen = classLoader.loadClass(getClassName()); return gen; } catch (ClassNotFoundException e) { // 發現異常說明沒加載到 不管了 } } //生成字節碼 byte[] b = strategy.generate(this); //獲取到字節碼代表的class的名字 String className = ClassNameReader.getClassName(new ClassReader(b)); //核實是否為protect ProtectionDomain protectionDomain = getProtectionDomain(); synchronized (classLoader) { // just in case //如果不是protect if (protectionDomain == null) { //根據字節碼 類加載器 以及類名字 將class加載到內存中 gen = ReflectUtils.defineClass(className, b, classLoader); } else { //根據字節碼 類加載器 以及類名字 以及找到的Protect級別的實體 將class加載到內存中 gen = ReflectUtils.defineClass(className, b, classLoader, protectionDomain); } }
//返回生成的class信息 return gen; } catch (RuntimeException e) { throw e; } catch (Error e) { throw e; } catch (Exception e) { throw new CodeGenerationException(e); } finally { CURRENT.set(save); } }
這個方法主要設置了下當前類生成器的類名,然后調用stratege的generate方法返回字節碼,根據字節碼 類名 類加載器將字節碼所代表的類加載到內存中,這個功能看一下大概就懂,我們接下來主要分析字節碼生成方法
3.8DefaultGeneratorStrategy.generate(ClassGenerator cg)
public byte[] generate(ClassGenerator cg) throws Exception { //創建一個寫入器 DebuggingClassWriter cw = getClassVisitor(); //加入自己的轉換邏輯后執行代理類生成器的generateClass方法 transform(cg).generateClass(cw); //將cw寫入的東西轉換為byte數組返回 return transform(cw.toByteArray()); }
這里面主要是新建一個寫入器,然后執行我們代理類生成器的generateClass方法將class信息寫入這個ClassWriter 最后將里面的東西轉換為byte數組返回,所以又回到了我們的代理類生成器的generateClass方法,這兒進入的是Generator的generateClass方法
3.9Generator.generateClass(ClassVisitor v)
這個類是核心的class信息寫入類
//該方法為字節碼寫入方法 為最后一步 public void generateClass(ClassVisitor v) { //創建類寫入聚合對象 ClassEmitter ce = new ClassEmitter(v); //找到被代理類的newInstance方法 如果沒有會報異常 由此可知 如果想用Generator代理類生成器 必須要有newInstance方法 Method newInstance = ReflectUtils.findNewInstance(keyInterface); //如果被代理類的newInstance不為Object則報異常 此處我們代理的Enchaer.EnhancerKey newInstance方法返回值為Object if (!newInstance.getReturnType().equals(Object.class)) { throw new IllegalArgumentException("newInstance method must return Object"); } //找到newInstance方法的所有參數類型 並當做成員變量 Type[] parameterTypes = TypeUtils.getTypes(newInstance.getParameterTypes()); //1.創建類開始寫入類頭 版本號 訪問權限 類名等通用信息 ce.begin_class(Constants.V1_8, Constants.ACC_PUBLIC, getClassName(), KEY_FACTORY, new Type[]{ Type.getType(keyInterface) }, Constants.SOURCE_FILE); //2.寫入無參構造方法 EmitUtils.null_constructor(ce); //3.寫入newInstance方法 EmitUtils.factory_method(ce, ReflectUtils.getSignature(newInstance)); int seed = 0; //4.開始構造 有參構造方法 CodeEmitter e = ce.begin_method(Constants.ACC_PUBLIC, TypeUtils.parseConstructor(parameterTypes), null); e.load_this(); //4.1有參構造中調用父類構造方法 即super.構造方法() e.super_invoke_constructor(); e.load_this(); //4.2找到傳入的定制器 例如一開始傳入的hashCode方法定制器 List<FieldTypeCustomizer> fieldTypeCustomizers = getCustomizers(FieldTypeCustomizer.class); //4.3遍歷成員變量即newInstance方法的所有參數 for (int i = 0; i < parameterTypes.length; i++) { Type parameterType = parameterTypes[i]; Type fieldType = parameterType; for (FieldTypeCustomizer customizer : fieldTypeCustomizers) { fieldType = customizer.getOutType(i, fieldType); } seed += fieldType.hashCode(); //4.3將這些參數全部聲明到寫入類中 ce.declare_field(Constants.ACC_PRIVATE | Constants.ACC_FINAL, getFieldName(i), fieldType, null); e.dup(); e.load_arg(i); for (FieldTypeCustomizer customizer : fieldTypeCustomizers) { customizer.customize(e, i, parameterType); } //4.4設置每個成員變量的值 即我們常見的有參構造中的this.xx = xx e.putfield(getFieldName(i)); } //設置返回值 e.return_value(); //有參構造及成員變量寫入完成 e.end_method(); /*************************到此已經在class中寫入了成員變量 寫入實現了newInstance方法 寫入無參構造 寫入了有參構造 *************************/ // 5.寫入hashcode方法 e = ce.begin_method(Constants.ACC_PUBLIC, HASH_CODE, null); int hc = (constant != 0) ? constant : PRIMES[(int)(Math.abs(seed) % PRIMES.length)]; int hm = (multiplier != 0) ? multiplier : PRIMES[(int)(Math.abs(seed * 13) % PRIMES.length)]; e.push(hc); for (int i = 0; i < parameterTypes.length; i++) { e.load_this(); e.getfield(getFieldName(i)); EmitUtils.hash_code(e, parameterTypes[i], hm, customizers); } e.return_value(); //hashcode方法結束 e.end_method(); // 6.寫入equals方法 e = ce.begin_method(Constants.ACC_PUBLIC, EQUALS, null); Label fail = e.make_label(); e.load_arg(0); e.instance_of_this(); e.if_jump(e.EQ, fail); for (int i = 0; i < parameterTypes.length; i++) { e.load_this(); e.getfield(getFieldName(i)); e.load_arg(0); e.checkcast_this(); e.getfield(getFieldName(i)); EmitUtils.not_equals(e, parameterTypes[i], fail, customizers); } e.push(1); e.return_value(); e.mark(fail); e.push(0); e.return_value(); //equals方法結束 e.end_method(); // 7.寫入toString方法 e = ce.begin_method(Constants.ACC_PUBLIC, TO_STRING, null); e.new_instance(Constants.TYPE_STRING_BUFFER); e.dup(); e.invoke_constructor(Constants.TYPE_STRING_BUFFER); for (int i = 0; i < parameterTypes.length; i++) { if (i > 0) { e.push(", "); e.invoke_virtual(Constants.TYPE_STRING_BUFFER, APPEND_STRING); } e.load_this(); e.getfield(getFieldName(i)); EmitUtils.append_string(e, parameterTypes[i], EmitUtils.DEFAULT_DELIMITERS, customizers); } e.invoke_virtual(Constants.TYPE_STRING_BUFFER, TO_STRING); e.return_value(); //toString方法結束 e.end_method(); //類寫入結束 至此類信息收集完成 並全部寫入ClassVisitor ce.end_class(); }
這個方法主要將一個完整的類信息寫入ClassVisitor中,例如目前實現的Enhancer.EnhancerKey代理,即實現了newInstance方法, 重寫了HashCode,toSting,equals方法,並將newInstance的所有參數作為了成員變量,這兒我們也可以看下具體實現newInstance方法的邏輯 即這個代碼 EmitUtils.factory_method(ce, ReflectUtils.getSignature(newInstance)); 具體內容如下 其他的寫入內容大致命令也是這樣,如果有興趣可以去研究asm字節碼寫入的操作
public static void factory_method(ClassEmitter ce, Signature sig) { //開始寫入方法 CodeEmitter e = ce.begin_method(Constants.ACC_PUBLIC, sig, null); //寫入 一個創建對象命令 即new命令 e.new_instance_this(); e.dup(); //加載參數命令 e.load_args(); //執行該類的有參構造命令 e.invoke_constructor_this(TypeUtils.parseConstructor(sig.getArgumentTypes())); //將上面指令執行的值返回 e.return_value(); //結束寫入方法 e.end_method(); }
所以通過方法構造指令
可以得知 我們通過Generator創建的代理類大致內容應該如下,Enhancer.EhancerKey代理類字節碼的class內容應該是把參數換為newInstance中的參數
public class EnhancerKeyProxy extends xxx implements xxx{ private paramA; private paramB; private paramC; public EnhancerKeyProxy() { super.xxx(); } public EnhancerKeyProxy(paramA, paramB,paramC) { super.xxx(); this.paramA = paramA this.paramB = paramB this.paramC = paramC } public Object newInstance(paramA,paramB,paramC){ EnhancerKeyProxy param = new EnhancerKeyProxy(o); return param; } public int hashCode(){ ... } public String toString(){ ... } public boolean equals(Object o){ ... } }
最后執行傳入的ClassVisitor 即我們傳入的實例DebuggingClassWriter的toByteArray即可以將寫入的內容轉換為byte[]返回
至此 我們的成功的生成了Enhancer.EnhancerKey的代理類,也就是我們需要的代理類標識類 用來標識被代理的類,這個代理類主要用來作為被代理類的標識,在進行緩存時作為判斷相等的依據。可以看到 cglib代理主要也是利用我們傳入的被代理類信息來生成對應的代理類字節碼,然后用類加載器加載到內存中。雖然我們的實際的代理任務才剛剛開始,但是要了解的東西已經基本上差不多了,對具體的我們案例中的ProxyFactory代理時,只是生成器Enhancer對比生成器Generator在生成過程中重寫了一些操作而已
現在我們重新回看步驟2中的代碼
private Object createHelper() { preValidate(); //獲取到了代理類標識類 Object key = KEY_FACTORY.newInstance((superclass != null) ? superclass.getName() : null, ReflectUtils.getNames(interfaces), filter == ALL_ZERO ? null : new WeakCacheKey<CallbackFilter>(filter), callbackTypes, useFactory, interceptDuringConstruction, serialVersionUID); //設置當前enhancer正在代理生成的類信息 this.currentKey = key; //調用父類的create(key方法) Object result = super.create(key); return result; }
可以看到獲取到代理類標志類后 將其設置為當前代理類生成器的正在代理的類 並同樣調用父類AbstractClassGenerator中create(key)的方法
下面開始分析Ehancer生成器的邏輯,由於部分邏輯和Generator生成器一致 所以一樣的我會略過
4.AbstractClassGenerator.create方法
這個邏輯和步驟3.4一致,查詢當前key即代理類標志類對應的ClassLoadData緩存,如果沒有則建一個空的緩存並初始化一個對應的ClassLoadData,傳入相應的生成器,生成失敗回調函數等
按照同樣的邏輯一直走到3.5中的generate(ClassLoadData)方法時,由於Enhancer生成器重寫了這個方法 所以我們分析Enahncer的生成邏輯
5.Enhancer.generate(ClassLoadData data)
@Override protected Class generate(ClassLoaderData data) { validate(); if (superclass != null) { setNamePrefix(superclass.getName()); } else if (interfaces != null) { setNamePrefix(interfaces[ReflectUtils.findPackageProtected(interfaces)].getName()); } return super.generate(data); }
可以發現ehancer生成器只是做了個檢查命名操作 在上面的Generator中也是做了個命名操作,然后繼續執行父類的generate(data)方法,這個和步驟3.7一致,我們主要看其中生成字節碼的方法,即最后調用的Enhancer.generatorClass(ClassVisitor c)方法,
方法代碼如下
6.Enhancer.generatorClass(ClassVisitor c)
public void generateClass(ClassVisitor v) throws Exception { //聲明需代理的類 或者接口 Class sc = (superclass == null) ? Object.class : superclass; //檢查 final類無法被繼承 if (TypeUtils.isFinal(sc.getModifiers())) throw new IllegalArgumentException("Cannot subclass final class " + sc.getName()); //找到該類所有聲明了的構造函數 List constructors = new ArrayList(Arrays.asList(sc.getDeclaredConstructors())); //去掉private之類的不能被繼承的構造函數 filterConstructors(sc, constructors); // Order is very important: must add superclass, then // its superclass chain, then each interface and // its superinterfaces. //這兒順序非常重要 上面是源碼的注釋 直接留着 相信大家都能看懂 //聲明代理類方法集合 List actualMethods = new ArrayList(); //聲明代理接口接口方法集合 List interfaceMethods = new ArrayList(); //聲明所有必須為public的方法集合 這兒主要是代理接口接口的方法 final Set forcePublic = new HashSet(); //即通過傳入的代理類 代理接口,遍歷所有的方法並放入對應的集合 getMethods(sc, interfaces, actualMethods, interfaceMethods, forcePublic); //對所有代理類方法修飾符做處理 List methods = CollectionUtils.transform(actualMethods, new Transformer() { public Object transform(Object value) { Method method = (Method)value; int modifiers = Constants.ACC_FINAL | (method.getModifiers() & ~Constants.ACC_ABSTRACT & ~Constants.ACC_NATIVE & ~Constants.ACC_SYNCHRONIZED); if (forcePublic.contains(MethodWrapper.create(method))) { modifiers = (modifiers & ~Constants.ACC_PROTECTED) | Constants.ACC_PUBLIC; } return ReflectUtils.getMethodInfo(method, modifiers); } }); //創建類寫入器 ClassEmitter e = new ClassEmitter(v); //1.開始創建類 並寫入基本信息 如java版本,類修飾符 類名等 if (currentData == null) { e.begin_class(Constants.V1_8, Constants.ACC_PUBLIC, getClassName(), Type.getType(sc), (useFactory ? TypeUtils.add(TypeUtils.getTypes(interfaces), FACTORY) : TypeUtils.getTypes(interfaces)), Constants.SOURCE_FILE); } else { e.begin_class(Constants.V1_8, Constants.ACC_PUBLIC, getClassName(), null, new Type[]{FACTORY}, Constants.SOURCE_FILE); } List constructorInfo = CollectionUtils.transform(constructors, MethodInfoTransformer.getInstance()); //2. 聲明一個private boolean 類型的屬性:CGLIB$BOUND e.declare_field(Constants.ACC_PRIVATE, BOUND_FIELD, Type.BOOLEAN_TYPE, null); //3. 聲明一個public static Object 類型的屬性:CGLIB$FACTORY_DATA e.declare_field(Constants.ACC_PUBLIC | Constants.ACC_STATIC, FACTORY_DATA_FIELD, OBJECT_TYPE, null); // 這個默認為true 如果為false則會聲明一個private boolean 類型的屬性:CGLIB$CONSTRUCTED if (!interceptDuringConstruction) { e.declare_field(Constants.ACC_PRIVATE, CONSTRUCTED_FIELD, Type.BOOLEAN_TYPE, null); } //4. 聲明一個public static final 的ThreadLocal:ThreadLocal e.declare_field(Constants.PRIVATE_FINAL_STATIC, THREAD_CALLBACKS_FIELD, THREAD_LOCAL, null); //5. 聲明一個public static final 的CallBack類型的數組:CGLIB$STATIC_CALLBACKS e.declare_field(Constants.PRIVATE_FINAL_STATIC, STATIC_CALLBACKS_FIELD, CALLBACK_ARRAY, null); //如果serialVersionUID不為null 則設置一個public static final 的Long類型 serialVersionUID if (serialVersionUID != null) { e.declare_field(Constants.PRIVATE_FINAL_STATIC, Constants.SUID_FIELD_NAME, Type.LONG_TYPE, serialVersionUID); } //遍歷CallBackTypes 即我們構建Enhancer是setCallBack的所有類的類型 本案例中是methodInterceptor 並且只傳入了一個 for (int i = 0; i < callbackTypes.length; i++) { //6.聲明一個private 的傳入的CallBack類型的屬性:CGLIB$CALLBACK_0 (從0開始編號,) e.declare_field(Constants.ACC_PRIVATE, getCallbackField(i), callbackTypes[i], null); } //7聲明一個private static 的傳入的Object類型的屬性:CGLIB$CALLBACK_FILTER e.declare_field(Constants.ACC_PRIVATE | Constants.ACC_STATIC, CALLBACK_FILTER_FIELD, OBJECT_TYPE, null); //判斷currentData if (currentData == null) { //8.為null則開始聲明所有的代理類方法的變量 以及其具體的重寫實現方法,還有static初始化執行代碼塊 emitMethods(e, methods, actualMethods); //9.聲明構造函數 emitConstructors(e, constructorInfo); } else { //聲明默認構造函數 emitDefaultConstructor(e); } // emitSetThreadCallbacks(e); emitSetStaticCallbacks(e); emitBindCallbacks(e); //如果currentData不為null if (useFactory || currentData != null) { //獲取到所有CallBack索引數組 int[] keys = getCallbackKeys(); //10.聲明三個newInstance方法 //只有一個callback參數 emitNewInstanceCallbacks(e); //參數為callback數組 emitNewInstanceCallback(e); //參數為callback數組 以及附帶的一些參數 emitNewInstanceMultiarg(e, constructorInfo); //11.聲明getCallBack方法 emitGetCallback(e, keys); //12.聲明setCallBack方法 emitSetCallback(e, keys); //12.聲明setCallBacks方法 emitGetCallbacks(e); //12.聲明setCallBacks方法 emitSetCallbacks(e); } //類聲明結束 e.end_class();
可以看到這兒也是聲明一個寫入類 然后按照Ehancer的代理生成策略寫入符合的class信息然后返回,最紅依舊會執行toByteArray方法返回byte[]數組,這樣則又回到了步驟3.5中 根據類加載器 字節碼數組來動態將代理類加載進內存中的方法了。最后我們回到3.4中根據class獲取實例的代碼即可返回被代理實例。 而我們執行方法時執行的是代理類中對應的方法,然后調用我們傳入的callback執行 原理和jdk動態代理類似,至此 cglib動態代理源碼分析到此結束
對比jdk動態代理和cglib動態代理我們可以得知 jdk動態代理只能代理接口,而cglib動態代理可以代理類或者接口,說明cglib的優勢更加明顯。但是jdk動態代理是java原生支持,所以不需要引入額外的包,cglib需要引入額外的包。二者的原理類似,都是在內存中根據jvm的字節碼文件規范動態創建class並使用傳入的類加載器加載到內存中,再反射調用生成代理實例,並且都根據類加載器做了相應的緩存。實際使用中應根據利弊按需使用