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