欧美bbbwbbbw肥妇,免费乱码人妻系列日韩,一级黄片

Java代理模式與動(dòng)態(tài)代理之間的關(guān)系以及概念

 更新時(shí)間:2023年02月20日 15:16:26   作者:綠仔牛奶_  
代理模式是開(kāi)發(fā)中常見(jiàn)的一種設(shè)計(jì)模式,使用代理模式可以很好的對(duì)程序進(jìn)行橫向擴(kuò)展。動(dòng)態(tài)代理:代理類(lèi)在程序運(yùn)行時(shí)被創(chuàng)建的代理方式。關(guān)鍵在于動(dòng)態(tài),程序具有了動(dòng)態(tài)特性,可以在運(yùn)行期間根據(jù)不同的目標(biāo)對(duì)象生成動(dòng)態(tài)代理對(duì)象

什么是代理模式

代理模式是開(kāi)發(fā)中常見(jiàn)的一種設(shè)計(jì)模式,使用代理模式可以很好的對(duì)程序進(jìn)行橫向擴(kuò)展。代理,顧名思義就是一個(gè)真實(shí)對(duì)象會(huì)存在一個(gè)代理對(duì)象,并且代理對(duì)象可以替真實(shí)對(duì)象完成相應(yīng)操作,外部通過(guò)代理對(duì)象來(lái)訪問(wèn)真實(shí)對(duì)象并且還可以在代理對(duì)象中進(jìn)行額外操作的擴(kuò)展。

代理模式的特征是擁有接口、代理類(lèi)、被代理類(lèi)。并且代理類(lèi)與被代理類(lèi)同時(shí)實(shí)現(xiàn)該接口。代理類(lèi)與被代理類(lèi)之間通常存在一定關(guān)聯(lián),設(shè)計(jì)時(shí)會(huì)在代理類(lèi)中注冊(cè)一個(gè)被代理類(lèi)的對(duì)象用于調(diào)用代理類(lèi)的方法。這也印證了代理對(duì)象依然是執(zhí)行的真實(shí)對(duì)象的方法

代理模式又分為靜態(tài)代理和動(dòng)態(tài)代理

靜態(tài)代理

靜態(tài)代理,關(guān)鍵字靜態(tài)是指在程序運(yùn)行之前編譯時(shí)就已經(jīng)確定了代理類(lèi)、被代理類(lèi)、接口。

下面列舉兩個(gè)示例展示靜態(tài)代理:

學(xué)生通過(guò)班長(zhǎng)交班費(fèi),班長(zhǎng)作為學(xué)生的代理,學(xué)生是被代理,具有同一行為就是交班費(fèi),這個(gè)行為我們用接口進(jìn)行約束

程序:

// 接口
public interface Person {void giveMoney();}
// 學(xué)生類(lèi)--> 被代理類(lèi)
public class Student implements Person{
  private String name;
  public Student(String name) {this.name = name;}
  public void giveMoney() {
    System.out.println(name+"同學(xué)上交50元班費(fèi)");
  }
}
// 學(xué)生代理類(lèi)
public class StuProxy implements Person{
  private Student stu;
  public StuProxy(Student stu) {
    if (stu.getClass() == Student.class) {
      this.stu = stu;
    }
  }
  public void giveMoney() {stu.giveMoney();}
}

測(cè)試:

public static void main(String[] args) {
  // 獲取學(xué)生實(shí)例  
  Student stu = new Student("張三");
  // 學(xué)生找交錢(qián)給班長(zhǎng)  學(xué)生找到代理
  StuProxy stuProxy = new StuProxy(stu);
  // 班長(zhǎng)交給老師  代理交錢(qián)(交的是學(xué)生的錢(qián))
  stuProxy.giveMoney();
}

房屋租賃,租客通過(guò)中介找房源,租客為被代理類(lèi),中介為代理類(lèi),接口聲明租房方法

// 接口
public interface Rent {void doRent();}
// 被代理類(lèi)
public class Renter implements Rent{
  public void doRent() {
    System.out.println("租客租房了");
  }
}
// 代理類(lèi)
public class RentProxy implements Rent{
  private Renter renter;
  public RentProxy(Renter renter) {
    if (renter.getClass()==Renter.class)
      this.renter = renter;
  }
  public void doRent() {renter.doRent();}
}

測(cè)試:

public static void main(String[] args) {
  // 創(chuàng)建租客
  Renter renter = new Renter();
  // 租客找到中介
  RentProxy rentProxy = new RentProxy(renter);
  // 租客租房
  rentProxy.doRent();
}

上述兩個(gè)示例,向代理類(lèi)中注入被代理對(duì)象的方式都是通過(guò)構(gòu)造器注入,當(dāng)然也可以通過(guò)set方法注入

下面演示如果需要在已經(jīng)編寫(xiě)好的代理類(lèi)的輸出中添加其他操作時(shí)的操作比如打印一個(gè)日志,在不修改源代碼的情況下擴(kuò)展

// 下面是最經(jīng)典的Service層的寫(xiě)法
public interface UserService {
    void del();
    void select();
}
public class UserServiceImpl implements UserService{
    public void del() {
        System.out.println("刪除操作");
    }
    public void select() {
        System.out.println("查詢(xún)操作");
    }
}

假設(shè)現(xiàn)在我們需要在每一次執(zhí)行操作前后打印一次執(zhí)行日志,并且不能修改源代碼那么就可以用到代理模式,將UserServiceImpl作為被代理類(lèi),擴(kuò)展代理類(lèi)如下:

public class UserServiceImplProxy implements UserService{
  private UserServiceImpl userService;
  // set注入
  public void setUserService(UserServiceImpl userService) {
    this.userService = userService;
  }
  public void del() {
    printLog();
    userService.del();
  }
  public void select() {
    printLog();
    userService.select();
  }
  private void printLog(){
    System.out.println("執(zhí)行時(shí)間="+new Date());
  }
}

動(dòng)態(tài)代理

動(dòng)態(tài)代理:代理類(lèi)在程序運(yùn)行時(shí)被創(chuàng)建的代理方式。

關(guān)鍵在于動(dòng)態(tài),程序具有了動(dòng)態(tài)特性,可以在運(yùn)行期間根據(jù)不同的目標(biāo)對(duì)象生成動(dòng)態(tài)代理對(duì)象,并且可以通過(guò)動(dòng)態(tài)代理對(duì)象對(duì)目標(biāo)對(duì)象(真實(shí)對(duì)象)進(jìn)行功能性補(bǔ)強(qiáng)。大白話來(lái)講就是,可以在程序運(yùn)行期間額外的對(duì)真實(shí)對(duì)象功能進(jìn)行擴(kuò)展。

此處的動(dòng)態(tài)代理對(duì)象不是通過(guò)預(yù)先編寫(xiě)好的程序生成的,而是運(yùn)行期間由于用戶需求或者說(shuō)是代碼的指示生成的

動(dòng)態(tài)代理分為兩種:一類(lèi)是基于接口實(shí)現(xiàn)的動(dòng)態(tài)代理,另一類(lèi)是基于類(lèi)的動(dòng)態(tài)代理

基于接口的動(dòng)態(tài)代理–JDK動(dòng)態(tài)代理通過(guò)反射完成,基于類(lèi)實(shí)現(xiàn)的–>cglib

JDK動(dòng)態(tài)代理核心:Proxy類(lèi)、InvocationHandler接口、要參與代理的目標(biāo)類(lèi)必須實(shí)現(xiàn)對(duì)應(yīng)接口,比如上述的Student必須實(shí)現(xiàn)Person接口。

繼續(xù)以上述學(xué)生交班費(fèi)為例,更改為動(dòng)態(tài)代理模式:

JDK動(dòng)態(tài)代理中間類(lèi):該類(lèi)需要實(shí)現(xiàn)InvocationHandler接口

// JDK動(dòng)態(tài)代理中間類(lèi)
public class ProxyInvocationHandler implements InvocationHandler {
  // 被代理的對(duì)象
  private Object target;
  // ser方法注入?yún)?shù)
  public void setTarget(Object target) {this.target = target;}
  // 生成動(dòng)態(tài)代理類(lèi)
  public Object getProxy(){
    return Proxy.newProxyInstance(this.getClass().getClassLoader(),
target.getClass().getInterfaces(),this);
  }
  // 處理代理實(shí)例,并返回結(jié)果
  public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
    Object result = method.invoke(target,args);
    return result;
  }
}

測(cè)試:

public static void main(String[] args) {
  // 獲取真實(shí)角色
  Student stu = new Student("張三三");
  // 動(dòng)態(tài)代理中間類(lèi)對(duì)象
  InvocationHandlerProxyStudent proxyStudent = new InvocationHandlerProxyStudent();
  proxyStudent.setStu(stu);
  // 代理類(lèi)實(shí)例
  Person proxy = (Person) proxyStudent.getProxy();
  // 代理類(lèi)實(shí)例調(diào)用方法
  proxy.giveMoney();
}

上述程序,我們利用Proxy來(lái)生成代理類(lèi):

public Object getProxy(){
  return Proxy.newProxyInstance(this.getClass().getClassLoader(),
stu.getClass().getInterfaces(),this);
}

Proxy提供了靜態(tài)的獲取Proxy代理類(lèi)的方法newProxyInstance,三個(gè)參數(shù)分別是1.類(lèi)加載器 2.代理對(duì)象實(shí)現(xiàn)的接口 3. 調(diào)用處理程序(InvocationHandler)

在InvocationHandler官方文檔就已經(jīng)指出,每一個(gè)代理實(shí)例都關(guān)聯(lián)有一個(gè)InvocationHandler調(diào)用處理程序,所以這里填this即可

在使用代理類(lèi)的時(shí)候首先我們創(chuàng)建需要被代理的真實(shí)對(duì)象和動(dòng)態(tài)代理中間類(lèi)的對(duì)象,用set方法將真實(shí)對(duì)象交給中間類(lèi)中的代理對(duì)象。在調(diào)用上述getProxy方法獲取代理類(lèi)。動(dòng)態(tài)代理相對(duì)于靜態(tài)代理有些難以理解,這是因?yàn)殪o態(tài)代理的代理類(lèi)可以在程序中顯式的被看到,而動(dòng)態(tài)代理中的代理類(lèi)文件是緩存在Java虛擬機(jī),類(lèi)名叫$Proxy0。

在虛擬機(jī)中生成的代理類(lèi)中就會(huì)將我們所調(diào)用的方法內(nèi)置,我們?cè)趫?zhí)行proxy.giveMoney()的同時(shí),實(shí)際上是將giveMoney()方法作為參數(shù)傳進(jìn)invoke()的參數(shù)中去,而此時(shí)我們就可以將其他的操作交給invoke,由于所有代理對(duì)象在執(zhí)行時(shí)最終都會(huì)走invoke方法,所以也為我們的開(kāi)發(fā)節(jié)省大量代碼

到此這篇關(guān)于Java代理模式與動(dòng)態(tài)代理之間的關(guān)系以及概念的文章就介紹到這了,更多相關(guān)Java代理模式與動(dòng)態(tài)代理內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!

相關(guān)文章

  • Spring AOP如何實(shí)現(xiàn)注解式的Mybatis多數(shù)據(jù)源切換詳解

    Spring AOP如何實(shí)現(xiàn)注解式的Mybatis多數(shù)據(jù)源切換詳解

    這篇文章主要給大家介紹了關(guān)于Spring AOP如何實(shí)現(xiàn)注解式的Mybatis多數(shù)據(jù)源切換的相關(guān)資料,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧
    2020-11-11
  • Springboot打包部署項(xiàng)目的過(guò)程詳解

    Springboot打包部署項(xiàng)目的過(guò)程詳解

    這篇文章主要介紹了Springboot打包部署項(xiàng)目的過(guò)程,通過(guò)jar包方式打包和war方式打包,本文結(jié)合示例代碼給大家介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友參考下吧
    2023-12-12
  • idea修改maven模塊名稱(chēng)還顯示老名稱(chēng)問(wèn)題解決

    idea修改maven模塊名稱(chēng)還顯示老名稱(chēng)問(wèn)題解決

    本文主要介紹了idea修改maven模塊名稱(chēng)還顯示老名稱(chēng)問(wèn)題解決,文中通過(guò)圖文介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧
    2023-11-11
  • 詳解Java中Collection集合的常用方法

    詳解Java中Collection集合的常用方法

    本篇文章給大家?guī)?lái)的內(nèi)容是關(guān)于Java中Collection集合的常用方法詳解,有一定的參考價(jià)值,有需要的朋友可以參考一下,希望對(duì)你有所幫助。下面我們就來(lái)學(xué)習(xí)一下吧
    2021-11-11
  • BeanFactory和FactoryBean的區(qū)別示例詳解

    BeanFactory和FactoryBean的區(qū)別示例詳解

    這篇文章主要為大家介紹了BeanFactory和FactoryBean的區(qū)別示例詳解,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪
    2022-10-10
  • 新聞列表的分頁(yè)查詢(xún)java代碼實(shí)現(xiàn)

    新聞列表的分頁(yè)查詢(xún)java代碼實(shí)現(xiàn)

    這篇文章主要為大家詳細(xì)介紹了新聞列表的分頁(yè)查詢(xún)java代碼實(shí)現(xiàn),感興趣的小伙伴們可以參考一下
    2016-08-08
  • Java的string類(lèi)為什么是不可變的

    Java的string類(lèi)為什么是不可變的

    這篇文章主要介紹了Java的string類(lèi)為什么是不可變的,總結(jié)了三個(gè)答案,需要的朋友可以參考下
    2014-04-04
  • Spring Boot實(shí)現(xiàn)自動(dòng)發(fā)送郵件

    Spring Boot實(shí)現(xiàn)自動(dòng)發(fā)送郵件

    這篇文章主要為大家詳細(xì)介紹了Spring Boot實(shí)現(xiàn)自動(dòng)發(fā)送郵件,文中示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下
    2020-02-02
  • Java實(shí)現(xiàn)的猴子吃桃問(wèn)題算法示例

    Java實(shí)現(xiàn)的猴子吃桃問(wèn)題算法示例

    這篇文章主要介紹了Java實(shí)現(xiàn)的猴子吃桃問(wèn)題算法,簡(jiǎn)單描述了猴子吃桃問(wèn)題并結(jié)合實(shí)例形式給出了java解決猴子吃桃問(wèn)題的具體實(shí)現(xiàn)技巧,需要的朋友可以參考下
    2017-10-10
  • IDEA上運(yùn)行Flink任務(wù)的實(shí)戰(zhàn)教程

    IDEA上運(yùn)行Flink任務(wù)的實(shí)戰(zhàn)教程

    這篇文章主要介紹了IDEA上運(yùn)行Flink任務(wù)的實(shí)戰(zhàn)教程,本文通過(guò)圖文并茂的形式給大家介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下
    2020-10-10

最新評(píng)論