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

您的位置:首頁(yè)技術(shù)文章
文章詳情頁(yè)

Java cglib動(dòng)態(tài)代理原理分析

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

本文分下面三個(gè)部分來(lái)分析cglib動(dòng)態(tài)代理的原理。

cglib 動(dòng)態(tài)代理示例 代理類(lèi)分析 Fastclass 機(jī)制分析一、cglib 動(dòng)態(tài)代理示例

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方法來(lái)調(diào)用目標(biāo)類(lèi)的方法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'); //實(shí)例化一個(gè)增強(qiáng)器,也就是cglib中的一個(gè)class generatorEnhancer eh = new Enhancer(); //設(shè)置目標(biāo)類(lèi)eh.setSuperclass(Target.class);// 設(shè)置攔截對(duì)象eh.setCallback(new Interceptor());// 生成代理類(lèi)并返回一個(gè)實(shí)例Target t = (Target) eh.create();t.f();t.g(); }}

運(yùn)行結(jié)果為:

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

與JDK動(dòng)態(tài)代理相比,cglib可以實(shí)現(xiàn)對(duì)一般類(lèi)的代理而無(wú)需實(shí)現(xiàn)接口。在上例中通過(guò)下列步驟來(lái)生成目標(biāo)類(lèi)Target的代理類(lèi):

創(chuàng)建Enhancer實(shí)例 通過(guò)setSuperclass方法來(lái)設(shè)置目標(biāo)類(lèi) 通過(guò)setCallback 方法來(lái)設(shè)置攔截對(duì)象 create方法生成Target的代理類(lèi),并返回代理類(lèi)的實(shí)例 二、代理類(lèi)分析

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

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

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

代理類(lèi)(Target$$EnhancerByCGLIB$$788444a0)繼承了目標(biāo)類(lèi)(Target),至于代理類(lèi)實(shí)現(xiàn)的factory接口與本文無(wú)關(guān),殘忍無(wú)視。代理類(lèi)為每個(gè)目標(biāo)類(lèi)的方法生成兩個(gè)方法,例如針對(duì)目標(biāo)類(lèi)中的每個(gè)非private方法,代理類(lèi)會(huì)生成兩個(gè)方法,以g方法為例:一個(gè)是@Override的g方法,一個(gè)是CGLIB$g$0(CGLIB$g$0相當(dāng)于目標(biāo)類(lèi)的g方法)。我們?cè)谑纠a中調(diào)用目標(biāo)類(lèi)的方法t.g()時(shí),實(shí)際上調(diào)用的是代理類(lèi)中的g()方法。接下來(lái)我們著重分析代理類(lèi)中的g方法,看看是怎么實(shí)現(xiàn)的代理功能。

當(dāng)調(diào)用代理類(lèi)的g方法時(shí),先判斷是否已經(jīng)存在實(shí)現(xiàn)了MethodInterceptor接口的攔截對(duì)象,如果沒(méi)有的話(huà)就調(diào)用CGLIB$BIND_CALLBACKS方法來(lái)獲取攔截對(duì)象,CGLIB$BIND_CALLBACKS的反編譯結(jié)果如下:

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

為了方便閱讀,等價(jià)的代碼如下:

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中g(shù)et攔截對(duì)象,如果獲取不到的話(huà),再?gòu)腃GLIB$STATIC_CALLBACKS來(lái)獲取,如果也沒(méi)有則認(rèn)為該方法不需要代理。

那么攔截對(duì)象是如何設(shè)置到CGLIB$THREAD_CALLBACKS 或者 CGLIB$STATIC_CALLBACKS中的呢?

在Jdk動(dòng)態(tài)代理中攔截對(duì)象是在實(shí)例化代理類(lèi)時(shí)由構(gòu)造函數(shù)傳入的,在cglib中是調(diào)用Enhancer的firstInstance方法來(lái)生成代理類(lèi)實(shí)例并設(shè)置攔截對(duì)象的。firstInstance的調(diào)用軌跡為:

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

在第5步,調(diào)用了代理類(lèi)的CGLIB$SET_THREAD_CALLBACKS來(lái)完成攔截對(duì)象的注入。下面我們看一下CGLIB$SET_THREAD_CALLBACKS的反編譯結(jié)果:

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方法中調(diào)用了CGLIB$THREAD_CALLBACKS的set方法來(lái)保存攔截對(duì)象,在CGLIB$BIND_CALLBACKS方法中使用了CGLIB$THREAD_CALLBACKS的get方法來(lái)獲取攔截對(duì)象,并保存到CGLIB$CALLBACK_0中。這樣,在我們調(diào)用代理類(lèi)的g方法時(shí),就可以獲取到我們?cè)O(shè)置的攔截對(duì)象,然后通過(guò) tmp4_1.intercept(this, CGLIB$g$0$Method, CGLIB$emptyArgs, CGLIB$g$0$Proxy) 來(lái)實(shí)現(xiàn)代理。這里來(lái)解釋一下intercept方法的參數(shù)含義:

@para1 obj :代理對(duì)象本身

@para2 method : 被攔截的方法對(duì)象

@para3 args:方法調(diào)用入?yún)?/p>

@para4 proxy:用于調(diào)用被攔截方法的方法代理對(duì)象

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

三、Fastclass 機(jī)制分析

Jdk動(dòng)態(tài)代理的攔截對(duì)象是通過(guò)反射的機(jī)制來(lái)調(diào)用被攔截方法的,反射的效率比較低,所以cglib采用了FastClass的機(jī)制來(lái)實(shí)現(xiàn)對(duì)被攔截方法的調(diào)用。FastClass機(jī)制就是對(duì)一個(gè)類(lèi)的方法建立索引,通過(guò)索引來(lái)直接調(diào)用相應(yīng)的方法,下面用一個(gè)小例子來(lái)說(shuō)明一下,這樣比較直觀

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中有兩個(gè)方法getIndex和invoke。在getIndex方法中對(duì)Test的每個(gè)方法建立索引,并根據(jù)入?yún)ⅲǚ椒?方法的描述符)來(lái)返回相應(yīng)的索引。Invoke根據(jù)指定的索引,以ol為入?yún)⒄{(diào)用對(duì)象O的方法。這樣就避免了反射調(diào)用,提高了效率。代理類(lèi)(Target$$EnhancerByCGLIB$$788444a0)中與生成Fastclass相關(guān)的代碼如下:

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中會(huì)對(duì)localClass1和localClass2進(jìn)行分析并生成FastClass,然后再使用getIndex來(lái)獲取方法g 和 CGLIB$g$0的索引,具體的生成過(guò)程將在后續(xù)進(jìn)行介紹,這里介紹一個(gè)關(guān)鍵的內(nèi)部類(lèi):

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

當(dāng)調(diào)用invokeSuper方法時(shí),實(shí)際上是調(diào)用代理類(lèi)的CGLIB$g$0方法,CGLIB$g$0直接調(diào)用了目標(biāo)類(lèi)的g方法。所以,在第一節(jié)示例代碼中我們使用invokeSuper方法來(lái)調(diào)用被攔截的目標(biāo)類(lèi)方法。

至此,我們已經(jīng)了解cglib動(dòng)態(tài)代理的工作原理,接下來(lái)會(huì)對(duì)cglib的相關(guān)源碼進(jìn)行分析。

以上就是Java cglib動(dòng)態(tài)代理原理分析的詳細(xì)內(nèi)容,更多關(guān)于Java cglib動(dòng)態(tài)代理原理的資料請(qǐng)關(guān)注好吧啦網(wǎng)其它相關(guān)文章!

標(biāo)簽: Java
相關(guān)文章:
日本不卡不码高清免费观看,久久国产精品久久w女人spa,黄色aa久久,三上悠亚国产精品一区二区三区
免费在线小视频| 精品午夜av| 日本aⅴ亚洲精品中文乱码| 欧美专区18| 麻豆视频在线看| 欧美亚洲一级| 国产中文一区| 精品资源在线| 麻豆久久精品| 久久亚洲在线| 精品国产亚洲日本| 天堂va在线高清一区| 欧美综合另类| 丰满少妇一区| 日韩精品久久理论片| 99久久亚洲精品蜜臀| 午夜在线精品| 亚洲午夜精品久久久久久app| 国产精品玖玖玖在线资源| 午夜在线精品| 红桃视频欧美| 美女网站一区| 欧美日韩国产亚洲一区| 日韩国产网站| 久久久久国产一区二区| 国产精品99一区二区三| 日韩欧美在线精品| 亚洲一区二区三区四区五区午夜| 电影天堂国产精品| 99成人在线视频| 日韩一级精品| 美女久久久久| 美女国产精品| 日韩福利视频一区| 国产精品欧美在线观看| 欧美有码在线| 捆绑调教美女网站视频一区| 久久精品国产亚洲一区二区三区| 国产精品3区| 精品成人18| 欧美特黄一级大片| 久久www成人_看片免费不卡| 亚洲一级淫片| 国产日韩欧美三级| 色网在线免费观看| 在线视频亚洲欧美中文| 在线国产一区| 在线观看视频免费一区二区三区| 午夜久久美女| 麻豆精品一区二区综合av| 国产精品欧美三级在线观看| 免费在线观看一区| 丝袜诱惑一区二区| 亚洲精品伊人| 婷婷精品在线| 亚洲精品成人一区| 性欧美精品高清| 99视频一区| 亚洲国产专区校园欧美| 欧美日本三区| 日韩一区精品视频| 午夜精品网站| 成人在线黄色| 欧美久久天堂| 国产一区二区三区91| 日韩精品久久久久久久软件91| 亚洲精品88| 久久影院资源站| 欧美亚洲三区| 欧美一区影院| 日产欧产美韩系列久久99| 免费不卡中文字幕在线| 偷拍精品精品一区二区三区| 欧美xxxx性| 青青草国产成人99久久| 午夜欧美精品| 亚洲影院天堂中文av色| 欧美亚洲一区二区三区| 国产欧美日韩一区二区三区在线| 亚洲毛片网站| 男人的天堂久久精品| 欧美精品高清| 国产白浆在线免费观看| 国产日产精品一区二区三区四区的观看方式| 亚洲一区二区免费看| 国产精品对白久久久久粗| 国产精品一区二区三区av| 欧美日韩xxxx| 久久99久久久精品欧美| 精品国产乱码久久久久久樱花| 精品国产成人| 国产精品伦理久久久久久| 91av亚洲| 免费在线观看一区| 少妇精品久久久| 最新亚洲一区| 视频一区国产视频| 国产精品一卡| 1024精品一区二区三区| 免费看黄色91| 亚洲青青久久| 亚洲播播91| 亚洲色图综合| 国产精品福利在线观看播放| 亚洲精品乱码| 亚洲视频二区| 国产日韩欧美中文在线| 成人三级高清视频在线看| 国产欧美日韩影院| 国产精品三p一区二区| 国产欧美大片| 日韩欧美二区| 亚洲成人va| 成人国产精品一区二区免费麻豆| 蜜桃免费网站一区二区三区| 亚洲精品极品少妇16p| 国产一区二区三区视频在线| 久久国产精品色av免费看| 日韩在线麻豆| 黑丝一区二区| 中文精品电影| 日韩三级精品| 欧美va天堂在线| 美女久久精品| 日韩一区二区三免费高清在线观看 | 日韩国产一区二区| 亚洲精品影院在线观看| 97精品国产一区二区三区| 久久久一本精品| 国产中文在线播放| 国产精品v亚洲精品v日韩精品 | 久久天堂影院| 久久久亚洲一区| 日韩精品一二三四| 羞羞答答国产精品www一本| 99精品一区| 国产精品嫩草影院在线看| 日本欧美大码aⅴ在线播放| 激情久久婷婷| 日韩极品在线观看| 国产欧美精品久久| 美女国产精品| 欧美影院三区| 日本欧美在线看| 国产精品午夜av| 精精国产xxxx视频在线播放| 亚洲大全视频| 日韩av一区二| 国产 日韩 欧美 综合 一区 | 美日韩精品视频| 国产精品一区二区精品| 99精品在线观看| 日本中文字幕一区二区视频| 麻豆视频在线看| 在线综合亚洲| 国产精品多人| 伊人久久成人| 国产精品红桃| 亚洲一区日韩在线| 欧美精品第一区| 极品日韩av| 精品一区二区三区在线观看视频| 美女少妇全过程你懂的久久| 久久国产精品美女| 西西人体一区二区| 日本免费一区二区三区四区| 日韩高清不卡一区| 午夜电影亚洲| 精品美女在线视频| 欧美日韩国产免费观看视频| 国产精品麻豆成人av电影艾秋| 亚洲午夜电影| 久久麻豆视频| 日韩激情视频网站| 另类亚洲自拍| 一区二区三区视频免费观看| 欧美激情网址| 青青草国产精品亚洲专区无| 亚洲一区区二区| 亚洲夜间福利| 超碰成人av| 久久99青青| 国产亚洲精品美女久久久久久久久久| 在线亚洲激情| 欧美香蕉视频| 美女久久99| 日本成人中文字幕在线视频| 蜜桃视频欧美| 日韩精品网站| 国语对白精品一区二区| 国产亚洲欧美日韩精品一区二区三区 | 欧美黄色一区二区| 最新国产精品久久久| 99视频精品全部免费在线视频| 国产一区二区三区亚洲| 91精品麻豆| 少妇高潮一区二区三区99| 99国内精品| 国产在线成人| 99亚洲视频|