比較好的做網(wǎng)站重慶白云seo整站優(yōu)化
1.代理模式概述
學(xué)習(xí)內(nèi)容
1)概述
為什么要有 “代理” ?
- 生活中就有很多例子,比如委托業(yè)務(wù),黃牛(票販子)等等
- 代理就是被代理者沒有能力或者不愿意去完成某件事情,需要找個人代替自己去完成這件事,這才是“代理”存在的原因。
- 例如要租房子,房產(chǎn)中介可以在我們住房前代理我們找房子。中介就是代理,而自己就是被代理了。
在代碼設(shè)計中,代理模式作用主要就是讓 “被代理對象” 的某個方法執(zhí)行之前或者執(zhí)行之后加入其他增強邏輯。
前增強 : 例如獲取當(dāng)前時間被代理對象調(diào)用方法后增強 : 例如獲取當(dāng)前時間計算方法執(zhí)行的時間
2)代理的前提條件 : 掌握 !
- 抽象角色 :聲明功能
- 代理角色 :實現(xiàn)抽象功能 , 完成代理邏輯
- 被代理角色 :實現(xiàn)抽象功能
意味著被代理角色和代理角色有著共同的父類型(既抽象角色) , 例如我要租房子, 我只能找房產(chǎn)中介, 不能找票販子
-
代理模式存在兩種實現(xiàn)方式:
- 靜態(tài)代理
- 動態(tài)代理
知識小結(jié)
-
請說出代碼中代理模式的作用?
代理角色對 被代理就角色某個方法執(zhí)行的前或者后進行 功能增強
-
請說出代理模式中的三個角色?
抽象角色 代理角色 被代理角色
==============================================================================================================
1.1 靜態(tài)代理
學(xué)習(xí)目標(biāo)
- 能夠?qū)懗鲮o態(tài)代理模式代碼
內(nèi)容講解
-
靜態(tài)代理是由程序員創(chuàng)建 或 工具生成代理類的源碼,再編譯代理類。
在程序運行前就已經(jīng)存在代理類的字節(jié)碼文件,代理類和被代理類的關(guān)系在運行前就確定了。
簡單理解 : 在程序運行之前 , 代理類就存在了,這就是靜態(tài)代理 ; 動態(tài)代理是程序運行時動態(tài)生成代理類
-
靜態(tài)代理實現(xiàn)的步驟 :
- 存在一個抽象角色
- 定義被代理角色
- 定義代理,增強被代理角色的功能
案例實踐 :
- 以現(xiàn)實中經(jīng)紀(jì)人代理明星
已知存在接口:
// 1.抽象角色
interface Star {// 真人秀方法double liveShow(double money);void sleep();
}
定義被代理類:
- 定義王寶強類,實現(xiàn)Star方法
// - 定義被代理角色(寶強)
class BaoQiang implements Star {@Overridepublic double liveShow(double money) {System.out.println("寶強參加了一個真人秀活動賺了" + money + "錢");return money;}@Overridepublic void sleep() {System.out.println("寶強累了 , 睡覺...");}
}
定義代理類:
- 定義宋喆經(jīng)紀(jì)人類
// - 定義代理角色(宋喆),增強被代理角色的功能
class SongZhe implements Star {private BaoQiang baoQiang;public SongZhe(BaoQiang baoQiang) {this.baoQiang = baoQiang;}@Overridepublic double liveShow(double money) {// 前增強System.out.println("宋喆幫寶強拉了一個真人秀的活動,獲取傭金" + money * 0.8 + "元");// 被代理角色的功能double result = baoQiang.liveShow(money * 0.2);// 后增強System.out.println("宋喆幫寶強把賺的錢存了起來...");return result;}@Overridepublic void sleep() {// 前增強System.out.println("宋喆幫寶強定了一家五星級大酒店");baoQiang.sleep();// 后增強System.out.println("宋喆幫寶強退房...");}
}
定義測試類進行測試
/*靜態(tài)代理實現(xiàn)的步驟 :- 存在一個抽象角色- 定義被代理角色(寶強)- 定義代理角色(宋喆),增強被代理角色的功能*/
public class StaticAgentDemo {public static void main(String[] args) {// 創(chuàng)建被代理角色 , 沒有任何增強BaoQiang baoQiang = new BaoQiang();double result = baoQiang.liveShow(1000);System.out.println(result);baoQiang.sleep();System.out.println("===========================");// 創(chuàng)建代碼角色對象 , 可以對被代理角色功能做前后增強SongZhe songZhe = new SongZhe(baoQiang);double result2 = songZhe.liveShow(1000);System.out.println(result2);songZhe.sleep();}
}
關(guān)系圖 :
宋喆和寶強都有共同的父類型。他們的業(yè)務(wù)方法都是一樣。
靜態(tài)代理和裝飾模式的對比 :
? BufferedRead(FileRead)
? 1 裝飾設(shè)計模式是功能擴展功能,在原有的功能基礎(chǔ)之上增加了新的功能
? 2 而代理主要對功能的前后做了增強
知識小結(jié)
-
請問什么叫做靜態(tài)代理?
代碼執(zhí)行前,已經(jīng)確定了代理的代碼邏輯。
2. 動態(tài)代理
學(xué)習(xí)目標(biāo)
- 能夠知道什么是動態(tài)代理
- 能夠熟悉動態(tài)代理相關(guān)API
- 能夠熟悉動態(tài)代理代碼執(zhí)行流程
內(nèi)容講解
1)概述
在實際開發(fā)過程中往往我們自己不會去創(chuàng)建代理類而是通過JDK提供的Proxy
類在程序運行時,運用反射機制動態(tài)創(chuàng)建而成
這就是我們所謂的動態(tài)代理。
與靜態(tài)代理之間的區(qū)別,在于不用自己寫代理類
雖然我們不需要自己定義代理類創(chuàng)建代理對象
但是我們要定義對被代理對象直接訪問方法的攔截,原因就是對攔截的方法做增強。
動態(tài)代理技術(shù)在框架中使用居多,例如:很快要學(xué)到的數(shù)據(jù)庫框架MyBatis框架等一些主流框架技術(shù)(Spring,SpringMVC)中都使用了動態(tài)代理技術(shù)。
2)API學(xué)習(xí)
Proxy類
java.lang.reflect.Proxy
類提供了用于創(chuàng)建動態(tài)代理類和對象的靜態(tài)方法
? 它還是由這些方法創(chuàng)建的所有動態(tài)代理類的超類(代理類的父類是Proxy)。
public static Object newProxyInstance (ClassLoader loader, Class<?>[] interfaces, InvocationHandler h ) 獲取代理對象的方法 - 返回值:該方法返回就是動態(tài)生成的代理對象
- 參數(shù)列表說明:1. ClassLoader loader - 定義代理類的類加載器2. Class<?>[] interfaces - 代理類要實現(xiàn)的接口列表,要求與被代理類的接口一樣。3. InvocationHandler h - 就是具體實現(xiàn)代理邏輯的接口
InvocationHandler接口
源碼 :
interface InvocationHandler{public Object invoke(Object proxy, Method method, Object[] args); //代理邏輯
}
java.lang.reflect.InvocationHandler
是代理對象的實際處理代理邏輯的接口,具體代理實現(xiàn)邏輯在其 invoke 方法中。所有代理對象調(diào)用的方法,執(zhí)行是都會經(jīng)過invoke。因此如果要對某個方法進行代理增強,就可以在這個invoke方法中進行定義。
方法說明如下:
public Object invoke(Object proxy, Method method, Object[] args);1. 返回值:方法被代理后執(zhí)行的結(jié)果。
2. 參數(shù)列表:1. proxy - 就是代理對象2. method - 代理對象調(diào)用的方法3. args - 代理對象調(diào)用方法傳入?yún)?shù)值的對象數(shù)組.
3)代碼實踐
將經(jīng)紀(jì)人代理明星的案例使用動態(tài)代理實現(xiàn)
- 把父接口定義
- 定義被代理類:寶強
- 動態(tài)生成代理類
- 定義代理邏輯
package com.itheima.dynamicproxy_demo;import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;// 測試類
/*1 Proxy類 :public static Object newProxyInstance (ClassLoader loader,Class<?>[] interfaces,InvocationHandler h ) 獲取代理對象的方法- 返回值:該方法返回就是動態(tài)生成的代理對象- 參數(shù)列表說明:1. ClassLoader loader - 定義代理類的類加載器2. Class<?>[] interfaces - 代理類要實現(xiàn)的接口列表,要求與被代理類的接口一樣。3. InvocationHandler h - 就是具體實現(xiàn)代理邏輯的接口2 InvocationHandler接口public Object invoke(Object proxy, Method method, Object[] args);1. 返回值:方法被代理后執(zhí)行的結(jié)果。2. 參數(shù)列表:1. proxy - 就是代理對象2. method - 代理對象調(diào)用的方法3. args - 代理對象調(diào)用方法傳入?yún)?shù)值的對象數(shù)組.*/
public class DynamicProxyDemo {public static void main(String[] args) {// Proxy.newProxyInstance(被代理角色的類加載器 , 被代理角色實現(xiàn)的所有接口 , 處理器);// 被代理角色的類加載器ClassLoader classLoader = BaoQiang.class.getClassLoader();// 被代理角色實現(xiàn)的所有接口Class<?>[] interfaces = BaoQiang.class.getInterfaces();// 創(chuàng)建被代理角色對象BaoQiang baoQiang = new BaoQiang();// 代理角色 , 動態(tài)生成Star songZhe = (Star) Proxy.newProxyInstance(classLoader, interfaces, new MyInvocationHandler(baoQiang));// 代理角色調(diào)用liveShow方法songZhe.liveShow(1000);songZhe.sleep();}
}// 定義InvocationHandler接口的實現(xiàn)類
class MyInvocationHandler implements InvocationHandler {private BaoQiang baoQiang;public MyInvocationHandler(BaoQiang baoQiang) {this.baoQiang = baoQiang;}// invoke什么時候會執(zhí)行????// 代理對象調(diào)用功能 , 就會觸發(fā)invoke方法// 此方法對被代理角色的功能做增強// method : 代理對象調(diào)用功能就會觸發(fā)invoke方法 , invoke方法中的method代表的就是調(diào)用的方法對象@Overridepublic Object invoke(Object proxy, Method method, Object[] args) throws Throwable {if (method.getName().equals("liveShow")) {// 代理角色對象調(diào)用liveShow方法 , 此位置會攔截// 前增強System.out.println("宋喆幫寶強拉了一個真人秀的活動,獲取傭金" + (double) args[0] * 0.8 + "元");Object result = method.invoke(baoQiang, (double) args[0] * 0.2);// 后增強System.out.println("宋喆幫寶強把賺的錢存了起來...");return result;} else if (method.getName().equals("sleep")) {// 代理角色對象調(diào)用sleep方法 , 此位置會攔截method.invoke(baoQiang);} else {// 除了liveShow和sleep方法 , 會執(zhí)行else代碼塊中的內(nèi)容}return null;}
}// 1 抽象角色
interface Star {double liveShow(double money);void sleep();
}// 2 定義被代理角色(寶強)
class BaoQiang implements Star {@Overridepublic double liveShow(double money) {System.out.println("寶強參加了一個真人秀活動賺了" + money + "錢");return money;}@Overridepublic void sleep() {System.out.println("寶強累了 , 睡覺...");}
}
動態(tài)代理調(diào)用流程:
小結(jié)
-
什么是動態(tài)代理?
在代碼執(zhí)行前,沒有代理類,代理類是在程序運行的時候動態(tài)生成.Proxy.newProxyInstance
-
動態(tài)代理有什么好處?
動態(tài)代理可以為 “被代理對象” 的所有接口的所有方法做代理,動態(tài)代理可以在不改變方法源碼的情況下,實現(xiàn)對方法功能的增強。 -
動態(tài)代理相關(guān)的API有哪些?
Proxypublic static Object newProxyInstance(類加載器,接口列表,調(diào)用處理器)類加載器 = 被代理對象.getClass().getClassLoader();接口列表 = 被代理對象.getClass().getInterfaces();調(diào)用處理器 = new InvocationHandler(){ 實現(xiàn) invoke 方法 };InvocationHandlerpublic Object invoke(代理對象,方法對象,方法的實參類別) 該方法執(zhí)行時機是,代理對象調(diào)用方法時觸發(fā)執(zhí)行
-
動態(tài)代理類的字節(jié)碼在程序運行時由Java反射機制動態(tài)生成,無需程序員手工編寫它的源代碼。
-
缺點 :只能針對接口的實現(xiàn)類做代理對象,普通類是不能做代理對象的。
后面框架學(xué)習(xí)的時候會接觸到CGLib(Code Genneration Library ): 可以實現(xiàn)對類的代理