一区二区三区在线-一区二区三区亚洲视频-一区二区三区亚洲-一区二区三区午夜-一区二区三区四区在线视频-一区二区三区四区在线免费观看

服務器之家:專注于服務器技術及軟件下載分享
分類導航

PHP教程|ASP.NET教程|Java教程|ASP教程|編程技術|正則表達式|C/C++|IOS|C#|Swift|Android|VB|R語言|JavaScript|易語言|vb.net|

服務器之家 - 編程語言 - Java教程 - 深入理解java動態代理機制

深入理解java動態代理機制

2020-08-13 11:36簡丶樹 Java教程

本篇文章主要介紹了深入理解java動態代理機制,詳細的介紹動態代理有哪些應用場景,什么是動態代理,怎樣使用,它的局限性在什么地方?有興趣的可以了解一下。

retrofit是一個解耦性非常高的網絡請求框架,最近在研究的時候發現了動態代理這個非常強大且實用的技術,這篇文章將作為retrofit的前置知識,讓大家認識:動態代理有哪些應用場景,什么是動態代理,怎樣使用,它的局限性在什么地方?

動態代理的應用場景

1. AOP—面向切面編程,程序解耦

簡言之當你想要對一些類的內部的一些方法,在執行前和執行后做一些共同的的操作,而在方法中執行個性化操作的時候--用動態代理。在業務量龐大的時候能夠降低代碼量,增強可維護性。

2. 想要自定義第三放類庫中的某些方法

我引用了一個第三方類庫,但他的一些方法不滿足我的需求,我想自己重寫一下那幾個方法,或在方法前后加一些特殊的操作--用動態代理。但需要注意的是,這些方法有局限性,我會在稍后說明。

什么是動態代理

深入理解java動態代理機制

以上的圖太過于抽象,我們從生活中的例子開始切入。

假如你是一個大房東(被代理人),你有很多套房子想要出租,而你覺得找租客太麻煩,不愿意自己弄,因而你找一個人來代理你(代理人),幫打理這些東西,而這個人(代理人也就是中介)在幫你出租房屋的時候對你收取一些相應的中介費(對房屋出租的一些額外操作)。對于租客而言,中介就是房東,代理你做一些事情。

以上,就是一個代理的例子,而他為什么叫動態代理,“動態”兩個字體現在什么地方?

我們可以這樣想,如果你的每一套房子你都請一個代理人幫你打理,每當你想再出租一套房子的時候你得再請一個,這樣你會請很多的代理人,花費高額的中介成本,這可以看作常說的“靜態代理”。

但假如我們把所有的房子都交給一個中介來代理,讓他在多套房子之間動態的切換身份,幫你應付每一個租客。這就是一個“動態代理”的過程。動態代理的一大特點就是編譯階段沒有代理類在運行時才生成代理類。

我們用一段代碼來看一下

房屋出租的操作

?
1
2
3
4
5
6
7
/**
*定義一個借口
**/
public interface RentHouse {
void rent();//房屋出租
void charge(String str);//出租費用收取
}

房東

?
1
2
3
4
5
6
7
8
9
public class HouseOwner implements RentHouse {
public void rent() {
  System.out.println("I want to rent my house");
}
 
public void charge(String str) {
  System.out.println("You get : " + str + " RMB HouseCharge.");
}
}

中介

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
public class DynamicProxy implements InvocationHandler {
 
// 這個就是我們要代理的真實對象,即房東
private Object subject;
 
// 構造方法,給我們要代理的真實對象賦初值
public DynamicProxy(Object subject) {
  this.subject = subject;
}
 
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
  //  在代理真實對象前我們可以添加一些自己的操作,中介收取中介費
  System.out.println("before "+method.getName()+" house");
 
  System.out.println("Method:" + method.getName());
 
  //    如果方法是 charge 則中介收取100元中介費
  if (method.getName().equals("charge")) {
 
    method.invoke(subject, args);
    System.out.println("I will get 100 RMB ProxyCharge.");
 
  } else {
    //  當代理對象調用真實對象的方法時,其會自動的跳轉到代理對象關聯的handler對象的invoke方法來進行調用
    method.invoke(subject, args);
  }
 
  //  在代理真實對象后我們也可以添加一些自己的操作
  System.out.println("after "+method.getName()+" house");
 
  return null;
}
}

客人

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
public class Client {
public static void main(String[] args)
{
  //  我們要代理的真實對象--房東
  HouseOwner houseOwner = new HouseOwner();
 
  //  我們要代理哪個真實對象,就將該對象傳進去,最后是通過該真實對象來調用其方法的
  InvocationHandler handler = new DynamicProxy(houseOwner);
 
  /*
   * 通過Proxy的newProxyInstance方法來創建我們的代理對象,我們來看看其三個參數
   * 第一個參數 handler.getClass().getClassLoader() ,我們這里使用handler這個類的ClassLoader對象來加載我們的代理對象
   * 第二個參數realSubject.getClass().getInterfaces(),我們這里為代理對象提供的接口是真實對象所實行的接口,表示我要代理的是該真實對象,這樣我就能調用這組接口中的方法了
   * 第三個參數handler, 我們這里將這個代理對象關聯到了上方的 InvocationHandler 這個對象上
   */
  RentHouse rentHouse = (RentHouse) Proxy.newProxyInstance(handler.getClass().getClassLoader(), houseOwner
      .getClass().getInterfaces(), handler);//一個動態代理類,中介
 
  System.out.println(rentHouse.getClass().getName());
  rentHouse.rent();
  rentHouse.charge("10000");
}
}

我們來看一下輸出

?
1
2
3
4
5
6
7
8
9
10
11
12
com.sun.proxy.$Proxy0
before rent house
Method:rent
I want to rent my house
after rent house
before charge house
Method:charge
You get : 10000 RMB HouseCharge.
I will get 100 RMB ProxyCharge.
after charge house
 
Process finished with exit code 0

輸出里有 before rent house以及after rent house,說明我們可以在方法的前后增加操作。再看輸出 I will get 100 RMB ProxyCharge. 中介收取了100塊的中介費,說明我們不僅可以增加操作,甚至可以替換該方法或者直接讓該方法不執行。

剛開始看代碼你可能會有很多疑惑,我們通過以下的內容來看看動態代理應該怎么用。

動態代理該如何使用

在java的動態代理機制中,有兩個重要的類和接口,一個是 InvocationHandler(Interface)、另一個則是 Proxy(Class),這一個類和接口是實現我們動態代理所必須用到的。

每一個動態代理類都必須要實現InvocationHandler這個接口(代碼中的中介),并且每個代理類的實例都關聯到了一個handler,當我們通過代理對象調用一個方法的時候,這個方法的調用就會被轉發為由InvocationHandler這個接口的 invoke(對方法的增強就寫在這里面) 方法來進行調用。

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

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

?
1
2
3
4
Object invoke(Object proxy, Method method, Object[] args) throws Throwable
//proxy:  指代我們所代理的那個真實對象
//method:  指代的是我們所要調用真實對象的某個方法的Method對象
//args:  指代的是調用真實對象某個方法時接受的參數

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

 

復制代碼 代碼如下:

public static Object newProxyInstance(ClassLoader loader, Class<?>[] interfaces,  InvocationHandler h)  throws IllegalArgumentException

 

 

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

 

復制代碼 代碼如下:

public static Object newProxyInstance(ClassLoader loader, Class<?>[] interfaces,  InvocationHandler h)  throws IllegalArgumentException

 

 

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

?
1
2
3
4
5
public static Object newProxyInstance(ClassLoader loader, Class<?>[] interfaces, InvocationHandler h) throws IllegalArgumentException
 
//loader:一個ClassLoader對象,定義了由哪個ClassLoader對象來對生成的代理對象進行加載
//interfaces:一個Interface對象的數組,表示的是我將要給我需要代理的對象提供一組什么接口,如果我提供了一組接口給它,那么這個代理對象就宣稱實現了該接口(多態),這樣我就能調用這組接口中的方法了
//h:一個InvocationHandler對象,表示的是當我這個動態代理對象在調用方法的時候,會關聯到哪一個InvocationHandler對象上

這樣一來,結合上面給出的代碼,我們就可以明白動態代理的使用方法了

動態代理的局限性

從動態代理的使用方法中我們看到其實可以被增強的方法都是實現了借口的(不實現借口的public方法也可以通過繼承被代理類來使用),代碼中的HouseOwner繼承了RentHouse 。而對于private方法JDK的動態代理無能為力!
以上的動態代理是JDK的,對于java工程還有大名鼎鼎的CGLib,但遺憾的是CGLib并不能在android中使用,android虛擬機相對與jvm還是有區別的。

結束語

動態代理的使用場景遠不止這些,內部原理會在以后的文章中介紹,但應用類反射臨時生成代理類這一機制決定它對性能會有一定的影響。本文作為retrofit原理的前置文章并沒有太過詳盡,如有疏漏和錯誤,歡迎指正!

以上就是本文的全部內容,希望對大家的學習有所幫助,也希望大家多多支持服務器之家。

原文鏈接:http://www.jianshu.com/p/dbce090d5c3e#

延伸 · 閱讀

精彩推薦
主站蜘蛛池模板: 国产成人精品免费 | www.成人在线视频 | 操美女网址 | 无套啪啪 | 国产成人在线视频 | 男人和女人日 | 久久亚洲精品AV无码四区 | 婷婷久久综合九色综合九七 | yin娃sao货调教情趣用品店 | 亚洲天堂色视频 | 91国产高清 | 日本肉体xxxx69xxxx | 日韩在线免费看 | 亚洲区视频在线观看 | 国内小情侣一二三区在线视频 | 男gaygays免费网站多人 | 国产播放器一区 | 女人张开腿让男人桶视频免费大全 | 久久综合久综合久久鬼色 | 百合互慰吃奶互揉漫画 | 日韩精品一二三区 | 17岁韩国在线观看免费1 | 99成人国产精品视频 | 偷拍综合网 | 午夜精品久久久内射近拍高清 | 摔跤成人黄版 | 麻豆最新地址 | 日本在线看免费 | 国产精品视频一区二区三区不卡 | 午夜国产精品视频在线 | 贵妇的私人性俱乐部 | 亚洲国产成人久久综合一区 | 色综合久久九月婷婷色综合 | 2021年国内自拍 | 亚洲第一区欧美日韩精品 | 久久免费黄色 | 日韩二区三区 | 国产亚洲欧美日韩综合综合二区 | 精品亚洲456在线播放 | 亚洲天堂免费观看 | 亚欧洲乱码专区视频 |