最新国产好看的视频,伊人天堂AV在线,国产Aaaaaa视频,蜜臀视频在线观看一区,人妻av色图,密臀久久久精品影片,青青视频免费观看毛片,久草在线观看视,国产三级精品色情在线

java 中動態(tài)代理機制的實例講解

 更新時間:2017年09月19日 11:36:54   投稿:lqh  
這篇文章主要介紹了java 中動態(tài)代理機制的實例講解的相關(guān)資料,希望通過本文大家能夠理解掌握動態(tài)代理機制,需要的朋友可以參考下

java 中動態(tài)代理機制的實例講解

在學(xué)習Spring的時候,我們知道Spring主要有兩大思想,一個是IoC,另一個就是AOP,對于IoC,依賴注入就不用多說了,而對于Spring的核心AOP來說,我們不但要知道怎么通過AOP來滿足的我們的功能,我們更需要學(xué)習的是其底層是怎么樣的一個原理,而AOP的原理就是java的動態(tài)代理機制,所以本篇隨筆就是對java的動態(tài)機制進行一個回顧。

在java的動態(tài)代理機制中,有兩個重要的類或接口,一個是 InvocationHandler(Interface)、另一個則是 Proxy(Class),這一個類和接口是實現(xiàn)我們動態(tài)代理所必須用到的。首先我們先來看看java的API幫助文檔是怎么樣對這兩個類進行描述的:

InvocationHandler:

InvocationHandler is the interface implemented by the invocation handler of a proxy instance. 

Each proxy instance has an associated invocation handler. When a method is invoked on a proxy instance, the method invocation is encoded and dispatched to the invoke method of its invocation handler.

每一個動態(tài)代理類都必須要實現(xiàn)InvocationHandler這個接口,并且每個代理類的實例都關(guān)聯(lián)到了一個handler,當我們通過代理對象調(diào)用一個方法的時候,這個方法的調(diào)用就會被轉(zhuǎn)發(fā)為由InvocationHandler這個接口的 invoke 方法來進行調(diào)用。我們來看看InvocationHandler這個接口的唯一一個方法 invoke 方法:

Object invoke(Object proxy, Method method, Object[] args) throws Throwable

我們看到這個方法一共接受三個參數(shù),那么這三個參數(shù)分別代表什么呢?

  • proxy:  指代我們所代理的那個真實對象
  • method:  指代的是我們所要調(diào)用真實對象的某個方法的Method對象
  • args:  指代的是調(diào)用真實對象某個方法時接受的參數(shù)

如果不是很明白,等下通過一個實例會對這幾個參數(shù)進行更深的講解。

接下來我們來看看Proxy這個類:

Proxy provides static methods for creating dynamic proxy classes and instances, and it is
 also the superclass of all dynamic proxy classes created by those methods.

Proxy這個類的作用就是用來動態(tài)創(chuàng)建一個代理對象的類,它提供了許多的方法,但是我們用的最多的就是 newProxyInstance 這個方法:

public static Object newProxyInstance(ClassLoader loader, Class<?>[] interfaces, InvocationHandler h) 
 throws IllegalArgumentException
Returns an instance of a proxy class for the specified interfaces that dispatches method
 invocations to the specified invocation handler.

這個方法的作用就是得到一個動態(tài)的代理對象,其接收三個參數(shù),我們來看看這三個參數(shù)所代表的含義:

  • loader:一個ClassLoader對象,定義了由哪個ClassLoader對象來對生成的代理對象進行加載
  • interfaces:一個Interface對象的數(shù)組,表示的是我將要給我需要代理的對象提供一組什么接口,如果我提供了一組接口給它,那么這個代理對象就宣稱實現(xiàn)了該接口(多態(tài)),這樣我就能調(diào)用這組接口中的方法了
  • h:一個InvocationHandler對象,表示的是當我這個動態(tài)代理對象在調(diào)用方法的時候,會關(guān)聯(lián)到哪一個InvocationHandler對象上

好了,在介紹完這兩個接口(類)以后,我們來通過一個實例來看看我們的動態(tài)代理模式是什么樣的:

首先我們定義了一個Subject類型的接口,為其聲明了兩個方法:

public interface Subject
{
  public void rent();

  public void hello(String str);
}

接著,定義了一個類來實現(xiàn)這個接口,這個類就是我們的真實對象,RealSubject類:

public class RealSubject implements Subject
{
  @Override
  public void rent()
  {
    System.out.println("I want to rent my house");
  }

  @Override
  public void hello(String str)
  {
    System.out.println("hello: " + str);
  }
}

下一步,我們就要定義一個動態(tài)代理類了,前面說個,每一個動態(tài)代理類都必須要實現(xiàn) InvocationHandler 這個接口,因此我們這個動態(tài)代理類也不例外:

public class DynamicProxy implements InvocationHandler
{
  // 這個就是我們要代理的真實對象
  private Object subject;

  //  構(gòu)造方法,給我們要代理的真實對象賦初值
  public DynamicProxy(Object subject)
  {
    this.subject = subject;
  }

  @Override
  public Object invoke(Object object, Method method, Object[] args)
      throws Throwable
  {
    //  在代理真實對象前我們可以添加一些自己的操作
    System.out.println("before rent house");

    System.out.println("Method:" + method);

    //  當代理對象調(diào)用真實對象的方法時,其會自動的跳轉(zhuǎn)到代理對象關(guān)聯(lián)的handler對象的invoke方法來進行調(diào)用
    method.invoke(subject, args);

    //  在代理真實對象后我們也可以添加一些自己的操作
    System.out.println("after rent house");

    return null;
  }

}

最后,來看看我們的Client類:

/**
 * Java學(xué)習交流QQ群:589809992 我們一起學(xué)Java!
 */
public class Client
{
  public static void main(String[] args)
  {
    //  我們要代理的真實對象
    Subject realSubject = new RealSubject();

    //  我們要代理哪個真實對象,就將該對象傳進去,最后是通過該真實對象來調(diào)用其方法的
    InvocationHandler handler = new DynamicProxy(realSubject);

    /*
     * 通過Proxy的newProxyInstance方法來創(chuàng)建我們的代理對象,我們來看看其三個參數(shù)
     * 第一個參數(shù) handler.getClass().getClassLoader() ,我們這里使用handler這個類的ClassLoader對象來加載我們的代理對象
     * 第二個參數(shù)realSubject.getClass().getInterfaces(),我們這里為代理對象提供的接口是真實對象所實行的接口,表示我要代理的是該真實對象,這樣我就能調(diào)用這組接口中的方法了
     * 第三個參數(shù)handler, 我們這里將這個代理對象關(guān)聯(lián)到了上方的 InvocationHandler 這個對象上
     */
    Subject subject = (Subject)Proxy.newProxyInstance(handler.getClass().getClassLoader(), realSubject
        .getClass().getInterfaces(), handler);

    System.out.println(subject.getClass().getName());
    subject.rent();
    subject.hello("world");
  }
}

我們先來看看控制臺的輸出:

$Proxy0

before rent house
Method:public abstract void com.xiaoluo.dynamicproxy.Subject.rent()
I want to rent my house
after rent house

before rent house
Method:public abstract void com.xiaoluo.dynamicproxy.Subject.hello(java.lang.String)
hello: world
after rent house

我們首先來看看 $Proxy0 這東西,我們看到,這個東西是由 System.out.println(subject.getClass().getName()); 這條語句打印出來的,那么為什么我們返回的這個代理對象的類名是這樣的呢?

Subject subject = (Subject)Proxy.newProxyInstance(handler.getClass().getClassLoader(), realSubject
        .getClass().getInterfaces(), handler);

可能我以為返回的這個代理對象會是Subject類型的對象,或者是InvocationHandler的對象,結(jié)果卻不是,首先我們解釋一下為什么我們這里可以將其轉(zhuǎn)化為Subject類型的對象?原因就是在newProxyInstance這個方法的第二個參數(shù)上,我們給這個代理對象提供了一組什么接口,那么我這個代理對象就會實現(xiàn)了這組接口,這個時候我們當然可以將這個代理對象強制類型轉(zhuǎn)化為這組接口中的任意一個,因為這里的接口是Subject類型,所以就可以將其轉(zhuǎn)化為Subject類型了。

同時我們一定要記住,通過 Proxy.newProxyInstance 創(chuàng)建的代理對象是在jvm運行時動態(tài)生成的一個對象,它并不是我們的InvocationHandler類型,也不是我們定義的那組接口的類型,而是在運行是動態(tài)生成的一個對象,并且命名方式都是這樣的形式,以$開頭,proxy為中,最后一個數(shù)字表示對象的標號。

接著我們來看看這兩句

subject.rent(); 
subject.hello(“world”);

這里是通過代理對象來調(diào)用實現(xiàn)的那種接口中的方法,這個時候程序就會跳轉(zhuǎn)到由這個代理對象關(guān)聯(lián)到的 handler 中的invoke方法去執(zhí)行,而我們的這個 handler 對象又接受了一個 RealSubject類型的參數(shù),表示我要代理的就是這個真實對象,所以此時就會調(diào)用 handler 中的invoke方法去執(zhí)行:

/**
 * Java學(xué)習交流QQ群:589809992 我們一起學(xué)Java!
 */
public Object invoke(Object object, Method method, Object[] args)
      throws Throwable
  {
    //  在代理真實對象前我們可以添加一些自己的操作
    System.out.println("before rent house");

    System.out.println("Method:" + method);

    //  當代理對象調(diào)用真實對象的方法時,其會自動的跳轉(zhuǎn)到代理對象關(guān)聯(lián)的handler對象的invoke方法來進行調(diào)用
    method.invoke(subject, args);

    //  在代理真實對象后我們也可以添加一些自己的操作
    System.out.println("after rent house");

    return null;
  }

我們看到,在真正通過代理對象來調(diào)用真實對象的方法的時候,我們可以在該方法前后添加自己的一些操作,同時我們看到我們的這個 method 對象是這樣的:

public abstract void com.xiaoluo.dynamicproxy.Subject.rent()

public abstract void com.xiaoluo.dynamicproxy.Subject.hello(java.lang.String)

正好就是我們的Subject接口中的兩個方法,這也就證明了當我通過代理對象來調(diào)用方法的時候,起實際就是委托由其關(guān)聯(lián)到的 handler 對象的invoke方法中來調(diào)用,并不是自己來真實調(diào)用,而是通過代理的方式來調(diào)用的。

這就是我們的java動態(tài)代理機制。

本篇隨筆詳細的講解了java中的動態(tài)代理機制,這個知識點非常非常的重要,包括我們Spring的AOP其就是通過動態(tài)代理的機制實現(xiàn)的,所以我們必須要好好的理解動態(tài)代理的機制。

如有疑問請留言或者到本站社區(qū)交流討論,感謝閱讀,希望能幫助到大家,謝謝大家對本站的支持!

相關(guān)文章

  • @RequiredArgsConstructor如何實現(xiàn)構(gòu)造器注入

    @RequiredArgsConstructor如何實現(xiàn)構(gòu)造器注入

    這篇文章主要介紹了@RequiredArgsConstructor如何實現(xiàn)構(gòu)造器注入問題,具有很好的參考價值,希望對大家有所幫助,如有錯誤或未考慮完全的地方,望不吝賜教
    2024-09-09
  • java 讀取文件路徑空格、

    java 讀取文件路徑空格、"+"和中文的處理方法

    今天小編就為大家分享一篇java 讀取文件路徑空格、"+"和中文的處理方法,具有很好的參考價值,希望對大家有所幫助。一起跟隨小編過來看看吧
    2018-07-07
  • mybatis-plus更新字段為null的處理方式

    mybatis-plus更新字段為null的處理方式

    這篇文章主要介紹了mybatis-plus更新字段為null的處理方式,具有很好的參考價值,希望對大家有所幫助。如有錯誤或未考慮完全的地方,望不吝賜教
    2022-08-08
  • Java8新特性之JavaFX 8_動力節(jié)點Java學(xué)院整理

    Java8新特性之JavaFX 8_動力節(jié)點Java學(xué)院整理

    這篇文章主要介紹了Java8新特性之JavaFX 8的相關(guān)知識,非常不錯,具有參考借鑒價值,需要的朋友參考下吧
    2017-06-06
  • Java常用類之日期相關(guān)類使用詳解

    Java常用類之日期相關(guān)類使用詳解

    這篇文章主要為大家介紹了Java中常用類的日期相關(guān)類的用法教程,文中的示例代碼講解詳細,對我們學(xué)習Java有一定的幫助,需要的可以參考一下
    2022-08-08
  • SpringBoot項目如何添加2FA雙因素身份認證

    SpringBoot項目如何添加2FA雙因素身份認證

    雙因素身份驗證2FA是一種安全系統(tǒng),要求用戶提供兩種不同的身份驗證方式才能訪問某個系統(tǒng)或服務(wù),國內(nèi)普遍做短信驗證碼這種的用的比較少,不過在國外的網(wǎng)站中使用雙因素身份驗證的還是很多的,這篇文章主要介紹了SpringBoot項目如何添加2FA雙因素身份認證,需要的朋友參考下
    2024-04-04
  • Java寫出生肖年判斷

    Java寫出生肖年判斷

    本篇文章主要給大家分享一篇關(guān)于用JAVA寫出生肖判斷的小功能,有興趣的跟著學(xué)習下。
    2018-02-02
  • IDEA創(chuàng)建springboot + mybatis項目全過程(步驟詳解)

    IDEA創(chuàng)建springboot + mybatis項目全過程(步驟詳解)

    這篇文章主要介紹了IDEA創(chuàng)建springboot + mybatis項目全過程及步驟詳解,本文通圖文實例代碼相結(jié)合給大家介紹的非常詳細,對大家的學(xué)習或工作具有一定的參考借鑒價值,需要的朋友可以參考下
    2020-07-07
  • Java中ArrayList去除重復(fù)元素(包括字符串和自定義對象)

    Java中ArrayList去除重復(fù)元素(包括字符串和自定義對象)

    本文主要介紹了Java中ArrayList去除重復(fù)元素(包括字符串和自定義對象)的方法。具有很好的參考價值。下面跟著小編一起來看下吧
    2017-03-03
  • 使用SpringAOP實現(xiàn)公共字段填充功能

    使用SpringAOP實現(xiàn)公共字段填充功能

    在新增員工或者新增菜品分類時需要設(shè)置創(chuàng)建時間、創(chuàng)建人、修改時間、修改人等字段,在編輯員工或者編輯菜品分類時需要設(shè)置修改時間、修改人等字段,這些字段屬于公共字段,本文將給大家介紹使用SpringAOP實現(xiàn)公共字段填充功能,需要的朋友可以參考下
    2024-08-08

最新評論

佳木斯市| 贡嘎县| 克什克腾旗| 铜山县| 社会| 肇源县| 定兴县| 淳安县| 濉溪县| 皋兰县| 安新县| 巴南区| 泸水县| 疏附县| 凤山市| 潞西市| 瓦房店市| 双城市| 乌拉特后旗| 金山区| 塔城市| 本溪| 山东| 芷江| 昂仁县| 左贡县| 贺州市| 泸定县| 红安县| 北安市| 于田县| 新化县| 乌拉特后旗| 和田县| 全南县| 大宁县| 田林县| 定边县| 阜阳市| 皮山县| 凌海市|