Java中的cglib代理詳解
工作原理
使用
<dependency> <groupId>cglib</groupId> <artifactId>cglib</artifactId> <version>3.3.0</version> </dependency>
對類和接口分別進(jìn)行代理
DemoService
package com.fanqiechaodan.user.service; /** * @author fanqiechaodan * @Classname DemoService * @Description * @Date 2023/3/1 19:44 */ public class DemoService { public void test(){ System.out.println("==================>test"); } }
DemoInterface
package com.fanqiechaodan.user.service; /** * @author fanqiechaodan * @Classname DemoInterface * @Description * @Date 2023/3/1 19:56 */ public interface DemoInterface { void test(); }
Demo
package com.fanqiechaodan.user; import com.fanqiechaodan.user.service.DemoInterface; import com.fanqiechaodan.user.service.DemoService; import net.sf.cglib.proxy.Callback; import net.sf.cglib.proxy.Enhancer; import net.sf.cglib.proxy.MethodInterceptor; /** * @author fanqiechaodan * @Classname Main * @Description * @Date 2023/3/1 19:47 */ public class Demo { public static void main(String[] args) { final DemoService target = new DemoService(); Enhancer enhancer = new Enhancer(); enhancer.setSuperclass(DemoService.class); // 必須設(shè)置callbacks不然會(huì)出現(xiàn)java.lang.NullPointerException enhancer.setCallbacks(new Callback[]{(MethodInterceptor) (o, method, objects, methodProxy) -> { // test方法增強(qiáng)邏輯 if ("test".equals(method.getName())) { System.out.println("方法執(zhí)行前增強(qiáng)..."); Object res = method.invoke(target, objects); System.out.println("方法執(zhí)行后增強(qiáng)..."); return res; } // 其他方法正常執(zhí)行 return method.invoke(target, objects); }}); DemoService demoService = (DemoService) enhancer.create(); demoService.test(); Enhancer enhancer1 = new Enhancer(); enhancer1.setSuperclass(DemoInterface.class); enhancer1.setCallbacks(new Callback[]{(MethodInterceptor) (o, method, objects, methodProxy) -> { // test方法增強(qiáng)邏輯 if ("test".equals(method.getName())) { System.out.println("切面邏輯..."); } return null; }}); DemoInterface demo = (DemoInterface) enhancer1.create(); demo.test(); } }
代碼執(zhí)行前設(shè)置VM options:
-Dcglib.debugLocation=根據(jù)自己實(shí)際情況填寫
運(yùn)行代碼是cglib就會(huì)將生成的代理類放到上面所指定的路徑上.
DemoService代理類
public class DemoService$$EnhancerByCGLIB$$1c9ab053 extends DemoService implements Factory { // 省去不重要代碼... final void CGLIB$test$0() { super.test(); } public final void test() { MethodInterceptor var10000 = this.CGLIB$CALLBACK_0; if (var10000 == null) { CGLIB$BIND_CALLBACKS(this); var10000 = this.CGLIB$CALLBACK_0; } if (var10000 != null) { var10000.intercept(this, CGLIB$test$0$Method, CGLIB$emptyArgs, CGLIB$test$0$Proxy); } else { super.test(); } } // 省去不重要代碼... }
DemoInterface代理類
public class DemoInterface$$EnhancerByCGLIB$$536bfe99 implements DemoInterface, Factory { // 省去不重要代碼... final void CGLIB$test$4() { super.test(); } public final void test() { MethodInterceptor var10000 = this.CGLIB$CALLBACK_0; if (var10000 == null) { CGLIB$BIND_CALLBACKS(this); var10000 = this.CGLIB$CALLBACK_0; } if (var10000 != null) { var10000.intercept(this, CGLIB$test$4$Method, CGLIB$emptyArgs, CGLIB$test$4$Proxy); } else { super.test(); } } // 省去不重要代碼... }
final void CGLIB$test$0() { super.test(); }
這個(gè)方法我們并不能直接調(diào)用,而是要通過所設(shè)置的Callback,也就是MethodInterceptor中的methodProxy來調(diào)用,methodProxy表示方法代理,假如DemoService代理對象在執(zhí)行test()方法,那么當(dāng)執(zhí)行流程進(jìn)入到intercept方法時(shí),methodProxy表示的就是test()方法,DemoService和DemoService代理類中都有test(),所以methodProxy代理的就是這兩個(gè)test()
工作原理:cglib會(huì)根據(jù)所設(shè)置得superclass,生成代理類作為其子類,并且會(huì)重寫superclass中需要代理得方法,比如test(),相應(yīng)得再代理類中會(huì)有兩個(gè)方法,一個(gè)是重寫的test(),用來執(zhí)行增強(qiáng)邏輯,一個(gè)是CGLIB$test$0(),會(huì)直接調(diào)用super.test(),是讓MethodProxy對象來用的
代理類生成邏輯
- DemoService代理類全部代碼
// // Source code recreated from a .class file by IntelliJ IDEA // (powered by Fernflower decompiler) // package com.fanqiechaodan.user.service; 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.Factory; import net.sf.cglib.proxy.MethodInterceptor; import net.sf.cglib.proxy.MethodProxy; public class DemoService$$EnhancerByCGLIB$$1c9ab053 extends DemoService 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$test$0$Method; private static final MethodProxy CGLIB$test$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("com.fanqiechaodan.user.service.DemoService$$EnhancerByCGLIB$$1c9ab053"); 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$test$0$Method = ReflectUtils.findMethods(new String[]{"test", "()V"}, (var1 = Class.forName("com.fanqiechaodan.user.service.DemoService")).getDeclaredMethods())[0]; CGLIB$test$0$Proxy = MethodProxy.create(var1, var0, "()V", "test", "CGLIB$test$0"); } final void CGLIB$test$0() { super.test(); } public final void test() { MethodInterceptor var10000 = this.CGLIB$CALLBACK_0; if (var10000 == null) { CGLIB$BIND_CALLBACKS(this); var10000 = this.CGLIB$CALLBACK_0; } if (var10000 != null) { var10000.intercept(this, CGLIB$test$0$Method, CGLIB$emptyArgs, CGLIB$test$0$Proxy); } else { super.test(); } } final boolean CGLIB$equals$1(Object var1) { return super.equals(var1); } public final boolean equals(Object var1) { MethodInterceptor var10000 = this.CGLIB$CALLBACK_0; if (var10000 == 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; } else { return super.equals(var1); } } final String CGLIB$toString$2() { return super.toString(); } public final String toString() { MethodInterceptor var10000 = this.CGLIB$CALLBACK_0; if (var10000 == 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 (var10000 == 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 (var10000 == 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 -1422510685: if (var10000.equals("test()V")) { return CGLIB$test$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 DemoService$$EnhancerByCGLIB$$1c9ab053() { CGLIB$BIND_CALLBACKS(this); } // 將代碼中設(shè)置的callbacks設(shè)置到CGLIB$THREAD_CALLBACKS這個(gè)ThreadLocal中 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) { DemoService$$EnhancerByCGLIB$$1c9ab053 var1 = (DemoService$$EnhancerByCGLIB$$1c9ab053)var0; if (!var1.CGLIB$BOUND) { var1.CGLIB$BOUND = true; Object var10000 = CGLIB$THREAD_CALLBACKS.get(); if (var10000 == null) { var10000 = CGLIB$STATIC_CALLBACKS; if (var10000 == null) { return; } } var1.CGLIB$CALLBACK_0 = (MethodInterceptor)((Callback[])var10000)[0]; } } public Object newInstance(Callback[] var1) { CGLIB$SET_THREAD_CALLBACKS(var1); DemoService$$EnhancerByCGLIB$$1c9ab053 var10000 = new DemoService$$EnhancerByCGLIB$$1c9ab053(); CGLIB$SET_THREAD_CALLBACKS((Callback[])null); return var10000; } public Object newInstance(Callback var1) { CGLIB$SET_THREAD_CALLBACKS(new Callback[]{var1}); DemoService$$EnhancerByCGLIB$$1c9ab053 var10000 = new DemoService$$EnhancerByCGLIB$$1c9ab053(); CGLIB$SET_THREAD_CALLBACKS((Callback[])null); return var10000; } public Object newInstance(Class[] var1, Object[] var2, Callback[] var3) { CGLIB$SET_THREAD_CALLBACKS(var3); DemoService$$EnhancerByCGLIB$$1c9ab053 var10000 = new DemoService$$EnhancerByCGLIB$$1c9ab053; 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(); } }
代理類中有一個(gè)靜態(tài)代碼塊,會(huì)調(diào)用CGLIB$STATICHOOK1(),這個(gè)方法主要是為了給屬性賦值,例如:
- 構(gòu)造一個(gè)ThreadLocal對象賦值給CGLIB$THREAD_CALLBACKS
- 獲取DemoService類中的test方法的Method對象賦值給CGLIB$test0 00Method
- 構(gòu)造test()方法所對應(yīng)的MethodProxy對象賦值給CGLIB$test0 00Proxy
DemoService的代理類即繼承了DemoService,也實(shí)現(xiàn)了Factory接口,從而就需要實(shí)現(xiàn)Factory接口中的方法
public interface Factory { Object newInstance(Callback callback); Object newInstance(Callback[] callbacks); Object newInstance(Class[] types, Object[] args, Callback[] callbacks); Callback getCallback(int index); void setCallback(int index, Callback callback); void setCallbacks(Callback[] callbacks); Callback[] getCallbacks(); }
newInstance方法會(huì)重新生成一個(gè)代理對象,setCallbacks()和getCallbacks()用來設(shè)置或獲取增強(qiáng)邏輯
代理類大致流程是:
- cglib先生成代理類,具體邏輯為:
- 先生成類的定義,繼承DemoService和實(shí)現(xiàn)Factory
- 根據(jù)DemoService類中的方法生成代理類中對應(yīng)的方法和屬性
- 生成一些輔助的屬性和方法
- 然后調(diào)用構(gòu)造方法得到代理對象
- 然后cglib調(diào)用代理對象的CGLIB$SET_THREAD_CALLBACKS()方法,將我們自己所設(shè)置的callbacks設(shè)置到CGLIB$THREAD_CALLBACKS這個(gè)ThreadLocal中
- 后續(xù)代理對象再執(zhí)行test()方法時(shí),就會(huì)從CGLIB$THREAD_CALLBACKS拿到所設(shè)置的callbacks,調(diào)用其intercept()方法
到此這篇關(guān)于Java中的cglib代理詳解的文章就介紹到這了,更多相關(guān)Java的cglib代理內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
Java獲取兩個(gè)集合List的交集、補(bǔ)集、并集(相加)和差集(相減)的不同方式
這篇文章主要給大家介紹了關(guān)于Java獲取兩個(gè)集合List的交集、補(bǔ)集、并集(相加)和差集(相減)的不同方式,在一般操作中對于list集合取交集、差集、并集,比較簡單,需要的朋友可以參考下2023-08-08Java8新特性之lambda的作用_動(dòng)力節(jié)點(diǎn)Java學(xué)院整理
我們期待了很久lambda為java帶來閉包的概念,但是如果我們不在集合中使用它的話,就損失了很大價(jià)值?,F(xiàn)有接口遷移成為lambda風(fēng)格的問題已經(jīng)通過default methods解決了,在這篇文章將深入解析Java集合里面的批量數(shù)據(jù)操作解開lambda最強(qiáng)作用的神秘面紗。2017-06-06eclipse創(chuàng)建項(xiàng)目沒有dynamic web的解決方法
最近上課要用到eclipse,要用到Dynamic web project.但是我下載的版本上沒有.接下來就帶大家了解 eclipse創(chuàng)建項(xiàng)目沒有dynamic web的解決方法,文中有非常詳細(xì)的圖文示例,需要的朋友可以參考下2021-06-06Java線程池并發(fā)執(zhí)行多個(gè)任務(wù)方式
這篇文章主要介紹了Java線程池并發(fā)執(zhí)行多個(gè)任務(wù)方式,具有很好的參考價(jià)值,希望對大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2022-08-08SpringMvc @RequestParam 使用推薦使用包裝類型代替包裝類型
這篇文章主要介紹了SpringMvc @RequestParam 使用推薦使用包裝類型代替包裝類型,小編覺得挺不錯(cuò)的,現(xiàn)在分享給大家,也給大家做個(gè)參考。一起跟隨小編過來看看吧2019-02-02Java高并發(fā)BlockingQueue重要的實(shí)現(xiàn)類詳解
這篇文章主要給大家介紹了關(guān)于Java高并發(fā)BlockingQueue重要的實(shí)現(xiàn)類的相關(guān)資料,文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧2021-01-01