時間:2017年08月28日星期一
說明:本文部分內(nèi)容均來自慕課網(wǎng)。@慕課網(wǎng):http://www.imooc.com
教學源碼:https://github.com/zccodere/s...
學習源碼:https://github.com/zccodere/s...
學習本課程基礎(chǔ)
面向?qū)ο蟮脑O(shè)計思維 了解多態(tài)的概念 了解反射機制
課程目標
代理模式基本概念及分類 了解代理模式開發(fā)中應用場景 掌握代理模式實現(xiàn)方式 理解JDK動態(tài)代理實現(xiàn)
代理模式定義
為其他對象提供一種代理以控制對這個對象的訪問 代理對象起到中介作用,可去掉功能服務或增加額外的服務
常見的幾種代理模式
遠程代理:類似于客戶端服務器這種模式,列一個為不同地理對象提供局域網(wǎng)代表對象 虛擬代理:根據(jù)需要將資源消耗很大的對象進行延遲,真正需要的時候進行創(chuàng)建 保護代理:控制對象的訪問權(quán)限 智能代理:提供對目標對象額外的服務
代理模式示意圖
第二章:常用代理模式 2-1 靜態(tài)代理智能引用代理
靜態(tài)代理 動態(tài)代理
靜態(tài)代理定義
代理和被代理對象在代理之前是確定的。他們都實現(xiàn)相同的接口或者繼承相同的抽象類
靜態(tài)代理類圖
代碼編寫
1.編寫Moveable接口
package com.myimooc.designpattern.c3proxy.car; /** * @describe 可行駛的接口 * @author zc * @version 1.0 2017-08-28 */ public interface Moveable { /** * 行駛的方法 */ void move(); }
2.編寫Car類
package com.myimooc.designpattern.c3proxy.car; import java.util.Random; /** * @describe 一輛車實現(xiàn)可行駛的接口 * @author zc * @version 1.0 2017-08-28 */ public class Car implements Moveable { @Override public void move() { // 記錄汽車行駛的時間 // long starttime = System.currentTimeMillis(); // System.out.println("汽車開始行駛..."); // 實現(xiàn)開車 try { System.out.println("汽車行駛中..."); Thread.sleep(new Random().nextInt(1000)); } catch (InterruptedException e) { // TODO Auto-generated catch block e.printStackTrace(); } // long endtime = System.currentTimeMillis(); // System.out.println("汽車結(jié)束行駛...汽車行駛時間:"+(endtime - starttime) + "毫秒"); } }
3.編寫Car2類
package com.myimooc.designpattern.c3proxy.car; /** * @describe 繼承的方式實現(xiàn)靜態(tài)代理 * @author zc * @version 1.0 2017-08-28 */ public class 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) + "毫秒"); } }
4.編寫Car3類
package com.myimooc.designpattern.c3proxy.car; /** * @describe 聚合的方式實現(xiàn)靜態(tài)代理 * @author zc * @version 1.0 2017-08-28 */ public class Car3 implements Moveable { public Car3(Car car) { super(); this.car = car; } private 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) + "毫秒"); } }
5.編寫Client類
package com.myimooc.designpattern.c3proxy.car; /** * @describe 測試類 * @author zc * @version 1.0 2017-08-28 */ public class Client { public static void main(String[] args) { // test1(); test2(); } // 2-2 聚合與繼承 代理功能疊加測試方法 public static void test2(){ Car car = new Car(); CarLogProxy clp = new CarLogProxy(car); CarTimeProxy ctp = new CarTimeProxy(clp); ctp.move(); } // 2-1 靜態(tài)代理測試方法 public static void test1(){ // Car car = new Car(); // car.move(); // 使用繼承的方式 // Moveable m = new Car2(); // m.move(); // 使用聚合方式 Car car = new Car(); Moveable m = new Car3(car); m.move(); } }2-2 聚合與繼承
場景分析
代理類功能疊加
1.記錄日志 2.記錄時間 3.權(quán)限功能
使用繼承方式
使用繼承方式來實現(xiàn)代理功能的疊加,代理類會無限的膨脹下去,所以這種方式不推薦使用。
使用聚合方式,通過代碼演示
代碼編寫
1.復制Car3命名為CarTimeProxy
package com.myimooc.designpattern.c3proxy.car; /** * @describe 汽車行駛時間的代理 * @author zc * @version 1.0 2017-08-28 */ public class CarTimeProxy implements Moveable { // 因為代理類和被代理類都是實現(xiàn)相同的接口,所以構(gòu)造方法傳遞的對象也可以是Moveable對象 public CarTimeProxy(Moveable m) { super(); this.m = m; } private Moveable m; @Override public void move() { long starttime = System.currentTimeMillis(); System.out.println("汽車開始行駛..."); m.move(); long endtime = System.currentTimeMillis(); System.out.println("汽車結(jié)束行駛...汽車行駛時間:"+(endtime - starttime) + "毫秒"); } }
2.編寫CarLogProxy類
package com.myimooc.designpattern.c3proxy.car; /** * @describe 汽車日志功能的代理 * @author zc * @version 1.0 2017-08-28 */ public class CarLogProxy implements Moveable { // 因為代理類和被代理類都是實現(xiàn)相同的接口,所以構(gòu)造方法傳遞的對象也可以是Moveable對象 public CarLogProxy(Moveable m) { super(); this.m = m; } private Moveable m; @Override public void move() { System.out.println("日志開始"); m.move(); System.out.println("日志結(jié)束"); } }
3.編寫Client類
package com.myimooc.designpattern.c3proxy.car; /** * @describe 測試類 * @author zc * @version 1.0 2017-08-28 */ public class Client { public static void main(String[] args) { // test1(); test2(); } // 2-2 聚合與繼承 代理功能疊加測試方法 public static void test2(){ Car car = new Car(); CarLogProxy clp = new CarLogProxy(car); CarTimeProxy ctp = new CarTimeProxy(clp); ctp.move(); } // 2-1 靜態(tài)代理測試方法 public static void test1(){ // Car car = new Car(); // car.move(); // 使用繼承的方式 // Moveable m = new Car2(); // m.move(); // 使用聚合方式 Car car = new Car(); Moveable m = new Car3(car); m.move(); } }2-3 JDK動態(tài)代理
場景分析
有沒有方法動態(tài)產(chǎn)生代理,實現(xiàn)對不同類,不同方法的代理呢
JDK動態(tài)代理類圖
Java動態(tài)代理類位于java.lang.reflect包下,一般主要涉及到以下兩個類
Interface InvocationHandler:該接口中僅定義了一個方法 public Object invoke(Object obj,Method method,Object[] args) 在實際使用時,第一參數(shù)obj一般是指代理類,method是被代理的方法,args為該方法的參數(shù)數(shù)組。 這個抽象方法在代理類中動態(tài)實現(xiàn)。 Proxy:該類即為動態(tài)代理類 static Object newProxyInstance(ClassLoader loader,Class[] interfaces,InvocationHandler h) 返回代理類的一個實例,返回后的代理類可以當做被代理類使用 (可使用被代理類的在接口中聲明過的方法)
所謂Dynamic Proxy是這樣一種class
它是在運行時生成的class 該class需要實現(xiàn)一組interface 使用動態(tài)代理類時,必須實現(xiàn)InvocationHandler接口
動態(tài)代理實現(xiàn)步驟
1.創(chuàng)建一個實現(xiàn)InvocationHandler接口的類,它必須實現(xiàn)invoke方法 2.創(chuàng)建被代理的類以及接口 3.調(diào)用Proxy的靜態(tài)方法,創(chuàng)建一個代理類 newProxyInstance(ClassLoader loader,Class[] interfaces,InvocationHandler h) 4.通過代理調(diào)用方法
代碼編寫
1.編寫TimeHandler類
package com.myimooc.designpattern.c3proxy.jdk; import java.lang.reflect.InvocationHandler; import java.lang.reflect.Method; /** * @describe 對時間上的處理-使用JDK動態(tài)代理 * @author zc * @version 1.0 2017-08-28 */ public class TimeHandler implements InvocationHandler { public TimeHandler(Object target) { super(); this.target = target; } private Object target; /** * 參數(shù): * proxy 被代理對象 * method 被代理對象方法 * args 方法的參數(shù) * 返回值: * Object 方法的返回值 */ @Override public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { long starttime = System.currentTimeMillis(); System.out.println("汽車開始行駛..."); method.invoke(target); long endtime = System.currentTimeMillis(); System.out.println("汽車結(jié)束行駛...汽車行駛時間:"+(endtime - starttime) + "毫秒"); return null; } }
2.編寫Test類
package com.myimooc.designpattern.c3proxy.jdk; import java.lang.reflect.InvocationHandler; import java.lang.reflect.Proxy; import com.myimooc.designpattern.c3proxy.car.Car; import com.myimooc.designpattern.c3proxy.car.Moveable; /** * @describe JDK動態(tài)代理測試類 * @author zc * @version 1.0 2017-08-28 */ public class Test { public static void main(String[] args) { Car car = new Car(); InvocationHandler h = new TimeHandler(car); Class> cls = car.getClass(); // 使用Proxy類newProxyInstance方法動態(tài)創(chuàng)建代理類 /** * loader 類加載器 * interfaces 實現(xiàn)接口 * h InvocationHandler */ Moveable m = (Moveable)Proxy.newProxyInstance(cls.getClassLoader(), cls.getInterfaces(), h); m.move(); } }2-4 使用cglib
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.對指定目標類產(chǎn)生一個子類,通過方法攔截技術(shù)攔截所有父類方法的調(diào)用 3.因為是使用繼承的方式,所以不能對final修飾的類來進行代理
代碼編寫
1.添加相關(guān)依賴
cglib cglib-nodep 3.2.5 commons-io commons-io 2.5
2.編寫CglibProxy類
package com.myimooc.designpattern.c3proxy.cglib; import java.lang.reflect.Method; import net.sf.cglib.proxy.Enhancer; import net.sf.cglib.proxy.MethodInterceptor; import net.sf.cglib.proxy.MethodProxy; /** * @describe 代理類 * @author zc * @version 1.0 2017-08-28 */ public class CglibProxy implements MethodInterceptor { private Enhancer enhance = new Enhancer(); @SuppressWarnings("rawtypes") public Object getProxy(Class clazz){ // 設(shè)置創(chuàng)建子類的類 enhance.setSuperclass(clazz); enhance.setCallback(this); return enhance.create(); } /** * 攔截所有目標類方法的調(diào)用 * 參數(shù): * obj 目標類的實例 * method 目標方法的反射對象 * args 方法的參數(shù) * proxy 代理類的實例 */ @Override public Object intercept(Object obj, Method method, Object[] args, MethodProxy proxy) throws Throwable { System.out.println("日志開始..."); // 代理類調(diào)用父類的方法 proxy.invokeSuper(obj, args); System.out.println("日志結(jié)束..."); return null; } }
3.編寫Train類
package com.myimooc.designpattern.c3proxy.cglib; /** * @describe 火車 * @author zc * @version 1.0 2017-08-28 */ public class Train { public void move(){ System.out.println("火車行駛中"); } }
4.編寫Client類
package com.myimooc.designpattern.c3proxy.cglib; /** * @describe cglib代理測試類 * @author zc * @version 1.0 2017-08-28 */ public class Client { public static void main(String[] args) { CglibProxy proxy = new CglibProxy(); Train t = (Train)proxy.getProxy(Train.class); t.move(); } }第三章:模擬JDK動態(tài)代理 3-1 實現(xiàn)動態(tài)代理
動態(tài)代理實現(xiàn)思路
實現(xiàn)功能:通過Proxy的newProxyInstance返回代理對象 1.聲明一段源碼(動態(tài)產(chǎn)生代理) 2.編譯編碼(JDK Compiler API),產(chǎn)生新的類(代理類) 3.將這個類load到內(nèi)存當中,產(chǎn)生一個新的對象(代理對象) 4.return 代理對象
代碼編寫
1.編寫InvocationHandler類
package com.myimooc.designpattern.c3proxy.simulationjdk; import java.lang.reflect.Method; /** * @describe 模擬JDK動態(tài)代理-業(yè)務處理類 * @author zc * @version 1.0 2017-08-28 */ public interface InvocationHandler { public void invoke(Object obj,Method method); }
2.編寫Proxy類
package com.myimooc.designpattern.c3proxy.simulationjdk; import java.io.File; import java.lang.reflect.Constructor; import java.lang.reflect.Method; import javax.tools.JavaCompiler; import javax.tools.JavaCompiler.CompilationTask; import javax.tools.StandardJavaFileManager; import javax.tools.ToolProvider; import org.apache.commons.io.FileUtils; /** * @describe 模擬JDK動態(tài)代理-代理類 * @author zc * @version 1.0 2017-08-28 */ @SuppressWarnings({"rawtypes","unchecked"}) public class Proxy { public static Object newProxyInstance( Class infce,InvocationHandler h)throws Exception{ String rt = " "; String methodStr = ""; for(Method m : infce.getMethods()){ methodStr += " @Override" + rt + " public void "+ m.getName() +"(){" + rt + " try{" + rt + " Method md = " +infce.getName()+".class.getMethod(""+m.getName()+"");" + rt + " h.invoke(this,md);" + rt + " }catch(Exception e){e.printStackTrace();}" + rt + " }" + rt; } String str = "package com.myimooc.designpattern.c3proxy.simulationjdk; " + rt + "import com.myimooc.designpattern.c3proxy.simulationjdk.InvocationHandler;" + rt + "import java.lang.reflect.Method;" + rt + "public class $Proxy0 implements "+ infce.getName() +" { " + rt + " public $Proxy0(InvocationHandler h) {" + rt + " this.h = h;" + rt + " }" + rt + " private InvocationHandler h;" + rt + methodStr + rt + "}"; // 產(chǎn)生代理類的java文件 String filename = System.getProperty("user.dir") + "/target/classes/com/myimooc/designpattern/c3proxy/simulationjdk/$Proxy0.java"; File file = new File(filename); FileUtils.writeStringToFile(file, str,"UTF-8"); // 編譯-拿到編輯器 JavaCompiler compiler = ToolProvider.getSystemJavaCompiler(); // 文件管理者 StandardJavaFileManager fileMgr = compiler.getStandardFileManager(null, null, null); // 獲取文件 Iterable units = fileMgr.getJavaFileObjects(filename); // 編譯任務 CompilationTask task = compiler.getTask(null, fileMgr, null, null, null, units); // 進行編譯 task.call(); fileMgr.close(); // load到內(nèi)存 ClassLoader cl = ClassLoader.getSystemClassLoader(); Class c = cl.loadClass("com.myimooc.designpattern.c3proxy.simulationjdk.$Proxy0"); Constructor ctr = c.getConstructor(InvocationHandler.class); return ctr.newInstance(h); } }
3.編寫TimeHandler類
package com.myimooc.designpattern.c3proxy.simulationjdk; import java.lang.reflect.Method; /** * @describe 模擬JDK動態(tài)代理-時間業(yè)務邏輯處理 * @author zc * @version 1.0 2017-08-28 */ public class TimeHandler implements InvocationHandler{ private Object target; public TimeHandler(Object target) { super(); this.target = target; } @Override public void invoke(Object obj, Method method) { try { long starttime = System.currentTimeMillis(); System.out.println("汽車開始行駛..."); method.invoke(target); long endtime = System.currentTimeMillis(); System.out.println("汽車結(jié)束行駛...汽車行駛時間:"+(endtime - starttime) + "毫秒"); } catch (Exception e) { e.printStackTrace(); } } }
4.編寫Client類
package com.myimooc.designpattern.c3proxy.simulationjdk; import com.myimooc.designpattern.c3proxy.car.Car; import com.myimooc.designpattern.c3proxy.car.Moveable; /** * @describe 模擬JDK動態(tài)代理-測試類 * @author zc * @version 1.0 2017-08-28 */ 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(); } }第四章:總結(jié) 4-1 課程總結(jié)
總結(jié)
代理模式概念、分類及應用場景 場景代理模式 靜態(tài)代理(繼承、聚合) JDK動態(tài)代理實現(xiàn)日志處理功能 模擬JDK動態(tài)代理實現(xiàn)
代理模式-動態(tài)代理
文章版權(quán)歸作者所有,未經(jīng)允許請勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。
轉(zhuǎn)載請注明本文地址:http://specialneedsforspecialkids.com/yun/70297.html
時間:2017年08月30日星期三說明:本文部分內(nèi)容均來自慕課網(wǎng)。@慕課網(wǎng):http://www.imooc.com教學源碼:https://github.com/zccodere/s...學習源碼:https://github.com/zccodere/s... 第一章:責任鏈模式簡介 1-1 課程簡介 課程大綱 什么是責任鏈模式 如何實現(xiàn)責任鏈模式 責任鏈模式如何解耦 責任鏈模式的應用 案例:...
時間:2017年08月27日星期日說明:本文部分內(nèi)容均來自慕課網(wǎng)。@慕課網(wǎng):http://www.imooc.com教學源碼:https://github.com/zccodere/s...學習源碼:https://github.com/zccodere/s... 第一章:單例模式簡介 1-1 簡介 單例模式 概念及應用場合 餓漢模式 懶漢模式 餓漢模式與懶漢模式的區(qū)別 什么是設(shè)計模式 是一套被反...
時間:2017年08月31日星期四說明:本文部分內(nèi)容均來自慕課網(wǎng)。@慕課網(wǎng):http://www.imooc.com教學源碼:https://github.com/zccodere/s...學習源碼:https://github.com/zccodere/s... 第一章:策略模式簡介 1-1 簡介 課程大綱 什么是策略模式 策略模式如何實現(xiàn) 策略模式總結(jié)篇 實例案例分享 日常生活中的策略 Wor...
摘要:時間年月日星期二說明本文部分內(nèi)容均來自慕課網(wǎng)。慕課網(wǎng)教學源碼學習源碼第一章適配器模式的簡介簡介生活中的適配器翻譯軟件插座適配器適配器模式定義適配器模式講將一個類的接口,轉(zhuǎn)換成客戶期望的另外一個接口。 時間:2017年08月29日星期二說明:本文部分內(nèi)容均來自慕課網(wǎng)。@慕課網(wǎng):http://www.imooc.com教學源碼:https://github.com/zccodere/s.....
摘要:時間年月日星期六說明本文部分內(nèi)容均來自慕課網(wǎng)。案例介紹飲料機配置模版把水煮沸泡飲料把飲料倒進杯子加調(diào)味料第二章模版模式實現(xiàn)基本框架代碼編寫編寫類模版模式抽象基類,為所有子類提供一個算法框架。 時間:2017年09月02日星期六說明:本文部分內(nèi)容均來自慕課網(wǎng)。@慕課網(wǎng):http://www.imooc.com教學源碼:https://github.com/zccodere/s...學習源...
閱讀 2041·2023-04-25 15:11
閱讀 3461·2021-09-23 11:57
閱讀 1372·2021-07-26 23:38
閱讀 1319·2019-08-30 15:54
閱讀 635·2019-08-30 15:53
閱讀 3245·2019-08-26 13:36
閱讀 986·2019-08-26 12:01
閱讀 2863·2019-08-23 16:21