23种设计模式——JDK动态代理(AOP)
文章目錄
- 01 代理
- 1.1 什么是代理?
- 1.2 為什么要找中介
- 02 靜態(tài)代理
- 2.1 使用代理模式的作用
- 2.2 實(shí)現(xiàn)代理的方式
- 2.3 具體實(shí)現(xiàn)
- 2.4 靜態(tài)代理的優(yōu)缺點(diǎn)
- 03 動態(tài)代理
- 3.1 靜態(tài)代理和動態(tài)代理模式的對比
- 3.2 動態(tài)代理的介紹
- 3.3 回顧反射 Method類
- 3.3.1 class.getMethod
- 3.3.2 Method.invoke
- 3.4 JDK動態(tài)代理
- 3.4.1 Interface InvocationHandler
- 3.4.2 Method
- 3.4.3 Proxy類
- 3.5 JDK動態(tài)代理實(shí)現(xiàn)步驟
- 3.6 靜態(tài)代理的優(yōu)缺點(diǎn)
- 04 實(shí)現(xiàn)動態(tài)代理的步驟
- 05 JDK動態(tài)代理執(zhí)行流程
- 06 靜態(tài)代理項(xiàng)目中的應(yīng)用
- 07 完結(jié)
01 代理
1.1 什么是代理?
代理,在我們?nèi)粘I钪芯陀畜w現(xiàn),代購,中介,換ip,商家等等.
比如有一家美國的大學(xué),可以對全世界招生.留學(xué)中介(代理 )
留學(xué)中介(代理):幫助這家美國的學(xué)校招生,中介是學(xué)校的代理中介是代替學(xué)校完成招生功能
代理特點(diǎn)
1.2 為什么要找中介
1.中介是專業(yè)的,方便.
2.家長現(xiàn)在不能自己去找學(xué)校。家長沒有能力訪問學(xué)校.或者美國學(xué)校不接收個(gè)人來訪
買東西都是商家賣, 商家是某個(gè)商品的代理, 你個(gè)人買東西,肯定不會讓你接觸到廠家的.
02 靜態(tài)代理
2.1 使用代理模式的作用
2.2 實(shí)現(xiàn)代理的方式
1)代理類是自己手工實(shí)現(xiàn)的,自己創(chuàng)建一個(gè)java類,表示代理類
2)同時(shí)你所要代理的目標(biāo)
特點(diǎn):
1)實(shí)現(xiàn)簡單
2)容易理解
模擬一個(gè)用戶購買u盤的行為。
用戶:客戶端類
商家:代理,代理某個(gè)品牌的u盤。
廠家:目標(biāo)類。
三者的關(guān)系:用戶(客戶端)-—-商家(代理)-—-廠家(目標(biāo))
商家和廠家都是賣u盤的,他們完成的功能是一致的,都是賣u盤。
實(shí)現(xiàn)步驟:
實(shí)現(xiàn)步驟
1.創(chuàng)建一個(gè)接口,定義賣u盤的方法,表示你的廠家和商家做的事情
2.創(chuàng)建廠家類,實(shí)現(xiàn)1步驟的接口
3.創(chuàng)建商家,就是代理,也需要實(shí)現(xiàn)1步驟中的接口
4.創(chuàng)建客戶端類,調(diào)用商家的方法買一個(gè)u盤
2.3 具體實(shí)現(xiàn)
實(shí)現(xiàn)步驟
1.創(chuàng)建一個(gè)接口,定義賣u盤的方法,表示你的廠家和商家做的事情
2.創(chuàng)建廠家類,實(shí)現(xiàn)1步驟的接口
package com.rango.factory;import com.rango.service.usbSell; //目標(biāo)類:金士頓廠家,不接受用戶的單獨(dú)購買 public class UsbKingFactory implements usbSell {/*** 定義一個(gè)方法 參數(shù) amount:表示一次購買的數(shù)量,暫時(shí)不用* 返回值表示一個(gè)u盤的價(jià)格** @param amount* @return*/@Override //一個(gè)128G的U盤是85元. // 后期根據(jù)amount,可以實(shí)現(xiàn)不同的價(jià)格,例如10000個(gè),單擊是80,50000個(gè)75public float sell(int amount) {return 85.0f*amount;} }3.創(chuàng)建商家,就是代理,也需要實(shí)現(xiàn)1步驟中的接口
package com.rango.business;import com.rango.factory.UsbKingFactory; import com.rango.service.usbSell;//淘寶是一個(gè)商家,代理金士頓U盤的銷售 public class TaoBao implements usbSell { // 聲明 商家代理的廠家具體是誰private UsbKingFactory factory =new UsbKingFactory();@Override // 實(shí)現(xiàn)銷售U盤功能public float sell(int amount) { // 向廠家發(fā)送訂單,告訴廠家,我買了U盤,廠家發(fā)貨 // 發(fā)送給工廠,我需要的訂單,返回報(bào)價(jià)float price = factory.sell(amount); // 商家需要加價(jià)也就是代理要增加價(jià)格price = price + 25; //在目標(biāo)類的方法調(diào)用后,你做的其他功能,都是增強(qiáng)的意思System.out.println("淘寶再給你返回一個(gè)優(yōu)惠券,或者紅包"); // 增加的價(jià)格return price;} }4.創(chuàng)建客戶端類,調(diào)用商家的方法買一個(gè)u盤
import com.rango.business.TaoBao;public class shopMain {public static void main(String[] args){ // 創(chuàng)建代理的商家淘寶對象TaoBao taoBao = new TaoBao(); // 我只向淘寶買一件產(chǎn)品,得到報(bào)價(jià)float price = taoBao.sell(2);System.out.println("購買一件產(chǎn)品.淘寶的報(bào)價(jià)為: "+price);} }代理類完成的功能:
所屬我們只有一個(gè)代理商,我們實(shí)際上可以寫多個(gè)代理商,
2.4 靜態(tài)代理的優(yōu)缺點(diǎn)
優(yōu)點(diǎn):
確定:當(dāng)你的項(xiàng)目中,目標(biāo)類的代理類很多的時(shí)候,有以下的缺點(diǎn)
03 動態(tài)代理
1)什么是動態(tài)代理?
使用jdk的反射機(jī)制,創(chuàng)建對象的能力,創(chuàng)建的是代理類的的對象.而不用我們創(chuàng)建類文件,不用寫java文件, 什么叫動態(tài)?在程序執(zhí)行時(shí),調(diào)用jdk提供的方法才能創(chuàng)建代理類的對象
3.1 靜態(tài)代理和動態(tài)代理模式的對比
在靜態(tài)代理中目標(biāo)很多的時(shí)候,可以使用動態(tài)代理,避免靜態(tài)代理的缺點(diǎn)
在靜態(tài)代理中目標(biāo)類很多時(shí)候,可以使用動態(tài)代理,避免靜態(tài)代理的缺點(diǎn)。
動態(tài)代理中目標(biāo)類即使很多,
動態(tài)代理:在程序執(zhí)行過程中,使用jdk的反射機(jī)制,創(chuàng)建代理類對象,并動態(tài)的指定要代理目標(biāo)類。
換句話說:動態(tài)代理是一種創(chuàng)建java象的能力,讓你不用創(chuàng)建 TaoBao類就能創(chuàng)建代理類對象,除去了中間商
在java中,要想創(chuàng)建對象
3.2 動態(tài)代理的介紹
動態(tài)代理的實(shí)現(xiàn):
重寫父類中同名的方法,實(shí)現(xiàn)功能的修改。
比如mybatis,spring框架中都有使用。
3.3 回顧反射 Method類
Method類的結(jié)構(gòu)圖
- Class Method
- java.lang.Object
- java.lang.reflect.AccessibleObject
- java.lang.reflect.Executable
- java.lang.reflect.Method
- java.lang.reflect.Executable
- java.lang.reflect.AccessibleObject
- java.lang.Object
3.3.1 class.getMethod
Method method = HelloService.class.getMethod("sayhello", String.class,Integer.class);提出問題?
public Method getMethod(String name, Class<?>... parameterTypes)加入該方法的參數(shù)有多個(gè)該怎么辦?
parameterTypes參數(shù)是一個(gè)類對象數(shù)組,按聲明的順序標(biāo)識方法的形式參數(shù)類型。
3.3.2 Method.invoke
public Object invoke(Object obj,Object... args) * public Object invoke(Object obj, Object... args) * 表示執(zhí)行方法的調(diào)用 * 參數(shù): * 1.Object,表示對象,要執(zhí)行這個(gè)對象的方法 * 2.Object...args,方法執(zhí)行時(shí)的參數(shù)值 * 返回值: * Object:方法執(zhí)行后的返回值 *3.4 JDK動態(tài)代理
jdk動態(tài)代理:
1.反射, Method類,表示方法。類中的方法。通過Method可以執(zhí)行某個(gè)方法
2.jdk動態(tài)代理的實(shí)現(xiàn)
反射包java.lang. reflect,里面有三個(gè)類:InvocationHandler,Method,Proxy
3.4.1 Interface InvocationHandler
public interface InvocationHandlerInvocationHandler是由代理實(shí)例的調(diào)用處理程序?qū)崿F(xiàn)的接口 。
每個(gè)代理實(shí)例都有一個(gè)關(guān)聯(lián)的調(diào)用處理程序。 當(dāng)在代理實(shí)例上調(diào)用方法時(shí),方法調(diào)用將被編碼并分派到其調(diào)用處理程序的invoke方法。
1)InvocationHandler接口(調(diào)用處理器):就一個(gè)方法 invoke()
invoke():表示代理對象要執(zhí)行的功能代碼。你的代理類要完成的功能就寫在
invoke()方法中。
方法原型:
參數(shù):object proxy:jdk創(chuàng)建的代理對象,無需賦值。Method method:目標(biāo)類中的方法,jdk提供method對象的object[]args:目標(biāo)類中方法的參數(shù),jdk提供的。 Object invoke(Object proxy,方法 method,Object[] args)throws Throwable處理代理實(shí)例上的方法調(diào)用并返回結(jié)果。3.4.2 Method
2)Method類:表示方法的,確切的說就是目標(biāo)類中的方法。
作用:通過 Method可以執(zhí)行某個(gè)目標(biāo)類的方法, Method. invoke();
method. invoke(目標(biāo)對象,方法的參數(shù))
object ret= method. invoke(service22,"李四")
說明:method.invoke()就是為了用來執(zhí)行目標(biāo)方法的,等同于靜態(tài)代理中的
// 向廠家發(fā)送訂單,告訴廠家,我買了U盤,廠家發(fā)貨// 發(fā)送給工廠,我需要的訂單,返回報(bào)價(jià)float price = factory.sell(amount);3.4.3 Proxy類
3)proxy類:核心的對象,創(chuàng)建代理對象。之前創(chuàng)建對象都是new類的構(gòu)造方法()
現(xiàn)在我們是使用proxy類的方法,代替new的使用。
方法:靜態(tài)方法 newProxyInstance()
作用是:創(chuàng)建代理對象,等同于靜態(tài)代理中的TaoBao taoBao=new TaoBao()
我們來觀察方法原型
public static Object newProxyInstance( ClassLoader loader,Class<?>[] interfaces,InvocationHandler h) throws IllegalArgumentException參數(shù):
如何獲取? 類 a, a.getCalss().getClassLoader(),目標(biāo)對象的類加載器
這里我們細(xì)分:每一個(gè)類都繼承Object類,在Object中有一個(gè)getClass方法,表示 類對象的運(yùn)行時(shí)類的Class對象。 而Class類里面有一個(gè)public ClassLoader getClassLoader()方法
返回值也就是代理對象
3.5 JDK動態(tài)代理實(shí)現(xiàn)步驟
實(shí)現(xiàn)步驟
1.創(chuàng)建一個(gè)接口,定義賣u盤的方法,表示你的廠家和商家做的事情
2.創(chuàng)建廠家類,實(shí)現(xiàn)1步驟的接口
package com.rango.factory;import com.rango.service.usbSell; //目標(biāo)類:金士頓廠家,不接受用戶的單獨(dú)購買 public class UsbKingFactory implements usbSell {/*** 定義一個(gè)方法 參數(shù) amount:表示一次購買的數(shù)量,暫時(shí)不用* 返回值表示一個(gè)u盤的價(jià)格** @param amount* @return*/@Override //一個(gè)128G的U盤是85元. // 后期根據(jù)amount,可以實(shí)現(xiàn)不同的價(jià)格,例如10000個(gè),單擊是80,50000個(gè)75public float sell(int amount) {return 85.0f*amount;} }3.創(chuàng)建商家,就是代理,也需要實(shí)現(xiàn)1步驟中的接口
package com.rango.business;import com.rango.factory.UsbKingFactory; import com.rango.service.usbSell;//淘寶是一個(gè)商家,代理金士頓U盤的銷售 public class TaoBao implements usbSell { // 聲明 商家代理的廠家具體是誰private UsbKingFactory factory =new UsbKingFactory();@Override // 實(shí)現(xiàn)銷售U盤功能public float sell(int amount) { // 向廠家發(fā)送訂單,告訴廠家,我買了U盤,廠家發(fā)貨 // 發(fā)送給工廠,我需要的訂單,返回報(bào)價(jià)float price = factory.sell(amount); // 商家需要加價(jià)也就是代理要增加價(jià)格price = price + 25; //在目標(biāo)類的方法調(diào)用后,你做的其他功能,都是增強(qiáng)的意思System.out.println("淘寶再給你返回一個(gè)優(yōu)惠券,或者紅包"); // 增加的價(jià)格return price;} }4.創(chuàng)建客戶端類,調(diào)用商家的方法買一個(gè)u盤
import com.rango.business.TaoBao;public class shopMain {public static void main(String[] args){ // 創(chuàng)建代理的商家淘寶對象TaoBao taoBao = new TaoBao(); // 我只向淘寶買一件產(chǎn)品,得到報(bào)價(jià)float price = taoBao.sell(2);System.out.println("購買一件產(chǎn)品.淘寶的報(bào)價(jià)為: "+price);} }所以我們再次總結(jié)代理類完成的功能:
所屬我們只有一個(gè)代理商,我們實(shí)際上可以寫多個(gè)代理商,
3.6 靜態(tài)代理的優(yōu)缺點(diǎn)
我們再次總結(jié)一下靜態(tài)代理的優(yōu)缺點(diǎn)
優(yōu)點(diǎn):
確定:當(dāng)你的項(xiàng)目中,目標(biāo)類的代理類很多的時(shí)候,有一下的缺點(diǎn)
所以我們繼續(xù)學(xué)習(xí)動態(tài)代理
04 實(shí)現(xiàn)動態(tài)代理的步驟
第一步:創(chuàng)建接口,定義目標(biāo)所需功能
public interface UsbSell {float sell(int amount); }第二步:創(chuàng)建目標(biāo)類實(shí)現(xiàn)接口
public class UsbKingFactory implements UsbSell {@Overridepublic float sell(int amount) {System.out.println("目標(biāo)類中,執(zhí)行了sell目標(biāo)方法");return 85.02f;} }我們寫了接口類,定義了功能,寫了代理類,實(shí)現(xiàn)了接口功能,按照以前的操作,現(xiàn)在就需要寫一個(gè)真正的代理類,創(chuàng)建對象.
第三步: 創(chuàng)建Invocationhandler實(shí)現(xiàn)類.在invoke()方法中完成代理類的對象
1.調(diào)用目標(biāo)的方法
2.增強(qiáng)功能
public class MyHandle implements InvocationHandler {@Overridepublic Object invoke(Object proxy, Method method, Object[] args) throws Throwable {return null;} }我們就在以前代理類的實(shí)現(xiàn)方法上進(jìn)行修改
//之前的代理類public class TaoBao implements usbSell {// 聲明 商家代理的廠家具體是誰private UsbKingFactory factory =new UsbKingFactory();@Override// 實(shí)現(xiàn)銷售U盤功能public float sell(int amount) {// 向廠家發(fā)送訂單,告訴廠家,我買了U盤,廠家發(fā)貨// 發(fā)送給工廠,我需要的訂單,返回報(bào)價(jià)float price = factory.sell(amount);// 商家需要加價(jià)也就是代理要增加價(jià)格price = price + 25;//在目標(biāo)類的方法調(diào)用后,你做的其他功能,都是增強(qiáng)的意思System.out.println("淘寶再給你返回一個(gè)優(yōu)惠券,或者紅包");// 增加的價(jià)格return price;}}調(diào)用目標(biāo)的方法
//傳入是誰的對象,就給誰創(chuàng)建代理public MyHandle(Object target) {this.target = target;} invoke里面的設(shè)置Object res =null;// 向廠家發(fā)送訂單,告訴廠家,我買了U盤,廠家發(fā)貨// 發(fā)送給工廠,我需要的訂單,返回報(bào)價(jià) // float price = factory.sell(amount);res = method.invoke(target,args); //待執(zhí)行目標(biāo)方法,執(zhí)行后返回值第四步: 使用Proxy類的靜態(tài)方法,創(chuàng)建代理對象,并把返回值轉(zhuǎn)換成接口類型
創(chuàng)建一個(gè)MainShop類.
public class MainShop {public static void main(String[] args){ // 1.創(chuàng)建對象,使用Proxy // 2.創(chuàng)建目標(biāo)對象UsbSell factory = new UsbKingFactory(); // 3.創(chuàng)建Invocationhandler對象InvocationHandler myHandle = new MyHandle(factory);// 4.創(chuàng)建代理對象UsbSell proxy = (UsbSell) Proxy.newProxyInstance(factory.getClass().getClassLoader(),factory.getClass().getInterfaces(),myHandle); // 通過代理執(zhí)行方法float price = proxy.sell(1);System.out.println("通過動態(tài)代理對象,調(diào)用方法:" +price);} }執(zhí)行成功.和之前動態(tài)代理模式一樣
05 JDK動態(tài)代理執(zhí)行流程
Proxy類,實(shí)現(xiàn)動態(tài)代理的流程,使用返回指定接口的代理類實(shí)例,
我們此時(shí)debug一下程序,在invok實(shí)現(xiàn)類中打一個(gè)斷點(diǎn)
此時(shí)我們再觀察,代理對象MyHandler里面的invoke方法的參數(shù)
06 靜態(tài)代理項(xiàng)目中的應(yīng)用
我們需要知道代理能做什么?
在不改變原來目標(biāo)方法功能的前提下,可以在代理中增強(qiáng)自己的功能代碼,程序開發(fā)中的意思,
比如:你所在的項(xiàng)目,有一個(gè)功能是其他人(公司其他部門,其他小組的人)寫好的,你可以使用
//比如,同事開發(fā)一個(gè)GoNong類 GoNong.class , GoNong gn=new GoNong()//我們需要增加一個(gè)print方法我們發(fā)現(xiàn)這個(gè)功能現(xiàn)在還存在缺點(diǎn),不能完全滿足我項(xiàng)目的需要,我需要在print()執(zhí)行過后,需要自己再增加代理,使用什么方法那,肯定是代理,因?yàn)閯e人不會讓我們看源文件
執(zhí)行步驟:
我們設(shè)置一個(gè)類來使用這個(gè)接口
public class MyApp {public static void main(String[] args){GoNeng gn = new GoNeng();int i = gn.print("nihao1");System.out.println("num" +i);} }問題是如果我們想修改這個(gè)功能改怎么辦?在不修改源代碼的基礎(chǔ)上,我們可以創(chuàng)建一個(gè)代理類,來增強(qiáng)這個(gè)類方法,
測試System.out.println("動態(tài)代理類參數(shù)接口"+goNeng.getClass().getInterfaces()[0].getName());
動態(tài)代理類參數(shù)接口com.rango.service.HelloService 其他人寫好的這個(gè)方法! 我們期望得到的 num ==407 完結(jié)
動態(tài)代理,必須要有接口出現(xiàn),如果沒有,我們可以使用cglib實(shí)現(xiàn)
總結(jié)
以上是生活随笔為你收集整理的23种设计模式——JDK动态代理(AOP)的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: SylixOS 经得起检验的国产操作系统
- 下一篇: 微信公共服务平台开发(.Net 的实现)