Java中的cglib原理解析
cglib原理解析
先放上示例代碼:
//Person.java public class Person { public void sayHello() { System.out.println("Hello!"); } } //Test.java import org.objectweb.asm.ClassWriter; import net.sf.cglib.proxy.Enhancer; import net.sf.cglib.proxy.MethodInterceptor; import net.sf.cglib.proxy.MethodProxy; import java.io.FileOutputStream; import java.lang.reflect.Method; public class Test { public static void main(String[] args) throws Exception { Enhancer enhancer = new Enhancer(); enhancer.setSuperclass(Person.class); //設置生成的類不繼承Factory接口 enhancer.setUseFactory(false); enhancer.setCallback(new MethodInterceptor() { public Object intercept(Object o, Method method, Object[] objects, MethodProxy methodProxy) throws Throwable { System.out.println("Intercept!"); methodProxy.invokeSuper(o, objects); return null; } }); Person person = (Person) enhancer.create(); person.sayHello(); //以下代碼是為了輸出cglib生成的類的class文件 ClassWriter cw = new ClassWriter(0); enhancer.generateClass(cw); byte[] klass = cw.toByteArray(); FileOutputStream fileOutputStream = new FileOutputStream(person.getClass().getName()+".class"); fileOutputStream.write(klass); fileOutputStream.close(); } }
使用cglib生成代碼的過程很簡單:
- new 一個Enhancer對象
- 調用它的setSuperclass()方法設置需要代理的類
- 調用它的setCallback()方法設置攔截被代理類方法時的邏輯
為了簡單起見,我們還調用了setUseFactory(false)方法,使得生成的代理類不實現(xiàn)Factory接口(該接口提供了一些生成新對象的和設置對象的Callback的方法)。并且沒有使用CallbackFilter。
cglib生成對象時主要的邏輯在Enchancer類的generateClass方法里面:
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()); //以下兩行代碼獲得被代理類的非私有構造函數(shù) List constructors = new ArrayList(Arrays.asList(sc.getDeclaredConstructors())); 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(); final Set forcePublic = new HashSet(); //得到被代理類及其父類、接口的非final、非static、非private方法。這些方法是需要代理的(在不考慮CallbackFilter的情況下) 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); if (currentData == null) { //生成class文件的版本號、類的訪問描述符、類名、父類名、接口,并生成SourceFile屬性 e.begin_class(Constants.V1_2, 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_2, Constants.ACC_PUBLIC, getClassName(), null, new Type[]{FACTORY}, Constants.SOURCE_FILE); } List constructorInfo = CollectionUtils.transform(constructors, MethodInfoTransformer.getInstance()); //以下生成代理類的字段,可以對照下面的反編譯結果觀看 //生成private boolean CGLIB$BOUND字段 e.declare_field(Constants.ACC_PRIVATE, BOUND_FIELD, Type.BOOLEAN_TYPE, null); //生成public static Object CGLIB$FACTORY_DATA字段 e.declare_field(Constants.ACC_PUBLIC | Constants.ACC_STATIC, FACTORY_DATA_FIELD, OBJECT_TYPE, null); if (!interceptDuringConstruction) { e.declare_field(Constants.ACC_PRIVATE, CONSTRUCTED_FIELD, Type.BOOLEAN_TYPE, null); } //生成private static final ThreadLocal CGLIB$THREAD_CALLBACKS字段 e.declare_field(Constants.PRIVATE_FINAL_STATIC, THREAD_CALLBACKS_FIELD, THREAD_LOCAL, null); //生成private static final Callback[] CGLIB$STATIC_CALLBACKS字段 e.declare_field(Constants.PRIVATE_FINAL_STATIC, STATIC_CALLBACKS_FIELD, CALLBACK_ARRAY, null); if (serialVersionUID != null) { e.declare_field(Constants.PRIVATE_FINAL_STATIC, Constants.SUID_FIELD_NAME, Type.LONG_TYPE, serialVersionUID); } //以下是生成Callback字段,可以看到,對應每個設置的Callback,都會在代理類中生成一個對應具體類型的字段 for (int i = 0; i < callbackTypes.length; i++) { //在本例中生成的是private MethodInterceptor CGLIB$CALLBACK_0字段,后綴_0代表是在Enhancer中設置的第0個Callback e.declare_field(Constants.ACC_PRIVATE, getCallbackField(i), callbackTypes[i], null); } // This is declared private to avoid "public field" pollution //生成private static Object CGLIB$CALLBACK_FILTER字段。如果Enhancer只設置了一個Callback并且沒有設置CallbackFilter,那么會默認對該Enhancer對象添加一個指向第0個Callback的CallbackFilter e.declare_field(Constants.ACC_PRIVATE | Constants.ACC_STATIC, CALLBACK_FILTER_FIELD, OBJECT_TYPE, null); if (currentData == null) { //這個函數(shù)生成需要代理類的方法 emitMethods(e, methods, actualMethods); //生成構造函數(shù) emitConstructors(e, constructorInfo); } else { emitDefaultConstructor(e); } //以下三行代碼分別生成代理類的CGLIB$SET_THREAD_CALLBACKS、CGLIB$SET_STATIC_CALLBACKS和CGLIB$BIND_CALLBACKS函數(shù) emitSetThreadCallbacks(e); emitSetStaticCallbacks(e); emitBindCallbacks(e); if (useFactory || currentData != null) { int[] keys = getCallbackKeys(); //如果useFactory為true就會生成幾個newInstance方法,還有幾個操作代理類的Callback的方法 emitNewInstanceCallbacks(e); emitNewInstanceCallback(e); emitNewInstanceMultiarg(e, constructorInfo); emitGetCallback(e, keys); emitSetCallback(e, keys); emitGetCallbacks(e); emitSetCallbacks(e); } e.end_class(); }
使用Bytecode Viewer的CFR反編譯生成的代理類如下:
/* * Decompiled with CFR 0_125. * * Could not load the following classes: * Person * Person$$EnhancerByCGLIB$$34b905e4 * net.sf.cglib.core.ReflectUtils * net.sf.cglib.core.Signature * net.sf.cglib.proxy.Callback * net.sf.cglib.proxy.MethodInterceptor * net.sf.cglib.proxy.MethodProxy */ import java.lang.reflect.Method; import net.sf.cglib.core.ReflectUtils; import net.sf.cglib.core.Signature; import net.sf.cglib.proxy.Callback; import net.sf.cglib.proxy.MethodInterceptor; import net.sf.cglib.proxy.MethodProxy; /* * Exception performing whole class analysis ignored. */ public class Person$$EnhancerByCGLIB$$34b905e4 extends Person { 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$sayHello$0$Method; private static final MethodProxy CGLIB$sayHello$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$STATICHOOK2() { CGLIB$THREAD_CALLBACKS = new ThreadLocal(); CGLIB$emptyArgs = new Object[0]; Class class_ = Class.forName("Person$$EnhancerByCGLIB$$34b905e4"); Class class_2 = Class.forName("java.lang.Object"); Method[] arrmethod = ReflectUtils.findMethods((String[])new String[]{"equals", "(Ljava/lang/Object;)Z", "toString", "()Ljava/lang/String;", "hashCode", "()I", "clone", "()Ljava/lang/Object;"}, (Method[])class_2.getDeclaredMethods()); CGLIB$equals$1$Method = arrmethod[0]; CGLIB$equals$1$Proxy = MethodProxy.create(class_2, class_, (String)"(Ljava/lang/Object;)Z", (String)"equals", (String)"CGLIB$equals$1"); CGLIB$toString$2$Method = arrmethod[1]; CGLIB$toString$2$Proxy = MethodProxy.create(class_2, class_, (String)"()Ljava/lang/String;", (String)"toString", (String)"CGLIB$toString$2"); CGLIB$hashCode$3$Method = arrmethod[2]; CGLIB$hashCode$3$Proxy = MethodProxy.create(class_2, class_, (String)"()I", (String)"hashCode", (String)"CGLIB$hashCode$3"); CGLIB$clone$4$Method = arrmethod[3]; CGLIB$clone$4$Proxy = MethodProxy.create(class_2, class_, (String)"()Ljava/lang/Object;", (String)"clone", (String)"CGLIB$clone$4"); class_2 = Class.forName("Person"); CGLIB$sayHello$0$Method = ReflectUtils.findMethods((String[])new String[]{"sayHello", "()V"}, (Method[])class_2.getDeclaredMethods())[0]; CGLIB$sayHello$0$Proxy = MethodProxy.create(class_2, class_, (String)"()V", (String)"sayHello", (String)"CGLIB$sayHello$0"); } final void CGLIB$sayHello$0() { super.sayHello(); } public final void sayHello() { MethodInterceptor methodInterceptor = this.CGLIB$CALLBACK_0; if (methodInterceptor == null) { Person$$EnhancerByCGLIB$$34b905e4.CGLIB$BIND_CALLBACKS((Object)this); methodInterceptor = this.CGLIB$CALLBACK_0; } if (methodInterceptor != null) { Object object = methodInterceptor.intercept((Object)this, CGLIB$sayHello$0$Method, CGLIB$emptyArgs, CGLIB$sayHello$0$Proxy); return; } super.sayHello(); } final boolean CGLIB$equals$1(Object object) { return super.equals(object); } public final boolean equals(Object object) { MethodInterceptor methodInterceptor = this.CGLIB$CALLBACK_0; if (methodInterceptor == null) { Person$$EnhancerByCGLIB$$34b905e4.CGLIB$BIND_CALLBACKS((Object)this); methodInterceptor = this.CGLIB$CALLBACK_0; } if (methodInterceptor == null) return super.equals(object); Object object2 = methodInterceptor.intercept((Object)this, CGLIB$equals$1$Method, new Object[]{object}, CGLIB$equals$1$Proxy); if (object2 == null) { return false; } boolean bl = (Boolean)object2; return bl; } final String CGLIB$toString$2() { return super.toString(); } public final String toString() { MethodInterceptor methodInterceptor = this.CGLIB$CALLBACK_0; if (methodInterceptor == null) { Person$$EnhancerByCGLIB$$34b905e4.CGLIB$BIND_CALLBACKS((Object)this); methodInterceptor = this.CGLIB$CALLBACK_0; } if (methodInterceptor == null) return super.toString(); return (String)methodInterceptor.intercept((Object)this, CGLIB$toString$2$Method, CGLIB$emptyArgs, CGLIB$toString$2$Proxy); } final int CGLIB$hashCode$3() { return super.hashCode(); } public final int hashCode() { MethodInterceptor methodInterceptor = this.CGLIB$CALLBACK_0; if (methodInterceptor == null) { Person$$EnhancerByCGLIB$$34b905e4.CGLIB$BIND_CALLBACKS((Object)this); methodInterceptor = this.CGLIB$CALLBACK_0; } if (methodInterceptor == null) return super.hashCode(); Object object = methodInterceptor.intercept((Object)this, CGLIB$hashCode$3$Method, CGLIB$emptyArgs, CGLIB$hashCode$3$Proxy); if (object == null) { return 0; } int n = ((Number)object).intValue(); return n; } final Object CGLIB$clone$4() throws CloneNotSupportedException { return super.clone(); } protected final Object clone() throws CloneNotSupportedException { MethodInterceptor methodInterceptor = this.CGLIB$CALLBACK_0; if (methodInterceptor == null) { Person$$EnhancerByCGLIB$$34b905e4.CGLIB$BIND_CALLBACKS((Object)this); methodInterceptor = this.CGLIB$CALLBACK_0; } if (methodInterceptor == null) return super.clone(); return methodInterceptor.intercept((Object)this, CGLIB$clone$4$Method, CGLIB$emptyArgs, CGLIB$clone$4$Proxy); } public static MethodProxy CGLIB$findMethodProxy(Signature signature) { String string = signature.toString(); switch (string.hashCode()) { case -508378822: { if (!string.equals("clone()Ljava/lang/Object;")) return null; return CGLIB$clone$4$Proxy; } case 1535311470: { if (!string.equals("sayHello()V")) return null; return CGLIB$sayHello$0$Proxy; } case 1826985398: { if (!string.equals("equals(Ljava/lang/Object;)Z")) return null; return CGLIB$equals$1$Proxy; } case 1913648695: { if (!string.equals("toString()Ljava/lang/String;")) return null; return CGLIB$toString$2$Proxy; } case 1984935277: { if (!string.equals("hashCode()I")) return null; return CGLIB$hashCode$3$Proxy; } } return null; } public Person$$EnhancerByCGLIB$$34b905e4() { Person$$EnhancerByCGLIB$$34b905e4 person$$EnhancerByCGLIB$$34b905e4 = this; Person$$EnhancerByCGLIB$$34b905e4.CGLIB$BIND_CALLBACKS((Object)person$$EnhancerByCGLIB$$34b905e4); } public static void CGLIB$SET_THREAD_CALLBACKS(Callback[] arrcallback) { CGLIB$THREAD_CALLBACKS.set(arrcallback); } public static void CGLIB$SET_STATIC_CALLBACKS(Callback[] arrcallback) { CGLIB$STATIC_CALLBACKS = arrcallback; } private static final void CGLIB$BIND_CALLBACKS(Object object) { Person$$EnhancerByCGLIB$$34b905e4 person$$EnhancerByCGLIB$$34b905e4 = (Person$$EnhancerByCGLIB$$34b905e4)object; if (person$$EnhancerByCGLIB$$34b905e4.CGLIB$BOUND) return; person$$EnhancerByCGLIB$$34b905e4.CGLIB$BOUND = true; Object t = CGLIB$THREAD_CALLBACKS.get(); if (t == null && (v783 = CGLIB$STATIC_CALLBACKS) == null) { return; } person$$EnhancerByCGLIB$$34b905e4.CGLIB$CALLBACK_0 = (MethodInterceptor)((Callback[])t)[0]; } static { Person$$EnhancerByCGLIB$$34b905e4.CGLIB$STATICHOOK2(); } }
可以看到,在創(chuàng)建一個代理類的對象的時候,會先加載這個類,也就調用了類的靜態(tài)方法CGLIB$STATICHOOK2(),在這個函數(shù)中對類的其它靜態(tài)字段進行了初始化,比如對應每個需要代理的方法都生成兩個字段,一個是用于反射的Method對象,另一個是用于加快方法調用、避免反射帶來的開銷的MethodProxy對象。然后在構造函數(shù)里面調用了CGLIB$BIND_CALLBACKS(this),在CGLIB$BIND_CALLBACKS方法中會把private MethodInterceptor CGLIB$CALLBACK_0字段和設置的靜態(tài)變量ThreadLocal CGLIB$THREAD_CALLBACKS進行綁定,也就是說,設置的Callback并不是硬編碼在生成的代理類里面的,而是可以動態(tài)地設置。
由于代理類繼承了被代理類,所以調用sayHello()方法時會直接調用代理類的sayHello()方法,而在代理類的方法中,調用了Callback的邏輯。
到此這篇關于Java中的cglib原理解析的文章就介紹到這了,更多相關cglib原理解析內容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關文章希望大家以后多多支持腳本之家!
相關文章
利用Java實現(xiàn)和可被K整除的子數(shù)組完整實例
這篇文章主要給大家介紹了關于利用Java實現(xiàn)和可被K整除的子數(shù)組的相關資料,這道題來自力扣,通過學習這道題的解題思路以及代碼對大家的學習或者工作具有一定的參考借鑒價值,需要的朋友可以參考下2024-01-01Spring JdbcTemplate整合使用方法及原理詳解
這篇文章主要介紹了Spring JdbcTemplate整合使用方法及原理詳解,文中通過示例代碼介紹的非常詳細,對大家的學習或者工作具有一定的參考學習價值,需要的朋友可以參考下2020-08-08