若是不瞭解JDK中proxy動態代理機制的能夠先查看上篇文章的內容:Java動態代理學習【Spring AOP基礎之一】html
因爲Java動態代理Proxy.newProxyInstance()的時候會發現其參數類型是ClassLoader classLoader, Class<?>[] interface, InvocationHandler handler, 只支持根據接口實現代理類,若是全部代碼都是本身掌控,固然沒有問題。全部的業務邏輯均抽象出接口,而後全部的業務類實現接口,這樣全部的業務類都可以使用Java動態代理做爲AOP編程的底層支持;可是,假設若是咱們想要給一個外部依賴的類添加AOP,而且外部的類並無實現接口,此時Java動態代理就無能爲力了,此時就須要CgLib出場了。java
業務邏輯類(無接口實現)git
public class EasyClass { public void easyMethod() { System.out.println("這是一個很是簡單的方法"); } }
若是想要使用CgLib給該業務邏輯類建立代理,而且在業務方法的先後等位置增長一些處理邏輯,須要實現net.sf.cglib.proxy.MethodInterceptor接口,而且重寫它的intercept方法(代理類中額外的邏輯實現須要在這個函數中實現,是否調用原有類中的方法也須要在這裏體現),下面簡單在原有方法先後增長一些邏輯;編程
public class EasyIntercepter implements MethodInterceptor { public Object intercept(Object obj, Method method, Object[] args, MethodProxy proxy) throws Throwable { System.out.println("before"); Object result = proxy.invokeSuper(obj, args); System.out.println("after"); return result; } }
接下來使用net.sf.cglib.proxy.Enhancer生成相應的代理類便可數組
public class EasyProxyTest { public static void main(String[] args) { EasyClass easyClass = (EasyClass)Enhancer.create( EasyClass.class, null, new EasyIntercepter() ); easyClass.easyMethod(); //another method Enhancer enhancer = new Enhancer(); enhancer.setSuperclass(EasyClass.class); enhancer.setCallback(new EasyIntercepter()); ((EasyClass)enhancer.create()).easyMethod(); } }
輸出內容以下:maven
從輸出內容來看,已經簡單的在原有的業務方法先後添加的處理邏輯,因此這個技術就能夠用來當作AOP底層生成的技術之一,Spring AOP也正是用這個技術來生成,當配置文件中啓用了cglib生成代理類,或者是須要代理的對象沒有實現接口,Spring均會使用cglib生成代理類。可是須要使用maven或者gradle引入cglib的引用。函數
其方法應該相似於JDK動態代理。該方法是生成原有類的子類,並使用MethodInterceptor截取每一個方法的調用。post
將上面生成的代理類反向編譯以下:學習
import java.lang.reflect.Method; import net.sf.cglib.core.ReflectUtils; import net.sf.cglib.core.Signature; public class EasyClass$$EnhancerByCGLIB$$48da2939 extends EasyClass 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$easyMethod$0$Method; private static final MethodProxy CGLIB$easyMethod$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("net.sf.cglib.proxy.EasyClass$$EnhancerByCGLIB$$48da2939"); 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$easyMethod$0$Method = ReflectUtils.findMethods(new String[]{"easyMethod", "()V"}, (var1 = Class.forName("net.sf.cglib.proxy.EasyClass")).getDeclaredMethods())[0]; CGLIB$easyMethod$0$Proxy = MethodProxy.create(var1, var0, "()V", "easyMethod", "CGLIB$easyMethod$0"); } final void CGLIB$easyMethod$0() { super.easyMethod(); } public final void easyMethod() { MethodInterceptor var10000 = this.CGLIB$CALLBACK_0; if(this.CGLIB$CALLBACK_0 == null) { CGLIB$BIND_CALLBACKS(this); var10000 = this.CGLIB$CALLBACK_0; } if(var10000 != null) { var10000.intercept(this, CGLIB$easyMethod$0$Method, CGLIB$emptyArgs, CGLIB$easyMethod$0$Proxy); } else { super.easyMethod(); } } final boolean CGLIB$equals$1(Object var1) { return super.equals(var1); } public final boolean equals(Object var1) { MethodInterceptor var10000 = this.CGLIB$CALLBACK_0; if(this.CGLIB$CALLBACK_0 == 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).booleanValue(); } else { return super.equals(var1); } } final String CGLIB$toString$2() { return super.toString(); } public final String toString() { MethodInterceptor var10000 = this.CGLIB$CALLBACK_0; if(this.CGLIB$CALLBACK_0 == 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(this.CGLIB$CALLBACK_0 == 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(this.CGLIB$CALLBACK_0 == 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 -1577766638: if(var10000.equals("easyMethod()V")) { return CGLIB$easyMethod$0$Proxy; } break; case -508378822: if(var10000.equals("clone()Ljava/lang/Object;")) { return CGLIB$clone$4$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 EasyClass$$EnhancerByCGLIB$$48da2939() { 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) { EasyClass$$EnhancerByCGLIB$$48da2939 var1 = (EasyClass$$EnhancerByCGLIB$$48da2939)var0; if(!var1.CGLIB$BOUND) { var1.CGLIB$BOUND = true; Object var10000 = CGLIB$THREAD_CALLBACKS.get(); if(var10000 == null) { var10000 = CGLIB$STATIC_CALLBACKS; if(CGLIB$STATIC_CALLBACKS == null) { return; } } var1.CGLIB$CALLBACK_0 = (MethodInterceptor)((Callback[])var10000)[0]; } } public Object newInstance(Callback[] var1) { CGLIB$SET_THREAD_CALLBACKS(var1); EasyClass$$EnhancerByCGLIB$$48da2939 var10000 = new EasyClass$$EnhancerByCGLIB$$48da2939(); CGLIB$SET_THREAD_CALLBACKS((Callback[])null); return var10000; } public Object newInstance(Callback var1) { CGLIB$SET_THREAD_CALLBACKS(new Callback[]{var1}); EasyClass$$EnhancerByCGLIB$$48da2939 var10000 = new EasyClass$$EnhancerByCGLIB$$48da2939(); CGLIB$SET_THREAD_CALLBACKS((Callback[])null); return var10000; } public Object newInstance(Class[] var1, Object[] var2, Callback[] var3) { CGLIB$SET_THREAD_CALLBACKS(var3); EasyClass$$EnhancerByCGLIB$$48da2939 var10000 = new EasyClass$$EnhancerByCGLIB$$48da2939; 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$CALLBACK_0就是設置的callback函數,及實現的MethodInceptor接口的邏輯類,因此當調用easyMethod的時候,若是代理類中存在實現MethodInceptor接口的邏輯類,調用其intercept方法,其實這個地方的原理和JDK動態代理有些類似。gradle
反編譯的方法是git clone cglib的工程文件,找到Enhancer類中建立代理類byte[]的位置,將byte[]數組寫成.class文件,而後反編譯.class文件。由於和JDK動態代理同樣,運行時動態生成類都是動態生成byte[]類結構,而後經過defineClass加載到虛擬機中進一步獲得對象。
目前不知道如何從一個class類型獲得其byte[]文件,因此只能採起上面的方法;關於這個我查閱到兩個相關問題,感受沒有很簡單的方法,大多回答是基於已有.class文件,可是這裏只有動態的class類型,並無生成.class文件。
https://stackoverflow.com/questions/2036108/convert-class-object-to-bytes