-
動態(tài)代理實現(xiàn)思路
實現(xiàn)功能;通過Proxy的newProxyInstance返回代理對象
1.聲明一段源碼(動態(tài)產(chǎn)生代理)
2.編譯源碼(JDK Compiler API),產(chǎn)生新的類(代理類)
3.將這個類load到內(nèi)存當(dāng)中,產(chǎn)生一個新的對象(代理對象)
4.return 代理對象查看全部 -
設(shè)計模式——代理模式(具備面向?qū)ο蟮脑O(shè)計思維、了解多態(tài)、反射機制)
一、基本概念及分類
????1、定義:為其他對象提供一種代理以控制對這個對象的訪問(購買火車票去代售網(wǎng)點、找代理),代理對象起到中介作用,可去掉功能服務(wù)或增加額外服務(wù)。
????2、常見的代理模式
????????(1)遠(yuǎn)程代理:為不同地理的對象提供局域網(wǎng)代表對象(客戶端、服務(wù)器等)
?????????????????例如:連鎖店查看門店經(jīng)營情況(通過遠(yuǎn)程代理可以監(jiān)控各個店鋪,使之能直觀地了解店內(nèi)信息)
????????(2)虛擬代理:格局需要將資源消耗很大的對象進行延遲,真正需要的時候進行創(chuàng)建
???????????????? 例如:瀏覽網(wǎng)頁中的圖片時以默認(rèn)圖片顯示,當(dāng)圖片加載完成后再查看
????????(3)智能引用代理:提供給目標(biāo)對象一些額外的服務(wù)
?????????????????例如:火車票代售處、日志處理、權(quán)限管理、事務(wù)處理...
????????(4)保護代理:控制對一個對象的訪問權(quán)限
???????????????? 例如:瀏覽網(wǎng)頁時,普通用戶只有瀏覽權(quán)限,當(dāng)用戶注冊登錄后,才可以進行發(fā)帖、刪除、評論等操作
二、開發(fā)中的應(yīng)用場景
三、實現(xiàn)方式(以智能引用代理為例)
????1、靜態(tài)代理:代理和被代理對象在代理之前是確定的,它們都實現(xiàn)相同的接口或者繼承相同的抽象類。
????????實現(xiàn)例子:車輛在公路上行駛,通過代理實現(xiàn)車輛行駛的方法,增加一個記錄車輛行駛的方法
? ?不使用代理正常實現(xiàn):
public?interface?Moveable{ ????void?move(); } public?class?Car?implements?Moveable{ ???? ????@Override ????public?void?move(){ ????????long?starttime?=?System.currentTimeMillis(); ???????????System.out.println("汽車開始行駛..."); ???????????//實現(xiàn)開車 ???????????try{ ???????????????Thread.sleep(new?Random().nextInt(1000)); ???????????????System.out.println("汽車行駛中..."); ???????????}catch(InterruptedException?e){ ???????????????e.printStackTrace(); ???????????} ???????????long?endtime?=?System.currentTimeMillis(); ???????????System.out.println("汽車結(jié)束行駛...汽車行駛時間:"+(endtime?-?starttime)?+?"毫秒"); ????} } public?class?Client{ ????public?static?void?main(String[]?args){ ????????Car?car?=?new?Car(); ????????car.move(); ????} }
? ? (1)通過繼承的方式實現(xiàn):
public?interface?Moveable{ ???void?move(); } public?class?Car?implements?Moveable{ ??? ???@Override ???public?void?move(){ ???????????//實現(xiàn)開車 ???????????try{ ???????????????Thread.sleep(new?Random().nextInt(1000)); ???????????????System.out.println("汽車行駛中..."); ???????????}catch(InterruptedException?e){ ???????????????e.printStackTrace(); ???????????} ???} } public?calss?Car2?extends?Car{ ????@Override ???????public?void?move(){ ???????????long?starttime?=?System.currentTimeMillis(); ???????????System.out.println("汽車開始行駛..."); ???????????super.move(); ???????????long?endtime?=?System.currentTimeMillis(); ???????????System.out.println("汽車結(jié)束行駛...汽車行駛時間:"+(endtime?-?starttime)?+?"毫秒"); ???????} } public?class?Client{ ???public?static?void?main(String[]?args){ ???????Moveable?m?=?new?Car2(); ???????m.move(); ???} }
? ? (2)通過聚合(一個類當(dāng)中調(diào)用另一個對象)的方式實現(xiàn):
public?interface?Moveable{ ???void?move(); } public?class?Car?implements?Moveable{ ???@Override ???public?void?move(){ ???????????//實現(xiàn)開車 ???????????try{ ???????????????Thread.sleep(new?Random().nextInt(1000)); ???????????????System.out.println("汽車行駛中..."); ???????????}catch(InterruptedException?e){ ???????????????e.printStackTrace(); ???????????} ???} } public?calss?Car3?implements?Moveable{ ???private?Car?car; ??? ???public?Car3(Car?car){ ???????super(); ???????this.car?=?car; ???} ???@Override ???????public?void?move(){ ???????????long?starttime?=?System.currentTimeMillis(); ???????????System.out.println("汽車開始行駛..."); ???????????car.move(); ???????????long?endtime?=?System.currentTimeMillis(); ???????????System.out.println("汽車結(jié)束行駛...汽車行駛時間:"+(endtime?-?starttime)?+?"毫秒"); ???????} } public?class?Client{ ???public?static?void?main(String[]?args){ ???????Car?car?=?new?Car(); ???????Moveable?m?=?new?Car3(car); ???????m.move(); ???} }
????
思考:通過繼承和聚合兩種方式都能實現(xiàn)靜態(tài)代理,但究竟哪種方式更好呢?
????????以上是在實現(xiàn)對象方法move()的外層添加方法運行時間處理功能,想要增加權(quán)限管理、增加日志處理實現(xiàn)功能的疊加,通過兩種方式示例:
????(1)通過繼承方式實現(xiàn)(代理類會無限膨脹下去)
????????????先記錄日志,再記錄時間:需要先創(chuàng)建類Car4繼承Car2或者Car,在move()方法前后先記錄日志,再記錄時間;
????????????先記錄時間,再記錄日志:需要先創(chuàng)建類Car5繼承Car2或者Car,在move()方法前后先記錄時間,再記錄日志;
????????????先處理權(quán)限,再記錄日志,再記錄時間:需要先創(chuàng)建類Car6繼承Car2或者Car,先處理權(quán)限,再記錄日志,再記錄時間;
????????????先處理權(quán)限,再記錄時間,再記錄日志:需要先創(chuàng)建類Car7繼承Car2或者Car,先處理權(quán)限,再記錄時間,再記錄日志;
?????(2)通過聚合方式實現(xiàn)?(代理類實現(xiàn)相同的接口,且代理之間相互傳遞、組合)
public?interface?Moveable{ ???void?move(); } public?class?Car?implements?Moveable{ ???@Override ???public?void?move(){ ???????????//實現(xiàn)開車 ???????????try{ ???????????????Thread.sleep(new?Random().nextInt(1000)); ???????????????System.out.println("汽車行駛中..."); ???????????}catch(InterruptedException?e){ ???????????????e.printStackTrace(); ???????????} ???} } public?calss?CarTimeProxy?implements?Moveable{ ???private?Moveable?m; ??? ???public?CarTimeProxy?(Moveable?m){ ???????super(); ???????this.m?=?m; ???} ???@Override ???????public?void?move(){ ???????????long?starttime?=?System.currentTimeMillis(); ???????????System.out.println("汽車開始行駛..."); ???????????m.move(); ???????????long?endtime?=?System.currentTimeMillis(); ???????????System.out.println("汽車結(jié)束行駛...汽車行駛時間:"+(endtime?-?starttime)?+?"毫秒"); ???????} } public?calss?CarLogProxy?implements?Moveable{??? ????private?Moveable?m;?????? ????public?CarLogProxy?(Moveable?m){??????? ????????super();??????? ????????this.m?=?m;??? ????}??? ????@Override??????? ????public?void?move(){??????????? ????????System.out.println("日志開始...");?????????? ????????m.move();??????????? ????????System.out.println("日志結(jié)束...");??????? ????} ?} ?public?class?Client{??? ?????public?static?void?main(String[]?args){??????? ?????????Car?car?=?new?Car();??????? ?????????//先記錄日志,再記錄時間??????? ?????????CarTimeProxy?ctp?=?new?CarTimeProxy?(car);???????? ?????????CarLogProxy??clp?=?new?CarLogProxy?(ctp);?????????????? ?????????clp.move();???????????? ?????????//先記錄時間,再記錄日志???????? ?????????CarLogProxy??clp?=?new?CarLogProxy?(car);??????????? ?????????CarTimeProxy?ctp?=?new?CarTimeProxy?(car);???????? ?????????ctp?.move();? ?????}?? ?}
????思考:不同的類(Car,Train)實現(xiàn)相同的代理(TimeProxy,LogProxy)怎樣實現(xiàn)(如果用靜態(tài)代理的聚合方式實現(xiàn),每增加一個類就要新創(chuàng)建新類的TimeProxy,LogProxy代理類,造成類膨脹)?
????有沒有一種方法:能夠動態(tài)產(chǎn)生代理,實現(xiàn)對不同類、不同方法的代理——動態(tài)代理
? ? 2、動態(tài)代理(在代理類與被代理類之間加入了實現(xiàn)InvocationHandler【事務(wù)處理器】類)
????????(一)JDK動態(tài)代理
????????????Java動態(tài)代理類位于java.lang.reflect包下,一般主要涉及到以下兩個類:
????????????(1)Interface Invocationhandler:該接口中僅定義了一個方法
???????????????????? public Object invoke(Object obj,Method method, Object[] args)
?????????????????????在實際使用中,參數(shù)obj一般是指代理類,method是被代理的方法,args為該方法的參數(shù)數(shù)組。這個抽象方法在代理類中動態(tài)實現(xiàn)。
????????????(2)Proxy:該類即為動態(tài)代理類
???????????????????? static Object newProxyInstance(ClassLoader loader, Class[] interfaces, InvocationHandler h) :返回代理類的一個實例,返回后的代理類可以當(dāng)做被代理類使用(可使用被代理類的在接口中聲明過的方法)
????????JDK動態(tài)代理代碼實現(xiàn):
public?interface?Moveable{ ??void?move(); } public?class?Car?implements?Moveable{ ??@Override ??public?void?move(){ ??????????//實現(xiàn)開車 ??????????try{ ??????????????Thread.sleep(new?Random().nextInt(1000)); ??????????????System.out.println("汽車行駛中..."); ??????????}catch(InterruptedException?e){ ??????????????e.printStackTrace(); ??????????} ??} } public?class?TimeHandler?implements?InvocationHandler{ ???private?Object?target; ???public?TimeHandler(Object?target){ ???????super(); ???????this.target?=?target; ???} ???/* ???*參數(shù): ???*proxy:被代理的對象 ???*method:被代理對象的方法 ???*args:方法的參數(shù) ???*返回值: ???*Object:方法的返回值 ???*/ ???@Override ???public?Object?invoke(Object?proxy,Method?method,Object[]?args)?throw?Throwable{ ???????long?starttime?=?System.currentTimeMillis(); ???????System.out.println("汽車開始行駛..."); ???????method.invoke(target); ???????long?endtime?=?System.currentTimeMillis(); ???????System.out.println("汽車結(jié)束行駛...汽車行駛時間:"+(endtime?-?starttime)?+?"毫秒"); ???} } //JDK動態(tài)代理測試 public?class?Test{ ???public?static?void?main(String[]?args){ ???????Car?car?=?new?Car(); ???????InvocationHandler?h?=?new?TimeHandler(car); ???????Class<?>?cls?=?car.getClass(); ???????/* ???????*參數(shù): ???????*loader:類加載器 ???????*interfaces:實現(xiàn)接口 ???????*h:實現(xiàn)處理器InvocationHandler? ???????*/ ???????Moveable?m?=?(Moveable)Proxy.newProxyInstance(cls.getClassLoader(),cls.getInterfaces(),h); ???????m.move(); ???} }
????????所謂動態(tài)代理是在運行時生成的class,該class需要實現(xiàn)一組interface,使用動態(tài)代理類時,必須事先InvocationHandler接口。
????????JDK動態(tài)代理實現(xiàn)步驟:
????????1、創(chuàng)建一個實現(xiàn)皆苦InvocationHandler的類,它必須事先invoke()方法;
????????2、創(chuàng)建被代理的類及接口;
????????3、調(diào)用Proxy類的靜態(tài)方法,創(chuàng)建一個代理類;
???????????? static Object newProxyInstance(ClassLoader loader,Class[] interfaces,InvocationHandler h)
????????4、通過代理調(diào)用方法。
????????實現(xiàn)作業(yè):實現(xiàn)Car類的多個動態(tài)代理類(記錄日志、時間)
實現(xiàn)作業(yè):實現(xiàn)Car類的多個動態(tài)代理類(記錄日志、時間)
????????(二)CGLIB動態(tài)代理
????????JDK動態(tài)代理與CGLIB動態(tài)代理的區(qū)別:
????????JDK動態(tài)代理:
????????????1、只能代理實現(xiàn)了接口的類;
????????????2、沒有實現(xiàn)接口的類不能實現(xiàn)JDK的動態(tài)代理。
????????CGLIB動態(tài)代理:
????????????1、針對類來實現(xiàn)代理的;
????????????2、對指定目標(biāo)類產(chǎn)生一個子類,通過方法攔截技術(shù)攔截所有父類方法的調(diào)用。
????CGLIB動態(tài)代理實現(xiàn)代碼示例(導(dǎo)包:cglib-nodep-2.2.jar):
public?class?Train{ ???public?void?move(){ ???????System.out.println("火車行駛中......") ???} } public?class?CglibProxy?implements?MethodInterceptor{ ???private?Enhancer?enhancer?=?new?Enhancer(); ???public?Object?getProxy(Class?clazz){ ???????//設(shè)置創(chuàng)建子類的類 ???????enhancer.setSuperclass(clazz); ???????enhancer.setCallback(this); ???????return?enhancer.create(); ???} ???/*攔截所有目標(biāo)類方法的調(diào)用 ???*參數(shù): ???*obj:目標(biāo)類的實例 ???*m:目標(biāo)方法的反射對象 ???*args:方法的參數(shù) ???*proxy:代理類的實例 ???*/ ???@Override ???public?Object?intercept(Object?obj,?Method?m,?Object[]?args,MethodProxy?proxy)?throw?Throwable{ ???????System.out.println("日志開始..."); ???????//代理類調(diào)用父類的方法 ???????proxy.invoke(obj,args); ???????System.out.println("日志結(jié)束..."); ???????return?null; ???} } public?class?Test{ ???public?static?void?main(String[]?args){ ???????CglibProxy?proxy?=?new?CglibProxy(); ???????Train?t?=?proxy.getProxy(Train.class); ???????t.move(); ??} }
四、理解JDK動態(tài)代理的實現(xiàn)
?動態(tài)代理實現(xiàn)思路(實現(xiàn)功能:通過Proxy的newProxyInstance返回代理對象)
????1、聲明一段源碼(動態(tài)產(chǎn)生代理)
????2、編譯源碼(JDKCompiler API),產(chǎn)生新的類(代理類)
????3、將這個類load到內(nèi)存當(dāng)中,產(chǎn)生一個新的對象(代理對象)
????4、return代理對象
代碼實現(xiàn):
public?class?Proxy{ ???public?static?Object?newProxyInstance(Class?infce,InvocationHandler?h)?throws?Exception{ ?????String?rt?=?"\r\t"; ?????String?methodStr?=?""; ?????for(Method?m?:?infce.getMethods()){ ????????methodStr?+="@Override"?+?rt?+ ???????"public?void?"+m.getName()+"(){"?+?rt?+ ???????????/* ???????????"long?starttime?=?System.currentTimeMillis();"?+?rt?+ ???????????"System.out.println("汽車開始行駛...");"?+?rt?+ ???????????"m."+m.getName()+"();"?+?rt?+ ???????????"long?endtime?=?System.currentTimeMillis();"?+?rt?+ ???????????"System.out.println("汽車結(jié)束行駛...汽車行駛時間:"+(endtime?-?starttime)?+?"毫秒");"?+?rt?+ ???????????*/ ???????????"try{"?+?rt?+ ???????????????"Method?md?="?+?infce.getName()?+".class.getMethod(\""+m.getName()+"\");"?+?rt?+ ???????????????"h.invoke(this,md);"?+?rt?+ ???????????"}catch(Exceotipn?e){"?+?rt?+ ???????????????"e.printStackTrace();"?+?rt?+ ???????????"}"?+?rt?+ ???????"}"; ???} ???String?str?= ???"public?calss?$Proxy0?implements"?+?infce.getName()+?"{"?+?rt?+ ???????? ????????"public?$Proxy0?(InvocationHandler?h){"?+?rt?+ ?????????"super();"?+?rt?+ ?????????"this.h?=?h;"?+?rt?+ ????????"}"?+?rt?+ ????????"?private?InvocationHandler?h;"?+?rt?+ ????????methodStr??+?rt?+ ???????"}"; ???????//String?filename?=?System.getProperty("user.dir"); ???????//System.out.println(filename);//C:/Proxy???????? ???????//產(chǎn)生代理類的Java文件???????? ???????String?filename?=?System.getProperty("user.dir")+"/bin/com/imooc/proxy/$Proxy0.java"; ???????File?file?=?new?File(filename);???????? ???????//FileUtils(commons-io的jar包下的類)???????? ???????FileUtils.writeStringToFile(file,str);???????? ???????//編譯???????? ???????//拿到編譯器???????? ???????JavaCompiler?compiler?=?ToolProvider.getSystemJavaCompiler();???????? ???????//文件管理者???????? ???????StandardJavaFileManager?fileMgr?=?compiler.getStandardFileManager(null,null,null);? ???????//獲取文件???????? ???????Iterable?units?=?fileMgr.getJavaFileObjects(filename);???????? ???????//編譯任務(wù)???????? ???????CompilationTask?t?=?compiler.getTask(null,fileMgr,null,null,null,units);???????? ???????//進行編譯???????? ???????t.call();???????? ???????fileMgr.close();???????? ???????//load到內(nèi)存???????? ???????ClassLoader?cl?=?ClassLoader.getSystemClassLoader();??????? ????????Class?c?=?cl.loadClass("$Proxy0");???????? ????????Constructor?ctr?=?c.getConstructor(InvocationHandler.class);???????? ????????System.out.println(c.getName());//$Proxy0???????? ????????return?ctr.newInstance(h);?? ????} } /*測試類*/ public?class?Client{???? ???public?static?void?main(String[]?args)?throws?Exception{ ???????Car?car?=?new?Car(); ???????InvocationHandler?h?=?new?TimeHandler(car); ???????Moveable?m?=?(Moveable)Proxy.newProxyInstance(Moveable.class,h);???????? ???????m.move(); ???} } public?class?Test{ ???public?static?void?main(String[]?args){ ???????Car?car?=?new?Car();??????? ???????InvocationHandler?h?=?new?TimeHandler(car);??????? ???????Class<?>?cls?=?car.getClass();??????? ???????/*??????? ???????*參數(shù):??????? ???????*loader:類加載器??????? ???????*interfaces:實現(xiàn)接口??????? ???????*h:實現(xiàn)處理器InvocationHandler???????? ???????*/??????? ???????Moveable?m?=?(Moveable)Proxy.newProxyInstance(cls.getClassLoader(),cls.getInterfaces(),h);??????? ???????System.out.println("代理類名字"?+?m.getClass().getName());//代理類名字$Proxy0??????? ???????m.move();??? ???} }
public?class?InvocationHandler{ ???public?void?invoke(Object?o,Method?m); } public?class?TimeHandler?implements?InvocationHandler{ ???private?O?bject?target; ???public?TimeHandler(Object?target){ ???????this.target?=?target; ???} ???@Override ???public?void?invoke(Object?o,Method?m){ ???????try{ ???????????long?starttime?=?System.currentTimeMillis(); ???????????System.out.println("汽車開始行駛..."); ???????????m.invoke(target); ???????????long?endtime?=?System.currentTimeMillis(); ???????????System.out.println("汽車結(jié)束行駛...汽車行駛時間:"+(endtime?-?starttime)?+?"毫秒"); ???????}catch(Exception?e){ ???????????e.printStackTrace(); ???????} ???} }
五、總結(jié)
查看全部 -
2222222222222222222222222222
查看全部 -
11111111111111111111111111111111
查看全部 -
22222222222222222222222222222222
查看全部 -
555555555555555555555555555
查看全部 -
333333333333333333333333333333333
查看全部 -
3333333333333333333333333333333333
查看全部 -
222222222222222222222222222222222222222
查看全部 -
實現(xiàn)靜態(tài)代理的兩種方式
查看全部 -
靜態(tài)代理的概念
查看全部 -
智能引用代理的兩種實現(xiàn)方式
查看全部 -
常見代理模式
查看全部 -
智能引用代理
查看全部 -
保護代理應(yīng)用
查看全部 -
虛擬代理例子
查看全部 -
虛擬代理概念
查看全部 -
例 子 例 子
查看全部 -
遠(yuǎn) 程 代 理
查看全部 -
常用代理模式
查看全部 -
代理模式基本概念
查看全部 -
代理模式定義
查看全部
舉報