日本不卡不码高清免费观看,久久国产精品久久w女人spa,黄色aa久久,三上悠亚国产精品一区二区三区

您的位置:首頁技術文章
文章詳情頁

Java cglib動態代理原理分析

瀏覽:157日期:2022-08-12 18:23:14

本文分下面三個部分來分析cglib動態代理的原理。

cglib 動態代理示例 代理類分析 Fastclass 機制分析一、cglib 動態代理示例

public class Target{ public void f(){System.out.println('Target f()'); } public void g(){System.out.println('Target g()'); }}public class Interceptor implements MethodInterceptor { @Override public Object intercept(Object obj, Method method, Object[] args, MethodProxy proxy) throws Throwable {System.out.println('I am intercept begin');//Note: 此處一定要使用proxy的invokeSuper方法來調用目標類的方法proxy.invokeSuper(obj, args);System.out.println('I am intercept end');return null; }}public class Test { public static void main(String[] args) { System.setProperty(DebuggingClassWriter.DEBUG_LOCATION_PROPERTY, 'F:code'); //實例化一個增強器,也就是cglib中的一個class generatorEnhancer eh = new Enhancer(); //設置目標類eh.setSuperclass(Target.class);// 設置攔截對象eh.setCallback(new Interceptor());// 生成代理類并返回一個實例Target t = (Target) eh.create();t.f();t.g(); }}

運行結果為:

I am intercept beginTarget f()I am intercept endI am intercept beginTarget g()I am intercept end

與JDK動態代理相比,cglib可以實現對一般類的代理而無需實現接口。在上例中通過下列步驟來生成目標類Target的代理類:

創建Enhancer實例 通過setSuperclass方法來設置目標類 通過setCallback 方法來設置攔截對象 create方法生成Target的代理類,并返回代理類的實例 二、代理類分析

在示例代碼中我們通過設置DebuggingClassWriter.DEBUG_LOCATION_PROPERTY的屬性值來獲取cglib生成的代理類。通過之前分析的命名規則我們可以很容易的在F:code下面找到生成的代理類 Target$$EnhancerByCGLIB$$788444a0.class 。

使用jd-gui進行反編譯(由于版本的問題,此處只能顯示部分代碼,可以結合javap的反編譯結果來進行分析),由于cglib會代理Object中的finalize,equals, toString,hashCode,clone方法,為了清晰的展示代理類我們省略這部分代碼,反編譯的結果如下:

public class Target$$EnhancerByCGLIB$$788444a0 extends Target implements Factory{private Boolean CGLIB$BOUND;private static final ThreadLocal CGLIB$THREAD_CALLBACKS;private static final Callback[] CGLIB$STATIC_CALLBACKS;private MethodInterceptor CGLIB$CALLBACK_0;private static final Method CGLIB$g$0$Method;private static final MethodProxy CGLIB$g$0$Proxy;private static final Object[] CGLIB$emptyArgs;private static final Method CGLIB$f$1$Method;private static final MethodProxy CGLIB$f$1$Proxy;static void CGLIB$STATICHOOK1(){CGLIB$THREAD_CALLBACKS = new ThreadLocal();CGLIB$emptyArgs = new Object[0];Class localClass1 = Class.forName('net.sf.cglib.test.Target$$EnhancerByCGLIB$$788444a0');Class localClass2;Method[] tmp60_57 = ReflectUtils.findMethods(new String[] { 'g', '()V', 'f', '()V' }, (localClass2 = Class.forName('net.sf.cglib.test.Target')).getDeclaredMethods());CGLIB$g$0$Method = tmp60_57[0];CGLIB$g$0$Proxy = MethodProxy.create(localClass2, localClass1, '()V', 'g', 'CGLIB$g$0');CGLIB$f$1$Method = tmp60_57[1];CGLIB$f$1$Proxy = MethodProxy.create(localClass2, localClass1, '()V', 'f', 'CGLIB$f$1');}final void CGLIB$g$0(){super.g();}public final void g(){MethodInterceptor tmp4_1 = this.CGLIB$CALLBACK_0;if (tmp4_1 == null){CGLIB$BIND_CALLBACKS(this);tmp4_1 = this.CGLIB$CALLBACK_0;}if (this.CGLIB$CALLBACK_0 != null) {tmp4_1.intercept(this, CGLIB$g$0$Method, CGLIB$emptyArgs, CGLIB$g$0$Proxy);} else{super.g();}}}

代理類(Target$$EnhancerByCGLIB$$788444a0)繼承了目標類(Target),至于代理類實現的factory接口與本文無關,殘忍無視。代理類為每個目標類的方法生成兩個方法,例如針對目標類中的每個非private方法,代理類會生成兩個方法,以g方法為例:一個是@Override的g方法,一個是CGLIB$g$0(CGLIB$g$0相當于目標類的g方法)。我們在示例代碼中調用目標類的方法t.g()時,實際上調用的是代理類中的g()方法。接下來我們著重分析代理類中的g方法,看看是怎么實現的代理功能。

當調用代理類的g方法時,先判斷是否已經存在實現了MethodInterceptor接口的攔截對象,如果沒有的話就調用CGLIB$BIND_CALLBACKS方法來獲取攔截對象,CGLIB$BIND_CALLBACKS的反編譯結果如下:

private static final void CGLIB$BIND_CALLBACKS(java.lang.Object); Code: 0: aload_0 1: checkcast #2; //class net/sf/cglib/test/Target$$EnhancerByCGLIB$$788444a0 4: astore_1 5: aload_1 6: getfield#212; //Field CGLIB$BOUND:Z 9: ifne 52 12: aload_1 13: iconst_1 14: putfield#212; //Field CGLIB$BOUND:Z 17: getstatic #24; //Field CGLIB$THREAD_CALLBACKS:Ljava/lang/ThreadLocal; 20: invokevirtual #215; //Method java/lang/ThreadLocal.get:()Ljava/lang/Object; 23: dup 24: ifnonnull 39 27: pop 28: getstatic #210; //Field CGLIB$STATIC_CALLBACKS:[Lnet/sf/cglib/proxy/Callback; 31: dup 32: ifnonnull 39 35: pop 36: goto 52 39: checkcast #216; //class '[Lnet/sf/cglib/proxy/Callback;' 42: aload_1 43: swap 44: iconst_0 45: aaload 46: checkcast #48; //class net/sf/cglib/proxy/MethodInterceptor 49: putfield#36; //Field CGLIB$CALLBACK_0:Lnet/sf/cglib/proxy/MethodInterceptor; 52: return

為了方便閱讀,等價的代碼如下:

private static final void CGLIB$BIND_CALLBACKS(Object o){Target$$EnhancerByCGLIB$$788444a0 temp_1 = (Target$$EnhancerByCGLIB$$788444a0)o;Object temp_2;Callback[] temp_3if(temp_1.CGLIB$BOUND == true){ return;}temp_1.CGLIB$BOUND = true;temp_2 = CGLIB$THREAD_CALLBACKS.get();if(temp_2!=null){ temp_3 = (Callback[])temp_2;}else if(CGLIB$STATIC_CALLBACKS!=null){ temp_3 = CGLIB$STATIC_CALLBACKS;}else{ return;}temp_1.CGLIB$CALLBACK_0 = (MethodInterceptor)temp_3[0];return; }

CGLIB$BIND_CALLBACKS 先從CGLIB$THREAD_CALLBACKS中get攔截對象,如果獲取不到的話,再從CGLIB$STATIC_CALLBACKS來獲取,如果也沒有則認為該方法不需要代理。

那么攔截對象是如何設置到CGLIB$THREAD_CALLBACKS 或者 CGLIB$STATIC_CALLBACKS中的呢?

在Jdk動態代理中攔截對象是在實例化代理類時由構造函數傳入的,在cglib中是調用Enhancer的firstInstance方法來生成代理類實例并設置攔截對象的。firstInstance的調用軌跡為:

Enhancer:firstInstance Enhancer:createUsingReflection Enhancer:setThreadCallbacks Enhancer:setCallbacksHelper Target$$EnhancerByCGLIB$$788444a0 : CGLIB$SET_THREAD_CALLBACKS

在第5步,調用了代理類的CGLIB$SET_THREAD_CALLBACKS來完成攔截對象的注入。下面我們看一下CGLIB$SET_THREAD_CALLBACKS的反編譯結果:

public static void CGLIB$SET_THREAD_CALLBACKS(net.sf.cglib.proxy.Callback[]); Code: 0: getstatic #24; //Field CGLIB$THREAD_CALLBACKS:Ljava/lang/ThreadLocal; 3: aload_0 4: invokevirtual #207; //Method java/lang/ThreadLocal.set:(Ljava/lang/Object;)V 7: return

在CGLIB$SET_THREAD_CALLBACKS方法中調用了CGLIB$THREAD_CALLBACKS的set方法來保存攔截對象,在CGLIB$BIND_CALLBACKS方法中使用了CGLIB$THREAD_CALLBACKS的get方法來獲取攔截對象,并保存到CGLIB$CALLBACK_0中。這樣,在我們調用代理類的g方法時,就可以獲取到我們設置的攔截對象,然后通過 tmp4_1.intercept(this, CGLIB$g$0$Method, CGLIB$emptyArgs, CGLIB$g$0$Proxy) 來實現代理。這里來解釋一下intercept方法的參數含義:

@para1 obj :代理對象本身

@para2 method : 被攔截的方法對象

@para3 args:方法調用入參

@para4 proxy:用于調用被攔截方法的方法代理對象

這里會有一個疑問,為什么不直接反射調用代理類生成的(CGLIB$g$0)來間接調用目標類的被攔截方法,而使用proxy的invokeSuper方法呢?這里就涉及到了另外一個點— FastClass 。

三、Fastclass 機制分析

Jdk動態代理的攔截對象是通過反射的機制來調用被攔截方法的,反射的效率比較低,所以cglib采用了FastClass的機制來實現對被攔截方法的調用。FastClass機制就是對一個類的方法建立索引,通過索引來直接調用相應的方法,下面用一個小例子來說明一下,這樣比較直觀

public class test10 { public static void main(String[] args){Test tt = new Test();Test2 fc = new Test2();int index = fc.getIndex('f()V');fc.invoke(index, tt, null); }}class Test{ public void f(){System.out.println('f method'); }public void g(){System.out.println('g method'); }}class Test2{ public Object invoke(int index, Object o, Object[] ol){Test t = (Test) o;switch(index){case 1: t.f(); return null;case 2: t.g(); return null;}return null; }public int getIndex(String signature){switch(signature.hashCode()){case 3078479: return 1;case 3108270: return 2;}return -1; }}

上例中,Test2是Test的Fastclass,在Test2中有兩個方法getIndex和invoke。在getIndex方法中對Test的每個方法建立索引,并根據入參(方法名+方法的描述符)來返回相應的索引。Invoke根據指定的索引,以ol為入參調用對象O的方法。這樣就避免了反射調用,提高了效率。代理類(Target$$EnhancerByCGLIB$$788444a0)中與生成Fastclass相關的代碼如下:

Class localClass1 = Class.forName('net.sf.cglib.test.Target$$EnhancerByCGLIB$$788444a0');localClass2 = Class.forName('net.sf.cglib.test.Target');CGLIB$g$0$Proxy = MethodProxy.create(localClass2, localClass1, '()V', 'g', 'CGLIB$g$0');

MethodProxy中會對localClass1和localClass2進行分析并生成FastClass,然后再使用getIndex來獲取方法g 和 CGLIB$g$0的索引,具體的生成過程將在后續進行介紹,這里介紹一個關鍵的內部類:

private static class FastClassInfo {FastClass f1; // net.sf.cglib.test.Target的fastclassFastClass f2; // Target$$EnhancerByCGLIB$$788444a0 的fastclassint i1; //方法g在f1中的索引int i2; //方法CGLIB$g$0在f2中的索引 }

MethodProxy 中invokeSuper方法的代碼如下:

FastClassInfo fci = fastClassInfo; return fci.f2.invoke(fci.i2, obj, args);

當調用invokeSuper方法時,實際上是調用代理類的CGLIB$g$0方法,CGLIB$g$0直接調用了目標類的g方法。所以,在第一節示例代碼中我們使用invokeSuper方法來調用被攔截的目標類方法。

至此,我們已經了解cglib動態代理的工作原理,接下來會對cglib的相關源碼進行分析。

以上就是Java cglib動態代理原理分析的詳細內容,更多關于Java cglib動態代理原理的資料請關注好吧啦網其它相關文章!

標簽: Java
相關文章:
日本不卡不码高清免费观看,久久国产精品久久w女人spa,黄色aa久久,三上悠亚国产精品一区二区三区
欧美gv在线| 久久久久久黄| 快she精品国产999| 午夜国产精品视频免费体验区| 日韩欧美一区二区三区在线视频 | 天堂成人国产精品一区| 欧美精品自拍| 国产视频一区免费看| 亚洲欧美日韩国产综合精品二区| 午夜欧美在线| 亚洲一区二区动漫| 亚洲影视一区| 日韩av一区二区在线影视| 日韩国产91| 久久99性xxx老妇胖精品| 精品国产亚洲一区二区三区在线 | 亚洲天堂av影院| 日本精品在线中文字幕| 午夜日本精品| 亚洲精品裸体| 国产精品日韩精品中文字幕| 九九久久国产| 久久精选视频| 免费人成精品欧美精品| 青草综合视频| 久久精品一区二区国产| 日韩网站中文字幕| 中文一区在线| 国产日产精品_国产精品毛片| 国产激情一区| 日本国产精品| 日日夜夜免费精品| 国产精品亚洲片在线播放| 人在线成免费视频| 国产模特精品视频久久久久| 欧美色综合网| 国产中文欧美日韩在线| 国产真实久久| 日韩久久一区| 日韩精品永久网址| 亚洲人成高清| 91亚洲人成网污www| 中文亚洲免费| 老司机免费视频一区二区| 99久久夜色精品国产亚洲1000部| 日韩精品免费视频一区二区三区 | 国产黄色精品| 久久国产亚洲精品| 日本欧美在线| 日韩一区二区在线免费| 日韩三级一区| 午夜精品久久久久久久久久蜜桃| 免费人成精品欧美精品| 国产精品不卡| 亚洲丝袜啪啪| yellow在线观看网址| 偷拍欧美精品| 开心激情综合| 亚洲开心激情| 日韩成人亚洲| 91精品丝袜国产高跟在线| 97se综合| 日韩一区精品| 久久精品免费一区二区三区 | 日韩精品免费一区二区三区| 日韩精品一区二区三区中文在线 | 热久久免费视频| 国产一区二区三区四区| 亚洲综合日韩| 国产精品99视频| 热久久久久久| 欧美日韩四区| 麻豆视频在线看| 日韩精品五月天| 欧美日韩精品免费观看视欧美高清免费大片 | 日本蜜桃在线观看视频| 久久国产欧美日韩精品| 国产韩日影视精品| 精品国产乱码久久久久久樱花| 国产精品普通话对白| 日韩一区欧美| 日本在线不卡视频一二三区| 久久精品动漫| 国产 日韩 欧美 综合 一区| 天堂av一区| 欧美成人综合| 黑人精品一区| 国产福利一区二区精品秒拍 | 国产成人77亚洲精品www| 日本精品一区二区三区在线观看视频| 蜜桃一区二区三区| 都市激情国产精品| 国产日韩欧美一区| 亚洲精品激情| 国产亚洲精品v| 在线看片福利| 麻豆精品99| 国产精品一在线观看| 综合一区二区三区| 亚洲激情欧美| 亚洲福利免费| 久久精品观看| 久久精品二区三区| 久久久精品日韩| а√在线中文在线新版| 成人在线免费观看91| 久久一区亚洲| 国产精品观看| 国产伦精品一区二区三区千人斩 | 国精品产品一区| 欧美精品1区| 欧美欧美黄在线二区| 在线精品亚洲| 亚洲无线观看| 日韩综合一区二区| 午夜精品影视国产一区在线麻豆| 夜夜精品视频| 99国产精品| 在线亚洲精品| 亚洲精品888| 日韩视频中文| 三级在线观看一区二区| 老牛国产精品一区的观看方式| 激情久久五月| 九一成人免费视频| 国产一区清纯| 欧美另类综合| 婷婷综合社区| 欧美在线综合| 亚洲精品精选| 日韩福利视频一区| 国产欧美精品| 精品久久国产一区| 日韩欧美精品| 99riav1国产精品视频| 一区二区91| 国产欧美日韩在线一区二区| 国产高清视频一区二区| 麻豆国产欧美日韩综合精品二区| 麻豆精品一区二区综合av| 国产成人免费| 亚洲精品.com| 丝袜美腿成人在线| 欧美日韩一区二区三区不卡视频 | 日韩精品一区二区三区中文字幕| 日韩av三区| 精品三级在线观看视频| 亚洲黄色网址| 在线精品小视频| 在线免费观看亚洲| 欧美一区成人| 日韩av免费大片| 国产综合色产| 日韩毛片网站| 成人国产精选| 欧美日韩视频| 青草久久视频| 韩国三级一区| 亚洲精品乱码| 国产91在线播放精品| 91成人精品| 日韩超碰人人爽人人做人人添| 免费一级欧美在线观看视频 | 欧美日韩网址| 日韩高清中文字幕一区二区| 亚洲免费影院| 国产精品香蕉| 久久久夜精品| 亚洲精品欧美| 国产aⅴ精品一区二区三区久久| 亚洲黑丝一区二区| 日韩综合一区二区| 超级白嫩亚洲国产第一| 亚洲一区二区动漫| 免费看久久久| av不卡免费看| 精品美女久久| 视频小说一区二区| 四虎精品永久免费| 欧美天堂视频| 中文字幕日本一区二区| 欧美韩日一区| 天堂俺去俺来也www久久婷婷| 成人日韩精品| 欧美天堂在线| 精品欧美激情在线观看| 国产精品mv在线观看| 国产精品腿扒开做爽爽爽挤奶网站| 久久亚洲国产精品尤物| 天使萌一区二区三区免费观看| 精品国产99| 视频在线在亚洲| 国产精品99精品一区二区三区∴| 欧美日韩免费观看一区=区三区 | 久久99精品久久久野外观看| 欧美日韩少妇| 精品国产亚洲一区二区三区大结局| 免费日韩av片| 岛国av在线网站| 欧美一区自拍|