詳解JAVA設(shè)計(jì)模式之代理模式
什么是設(shè)計(jì)模式(Design Pattern)?
設(shè)計(jì)模式是一套被反復(fù)使用,多數(shù)人知曉的,經(jīng)過分類編目的,代碼設(shè)計(jì)經(jīng)驗(yàn)的總結(jié)。
代理模式的定義?
代理模式就是為其他對象提供一種代理,以控制對這個對象的訪問。
代理對象起到中介作用,可去掉功能服務(wù)或增加額外的服務(wù)。
代理對象和目標(biāo)對象的關(guān)系?
代理對象:增強(qiáng)后的對象
目標(biāo)對象:被增強(qiáng)的對象
他們不是絕對的,會根據(jù)情況發(fā)生變化。
代理模式的兩種實(shí)現(xiàn)方式?
1.靜態(tài)代理:代理和被代理對象在代理之前是確定的,它們都實(shí)現(xiàn)相同的接口或者繼承相同的抽象類。
2.動態(tài)代理:JDK通過接口反射得到字節(jié)碼,然后把字節(jié)碼轉(zhuǎn)換成class(通過native方法)
靜態(tài)代理實(shí)現(xiàn)的兩種方式?
使用繼承方式實(shí)現(xiàn)和使用聚合方式實(shí)現(xiàn)。
繼承:代理對象繼承目標(biāo)對象,重寫需要增強(qiáng)的方法。缺點(diǎn):代理類過多,產(chǎn)生類爆炸。
聚合:目標(biāo)對象和代理對象實(shí)現(xiàn)同一個接口,代理對象當(dāng)中要包含目標(biāo)對象。
動態(tài)代理的實(shí)現(xiàn)方式?
Java動態(tài)代理類位于java.lang.reflect包下,一般主要涉及到以下兩個類:
1.Interface InvocationHandler : 該接口中僅定義了一個方法,public Object invoke(Object obj,Method method,Object[] args),在實(shí)際使用時,第一個參數(shù)obj一般是指代理類,method是被代理的方法,args是該方法的參數(shù)數(shù)組,這個抽象方法在代理類中動態(tài)實(shí)現(xiàn)。
2.Proxy 該類即為動態(tài)代理類,static Object newProxyInstance(ClassLoader loader,Class[] interfaces,InvocationHandler h):返回代理類的一個實(shí)例,返回后的代理類可以當(dāng)做被代理類使用(可使用被代理類在接口中聲明過的方法)
所謂的動態(tài)代理是這樣一種class:它是在運(yùn)行時生成的class,該class需要實(shí)現(xiàn)一組interface,使用動態(tài)代理類時,必須實(shí)現(xiàn)InvocationHandler接口。
JDK動態(tài)代理和CGLIB動態(tài)代理的區(qū)別?
1.JDK動態(tài)代理只能代理實(shí)現(xiàn)了接口的類,沒有實(shí)現(xiàn)接口的類不能實(shí)現(xiàn)JDK的動態(tài)代理。
2.CGLIB動態(tài)代理針對類來實(shí)現(xiàn)代理的,對指定目標(biāo)類產(chǎn)生一個子類,通過方法攔截技術(shù)攔截所有的父類方法的調(diào)用。
動態(tài)代理實(shí)現(xiàn)的思路:
1.聲明一段源碼(動態(tài)產(chǎn)生代理)
2.編譯源碼(JDK Compiler API ),產(chǎn)生新的類(代理類)
3.將這個類load到內(nèi)存中,產(chǎn)生一個新的對象(代理對象)
4.return 代理對象。
使用靜態(tài)代理的例子:
1.首先創(chuàng)建業(yè)務(wù)邏輯接口
/** * 接口 * @author Administrator * */ public interface Moveable { /** * * 接口中的方法 * @Description: TODO * @returnType: void */ void move(); }
2.創(chuàng)建實(shí)現(xiàn)類,實(shí)現(xiàn)接口中的方法
/** * 實(shí)現(xiàn)類 * @author Administrator * */ 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(); } } }
3.使用繼承方式實(shí)現(xiàn)對實(shí)現(xiàn)類的代理
/** * 使用繼承方式實(shí)現(xiàn)代理 * @author Administrator * */ public class Car2 extends Car { /* (non-Javadoc) * @see com.wk.design.proxy.Car#move() * 直接調(diào)用父類的move方法,這樣就形成了一個Car2對Car的代理 */ @Override public void move() { long startTime = System.currentTimeMillis(); System.out.println("汽車開始行駛..."); //使用繼承的方式調(diào)用父類的move()方法 super.move(); long endTime = System.currentTimeMillis(); System.out.println("汽車行駛結(jié)束... 汽車行駛時間:"+(endTime-startTime)+"毫秒。"); } }
4.創(chuàng)建測試類
/** * 測試類 * @author Administrator * */ public class Test { public static void main(String[] args) { // Car car = new Car(); // car.move(); //使用繼承方式實(shí)現(xiàn)代理 Moveable car2 = new Car2(); car2.move(); //使用聚合方式實(shí)現(xiàn)代理 // Car car = new Car(); // Moveable car3 = new Car3(car); // car3.move(); } }
5.使用聚合方式實(shí)現(xiàn)對實(shí)現(xiàn)類的代理
日志代理類
/** * * 日志代理類 * @author Administrator * */ public class CarLogProxy implements Moveable { /** * 使用接口聲明代理類 */ private Moveable m; /** * 通過構(gòu)造方法的參數(shù)傳入代理類 * @param m */ public CarLogProxy(Moveable m) { super(); this.m = m; } @Override public void move() { System.out.println("日志開始"); //調(diào)用代理類的方法 m.move(); System.out.println("日志結(jié)束"); } }
時間代理類
/** * 時間代理類 * @author Administrator * */ public class CarTimeProxy implements Moveable { /** * 使用接口聲明代理類 */ private Moveable m; /** * 通過構(gòu)造方法的參數(shù)傳入代理類 * @param m */ public CarTimeProxy(Moveable m) { super(); this.m = m; } @Override public void move() { long startTime = System.currentTimeMillis(); System.out.println("汽車開始行駛..."); //調(diào)用代理類的方法 m.move(); long endTime = System.currentTimeMillis(); System.out.println("汽車行駛結(jié)束... 汽車行駛時間:"+(endTime-startTime)+"毫秒。"); } }
6.創(chuàng)建聚合方式測試類
/** * 聚合代理測試類 * @author Administrator * */ public class TestJuHeProxy { 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(clp); ctp.move(); } }
使用JDK動態(tài)代理實(shí)現(xiàn)的例子:
1.創(chuàng)建一個實(shí)現(xiàn)接口InvocationHandler的類,它必須實(shí)現(xiàn)invoke()方法。
2.創(chuàng)建被代理類及接口
3.調(diào)用Proxy的靜態(tài)方法,創(chuàng)建一個代理類
4.通過代理調(diào)用方法
/** * 使用jdk的動態(tài)代理 * @author Administrator * */ 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) throws Throwable { //在執(zhí)行被代理對象的方法之前執(zhí)行自己的邏輯 long startTime = System.currentTimeMillis(); System.out.println("汽車開始行駛..."); //執(zhí)行被代理對象的方法 method.invoke(target); //在執(zhí)行被代理對象的方法之后執(zhí)行自己的邏輯 long endTime = System.currentTimeMillis(); System.out.println("汽車行駛結(jié)束... 汽車行駛時間:"+(endTime-startTime)+"毫秒。"); return null; } }
/** * JDK動態(tài)代理測試類 * @author Administrator * */ public class JdkProxyTest { 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 InvocationHandler */ Moveable m= (Moveable)Proxy.newProxyInstance(cls.getClassLoader(), cls.getInterfaces(), h); //執(zhí)行被代理類的方法 m.move(); } }
使用CGLIB動態(tài)代理實(shí)現(xiàn)的例子:
1.創(chuàng)建代理類,實(shí)現(xiàn)MethodInterceptor接口
2.使用Enhancer類創(chuàng)建代理方法
3.創(chuàng)建被代理類,并編寫代理方法
4.通過代理調(diào)用方法
/** * 使用cglib動態(tài)代理 * @author Administrator * */ public class Train { public void move(){ System.out.println("火車行駛中。。。"); } }
public class CglibProxy implements MethodInterceptor { private Enhancer enhancer = new Enhancer(); //創(chuàng)建代理類方法 public Object getProxy(Class clazz){ //設(shè)置創(chuàng)建子類的類 enhancer.setSuperclass(clazz); //回調(diào)函數(shù) enhancer.setCallback(this); //創(chuàng)建并返回子類的實(shí)例 return enhancer.create(); } /** * 作用:攔截所有目標(biāo)類方法的調(diào)用 * obj : 目標(biāo)類的實(shí)例 * m : 目標(biāo)方法的反射對象 * args : 方法的參數(shù) * proxy : 代理類的實(shí)例 */ @Override public Object intercept(Object obj, Method m, Object[] args, MethodProxy proxy) throws Throwable { //在調(diào)用方法時實(shí)現(xiàn)自己的業(yè)務(wù)邏輯 System.out.println("日志開始..."); //代理類調(diào)用父類的方法 proxy.invokeSuper(obj, args); //調(diào)用方法之后實(shí)現(xiàn)自己的業(yè)務(wù)邏輯 System.out.println("日志結(jié)束..."); return null; } }
/** * 使用cglib動態(tài)代理的測試類 * @author Administrator * */ public class CglibProxyTest { public static void main(String[] args) { CglibProxy proxy = new CglibProxy(); //傳入要代理的類 Train t = (Train)proxy.getProxy(Train.class); //執(zhí)行方法 t.move(); } }
以上就是詳解JAVA設(shè)計(jì)模式之代理模式的詳細(xì)內(nèi)容,更多關(guān)于JAVA 代理模式的資料請關(guān)注腳本之家其它相關(guān)文章!
相關(guān)文章
Java規(guī)則引擎easy-rules詳細(xì)介紹
本文主要介紹了Java規(guī)則引擎easy-rules詳細(xì)介紹,文中通過示例代碼介紹的非常詳細(xì),具有一定的參考價值,感興趣的小伙伴們可以參考一下2022-01-01修改request的parameter的幾種方式總結(jié)
這篇文章主要介紹了修改request的parameter的幾種方式,具有很好的參考價值,希望對大家有所幫助。如有錯誤或未考慮完全的地方,望不吝賜教2021-08-08java實(shí)現(xiàn)http的Post、Get、代理訪問請求
這篇文章主要為大家提供了java實(shí)現(xiàn)http的Post、Get、代理訪問請求的相關(guān)代碼,感興趣的小伙伴們可以參考一下2016-01-01Spring MVC+FastJson+Swagger集成的完整實(shí)例教程
這篇文章主要給大家分享介紹了關(guān)于Spring MVC+FastJson+Swagger集成的完整實(shí)例教程,文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧。2018-04-04springboot?集成activemq項(xiàng)目配置方法
這篇文章主要介紹了springboot?集成activemq項(xiàng)目配置方法,e-car項(xiàng)目配置通過引入activemq依賴,本文結(jié)合實(shí)例代碼給大家介紹的非常詳細(xì),感興趣的朋友跟隨小編一起看看吧2024-04-04Jmeter基于JDBC請求實(shí)現(xiàn)MySQL數(shù)據(jù)庫測試
這篇文章主要介紹了Jmeter基于JDBC請求實(shí)現(xiàn)MySQL數(shù)據(jù)庫測試,文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,需要的朋友可以參考下2020-10-10在Spring Boot2中使用CompletableFuture的方法教程
這篇文章主要給大家介紹了關(guān)于在Spring Boot2中使用CompletableFuture的相關(guān)資料,文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,需要的朋友們下面來一起看看吧2019-01-01Java Guava排序器Ordering原理及代碼實(shí)例
這篇文章主要介紹了Java Guava排序器Ordering原理及代碼實(shí)例,文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,需要的朋友可以參考下2020-11-11