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