Java設(shè)計模式——代理模式

最近看到一篇關(guān)于講代理的文章,接觸到了一些jdk動態(tài)代理,然后寫一篇文章加深下記憶。
主要講靜態(tài)代理和動態(tài)代理,通俗一點就是在原對象的基礎(chǔ)上增加原對象的功能,比如說:在原對象的調(diào)用方法前后進行日志記錄、事務(wù)操作等。Spring AOP就是用了代理模式,后續(xù)有機會看看這部分源碼。

1.RPC(Remote Procedure Call)

—[ 遠程過程調(diào)用 ] 它是一種通過網(wǎng)絡(luò)從遠程計算機程序上請求服務(wù),而不需要了解底層網(wǎng)絡(luò)技術(shù)的協(xié)議。

接觸到的一種概念,好像沒啥關(guān)系。


2. 靜態(tài)代理

在程序運行前就已經(jīng)存在的編寫好的代理類
大概就四個步驟:

  1. 定義接口 業(yè)務(wù)接口
  2. 實現(xiàn)接口 被代理類實現(xiàn)接口
  3. 再次實現(xiàn)接口 代理類實現(xiàn)接口
  4. 客戶端調(diào)用
    從上面的步驟主要看出來要寫三個類 業(yè)務(wù)類、被代理類 、代理類,客戶端調(diào)用的類我們暫且不管,下面來看代碼的實現(xiàn):

2.1 業(yè)務(wù)接口 也可稱被代理的接口

主要就是定義業(yè)務(wù)要實現(xiàn)的功能

package com.zhb.jdk.proxy;

public interface IUserService {
 
 void add(String name);
 
}

2.2 被代理類

通常這個地方就是我們實現(xiàn)接口的類

package com.zhb.jdk.proxy;

public class UserServiceImpl implements IUserService { 
 
 @Override 
 public void add(String name) { 
   System.out.println("向數(shù)據(jù)庫中插入名為: "+name+" 的用戶"); 
 } 
 
}

2.3 代理類

這個類就是我們需要添加的代理類,一般代理類命名都會加上proxy,可以由此來判斷是否是代理類。
它主要就是兩個部分,第一部分就是構(gòu)造函數(shù)傳入被代理類,然后在實現(xiàn)業(yè)務(wù)接口,重寫業(yè)務(wù)接口的方法,并且在重寫方法里,調(diào)用被代理類的方法。然后在調(diào)用被代理類的方法的前后你就可以進行自己的業(yè)務(wù)操作。

package com.zhb.jdk.proxy; 

public class UserServiceProxy implements IUserService { 
 
 // 被代理對象
 private IUserService target; 
 
 // 通過構(gòu)造方法傳入被代理對象 
 public UserServiceProxy(IUserService target) {
   this.target = target; 
 } 
 
 @Override 
 public void add(String name) {
   
   System.out.println("準備向數(shù)據(jù)庫中插入數(shù)據(jù)"); 
   target.add(name); 
   System.out.println("插入數(shù)據(jù)庫成功"); 
 }
 
}

2.4 客戶端調(diào)用

使用代理的話,主要就是兩個部分,第一:就是先實例化被代理類,然后在是實例化代理類時,將被代理類傳入,最后調(diào)用代理類的方法,執(zhí)行。

package com.zhb.jdk.proxy;

public class StaticProxyTest {
 
 public static void main(String[] args) {
   
   IUserService target = new UserServiceImpl();
   UserServiceProxy proxy = new UserServiceProxy(target);
   proxy.add("陳粒");
 }
}

靜態(tài)代理就這樣實現(xiàn)了,很簡單的,也容易理解的。


3. 動態(tài)代理

為啥要動態(tài)代理,因為靜態(tài)代理有缺點,1. 兩次實現(xiàn)業(yè)務(wù)接口,接口 增加方法,兩個類都需要修改;2. 代理對象只服務(wù)于一種類型的對象,如果要服務(wù)多類型的對象。比如上面的例子,只是對用戶的業(yè)務(wù)功能(IUserService)進行代理,如果是商品(IItemService)的業(yè)務(wù)功能那就無法代理,需要去編寫商品服務(wù)的代理類。
所以有了動態(tài)代理 ,所謂動態(tài)代理是指:在程序運行期間根據(jù)需要動態(tài)創(chuàng)建代理類及其實例來完成具體的功能。

動態(tài)代理主要分為JDK動態(tài)代理cglib動態(tài)代理兩大類,本文主要對JDK動態(tài)代理進行探討。

主要步驟有以下:

  1. 創(chuàng)建被代理的接口和它的實現(xiàn)類
  2. 創(chuàng)建InvocationHandler接口的實現(xiàn)類,在invoke方法中實現(xiàn)代理邏輯;
  3. 通過Proxy的靜態(tài)方法newProxyInstance( ClassLoaderloader, Class[] interfaces, InvocationHandler h)創(chuàng)建一個代理對象
  4. 使用代理對象。

3.1 被代理的接口和它的實現(xiàn)類

還是使用上面靜態(tài)代理的兩個

3.2 創(chuàng)建InvocationHandler接口的實現(xiàn)類

這個實現(xiàn)類也是構(gòu)造函數(shù)傳入 被代理接口的實現(xiàn)類,然后重寫InvocationHandler接口invoke方法,然后在method.invoke方法前后去完成自己需要加入的操作,記錄日志呀、事務(wù)操作等;看到這里應(yīng)該就懂了,這個方法是特定的,不管你被代理的業(yè)務(wù)接口有多少個方法。

package com.zhb.jdk.dynamicProxy;

import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;

public class MyInvocationHandler implements InvocationHandler {
 
 //被代理對象,Object類型 
 private Object target;
 
 public MyInvocationHandler(Object target) { 
   this.target = target; 
 } 
 
 @Override 
 public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
   
   System.out.println("準備向數(shù)據(jù)庫中插入數(shù)據(jù)"); 
   Object returnvalue = method.invoke(target, args); 
   System.out.println("插入數(shù)據(jù)庫成功"); 
   return returnvalue; 
 }
 
}

3.3 客戶端調(diào)用

然后這塊主要理解invoke方法的傳入的參數(shù)

  1. 第一個參數(shù)是指定代理類的類加載器(我們傳入當前測試類的類加載器)
  2. 第二個參數(shù)是代理類需要實現(xiàn)的接口(我們傳入被代理類實現(xiàn)的接口,這樣生成的代理類和被代理類就實現(xiàn)了相同的接口)
  3. 第三個參數(shù)是invocation handler,用來處理方法的調(diào)用。這里傳入我們自己實現(xiàn)的handler
package com.zhb.jdk.dynamicProxy;

import java.lang.reflect.Proxy;


public class DynamicProxyTest {
 
 public static void main(String[] args) {
   
   IUserService target = new UserServiceImpl();
   MyInvocationHandler handler = new MyInvocationHandler(target);   
   IUserService proxyObject = (IUserService) Proxy.newProxyInstance(DynamicProxyTest.class.getClassLoader(), 
       target.getClass().getInterfaces(), handler); 
   proxyObject.add("陳粒"); 
 }
}

實際上,動態(tài)代理的代理對象是在內(nèi)存中的,是JDK根據(jù)我們傳入的參數(shù)生成好的。那動態(tài)代理的代理類和代理對象是怎么產(chǎn)生的呢?

這塊就需要去查閱jdk的源碼了。下次再會!

記住胖子不是一口吃成的!加油!

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

  • 參考資料:菜鳥教程之設(shè)計模式 設(shè)計模式概述 設(shè)計模式(Design pattern)代表了最佳的實踐,通常被有經(jīng)驗...
    Steven1997閱讀 1,267評論 1 12
  • 定義 代理模式是對象的結(jié)構(gòu)模式。代理模式給某一個對象提供代理對象,并由代理對象控制對源對象的引用。 代理模式的結(jié)構(gòu)...
    步積閱讀 6,604評論 0 1
  • 欣賞自己:每天都很忙碌,總覺得時間不夠用,為了將來那個優(yōu)秀的自己,我堅持著!給自己一個大大的贊! 欣賞戰(zhàn)友:此處省...
    汪小小樣閱讀 321評論 0 1
  • 大學(xué)的第一學(xué)期,恍惚間就過去了!此刻,收拾好行囊的我,在火車站等待著火車。 這個學(xué)期學(xué)到了什么,收獲了什么,仿佛很...
    葉寸心閱讀 201評論 0 0
  • 四號的感冒加重,這次是真的嚴重了,喝藥并不管用。 漫展拍到的照片還在社團編輯部后期,其實我也蠻想幫忙的,無奈沒網(wǎng)…...
    龍孟秋閱讀 258評論 2 2

友情鏈接更多精彩內(nèi)容