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

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

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

服務器之家 - 編程語言 - Java教程 - java 代理模式及動態代理機制深入分析

java 代理模式及動態代理機制深入分析

2020-08-23 15:16Java之家 Java教程

這篇文章主要介紹了java 代理模式及動態代理機制深入分析的相關資料, 代理是一種常用的設計模式,其目的就是為其他對象提供一個代理以控制對某個對象的訪問,需要的朋友可以參考下

java 代理模式動態代理機制深入分析

代理設計模式

       代理是一種常用的設計模式,其目的就是為其他對象提供一個代理以控制對某個對象的訪問。代理類負責為委托類預處理消息,過濾消息并轉發消息,以及進行消息被委托類執行后的后續處理。
代理模式的作用是:為其他對象提供一種代理以控制對這個對象的訪問。在某些情況下,一個客戶不想或者不能直接引用另一個對象,而代理對象可以在客戶端和目標對象之間起到中介的作用。

代理模式一般涉及到的角色有:

抽象角色:聲明真實對象和代理對象的共同接口;
代理角色:代理對象角色內部含有對真實對象的引用,從而可以操作真實對象,同時代理對象提供與真實對象相同的接口以便

在任何時刻都能代替真實對象。同時,代理對象可以在執行真實對象操作時,附加其他的操作,相當于對真實對象進行封裝。
真實角色:代理角色所代表的真實對象,是我們最終要引用的對象

圖 1. 代理模式類圖

java 代理模式及動態代理機制深入分析

為了保持行為的一致性,代理類和委托類通常會實現相同的接口,所以在訪問者看來兩者沒有絲毫的區別。通過代理類這中間一層,能有效控制對委托 類對象的直接訪問,也可以很好地隱藏和保護委托類對象,同時也為實施不同控制策略預留了空間,從而在設計上獲得了更大的靈活性。Java 動態代理機制以巧妙的方式近乎完美地實踐了代理模式的設計理念。

java動態代理

相關的類和接口

要了解 Java 動態代理的機制,首先需要了解以下相關的類或接口:
· java.lang.reflect.Proxy:這是 Java 動態代理機制的主類,它提供了一組靜態方法來為一組接口動態地生成代理類及其對象。

清單 1. Proxy 的靜態方法

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
// 方法 1: 該方法用于獲取指定代理對象所關聯的調用處理器
 
static InvocationHandler getInvocationHandler(Object proxy) 
 
// 方法 2:該方法用于獲取關聯于指定類裝載器和一組接口的動態代理類的類對象
 
static Class getProxyClass(ClassLoader loader, Class[] interfaces) 
 
// 方法 3:該方法用于判斷指定類對象是否是一個動態代理類
 
static boolean isProxyClass(Class cl) 
 
// 方法 4:該方法用于為指定類裝載器、一組接口及調用處理器生成動態代理類實例
 
static Object newProxyInstance(ClassLoader loader, Class[] interfaces, 
 
  InvocationHandler h) 

java.lang.reflect.InvocationHandler:這是調用處理器接口,它自定義了一個 invoke 方法,用于集中處理在動態代理類對象上的方法調用,通常在該方法中實現對委托類的代理訪問。

清單 2. InvocationHandler 的核心方法

?
1
2
3
4
5
// 該方法負責集中處理動態代理類上的所有方法調用。第一個參數既是代理類實例,第二個參數是被調用的方法對象
 
// 第三個方法是調用參數。調用處理器根據這三個參數進行預處理或分派到委托類實例上發射執行
 
Object invoke(Object proxy, Method method, Object[] args)

每次生成動態代理類對象時都需要指定一個實現了該接口的調用處理器對象(參見 Proxy 靜態方法 4 的第三個參數)。
· java.lang.ClassLoader:這是類裝載器類,負責將類的字節碼裝載到 Java 虛擬機(JVM)中并為其定義類對象,然后該類才能被使用。Proxy 靜態方法生成動態代理類同樣需要通過類裝載器來進行裝載才能使用,它與普通類的唯一區別就是其字節碼是由 JVM 在運行時動態生成的而非預存在于任何個 .class 文件中。

每次生成動態代理類對象時都需要指定一個類裝載器對象(參見 Proxy 靜態方法 4 的第一個參數)

代理機制及其特點

首先讓我們來了解一下如何使用 Java 動態代理。具體有如下四步驟:

1. 通過實現 InvocationHandler 接口創建自己的調用處理器;
2. 通過為 Proxy 類指定 ClassLoader 對象和一組 interface 來創建動態代理類;
3. 通過反射機制獲得動態代理類的構造函數,其唯一參數類型是調用處理器接口類型;
4. 通過構造函數創建動態代理類實例,構造時調用處理器對象作為參數被傳入。

清單 3. 動態代理對象創建過程

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
// InvocationHandlerImpl 實現了 InvocationHandler 接口,并能實現方法調用從代理類到委托類的分派轉發
 
// 其內部通常包含指向委托類實例的引用,用于真正執行分派轉發過來的方法調用
 
InvocationHandler handler = new InvocationHandlerImpl(..); 
 
 
// 通過 Proxy 為包括 Interface 接口在內的一組接口動態創建代理類的類對象
 
Class clazz = Proxy.getProxyClass(classLoader, new Class[] { Interface.class, ... }); 
 
 
// 通過反射從生成的類對象獲得構造函數對象
 
Constructor constructor = clazz.getConstructor(new Class[] { InvocationHandler.class }); 
 
 
// 通過構造函數對象創建動態代理類實例
 
Interface Proxy = (Interface)constructor.newInstance(new Object[] { handler }); 

實際使用過程更加簡單,因為 Proxy 的靜態方法 newProxyInstance 已經為我們封裝了步驟 2 到步驟 4 的過程,所以簡化后的過程如

清單 4. 簡化的動態代理對象創建過程

?
1
2
3
4
5
6
7
8
9
10
11
// InvocationHandlerImpl 實現了 InvocationHandler 接口,并能實現方法調用從代理類到委托類的分派轉發
 
InvocationHandler handler = new InvocationHandlerImpl(..); 
 
// 通過 Proxy 直接創建動態代理類實例
 
Interface proxy = (Interface)Proxy.newProxyInstance( classLoader, 
 
 new Class[] { Interface.class }, 
 
 handler ); 

下面我們來看一個簡單實現動態代理的例子:

1.代理類和真實類接口:

?
1
2
3
4
5
6
7
public interface Subject
 
{
 
public void request();
 
}

2.真實類:

?
1
2
3
4
5
6
7
8
9
10
11
public class RealSubject implements Subject
 
{
 
public void request()
 
{
 
System.out.println("From real subject!");
 
}}

3.具體代理類:

?
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
35
import java.lang.reflect.InvocationHandler;
 
import java.lang.reflect.Method;
 
public class DynamicSubject implements InvocationHandler
 
{
 
private Object sub;
 
public DynamicSubject(Object obj)
 
{
 
this.sub = obj;
 
}
 
public Object invoke(Object proxy, Method method, Object[] args)
 
throws Throwable
 
{
 
System.out.println("before calling: " + method);
 
method.invoke(sub, args); 
 
System.out.println(args == null); 
 
System.out.println("after calling: " + method);
 
return null;
 
}

注:該代理類的內部屬性是Object類型,實際使用的時候通過該類的構造方法傳遞進來一個對象。 此外,該類還實現了invoke方法,該方法中的method.invoke其實就是調用被代理對象的將要 執行的方法,方法參數是sub,表示該方法從屬于sub,通過動態代理類,我們可以在執行真實對象的方法前后加入自己的一些額外方法。

4.客戶端調用示例:

?
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
import java.lang.reflect.InvocationHandler;
 
import java.lang.reflect.Proxy;
 
public class Client
 
{
 
public static void main(String[] args)
 
{
 
RealSubject realSubject = new RealSubject();
 
InvocationHandler handler = new DynamicSubject(realSubject);
 
Class<?> classType = handler.getClass();
 
// 下面的代碼一次性生成代理
 
Subject subject = (Subject) Proxy.newProxyInstance(classType
 
.getClassLoader(), realSubject.getClass().getInterfaces(),
 
handler);
 
subject.request();
 
System.out.println(subject.getClass());
 
}
 
}

接下來讓我們來了解一下 Java 動態代理機制 Proxy 的構造方法:

清單 6. Proxy 構造方法

?
1
2
3
4
5
6
7
8
// 由于 Proxy 內部從不直接調用構造函數,所以 private 類型意味著禁止任何調用
 
private Proxy() {} 
 
 
// 由于 Proxy 內部從不直接調用構造函數,所以 protected 意味著只有子類可以調用
 
protected Proxy(InvocationHandler h) {this.h = h;} 

接著,可以快速瀏覽一下 newProxyInstance 方法,因為其相當簡單:

清單 7. Proxy 靜態方法 newProxyInstance

?
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
35
36
37
38
39
40
41
public static Object newProxyInstance(ClassLoader loader, 
 
      Class<?>[] interfaces, 
 
      InvocationHandler h) 
 
      throws IllegalArgumentException { 
 
   
 
  // 檢查 h 不為空,否則拋異常
 
  if (h == null) { 
 
    throw new NullPointerException(); 
 
  
 
  // 獲得與制定類裝載器和一組接口相關的代理類類型對象
 
  Class cl = getProxyClass(loader, interfaces); 
 
 
  // 通過反射獲取構造函數對象并生成代理類實例
 
  try
 
    Constructor cons = cl.getConstructor(constructorParams); 
 
    return (Object) cons.newInstance(new Object[] { h }); 
 
  } catch (NoSuchMethodException e) { throw new InternalError(e.toString()); 
 
  } catch (IllegalAccessException e) { throw new InternalError(e.toString()); 
 
  } catch (InstantiationException e) { throw new InternalError(e.toString()); 
 
  } catch (InvocationTargetException e) { throw new InternalError(e.toString()); 
 
  
}

     由此可見,動態代理真正的關鍵是在 getProxyClass 方法,該方法負責為一組接口動態地生成代理類類型對象。

     有很多條理由,人們可以否定對 class 代理的必要性,但是同樣有一些理由,相信支持 class 動態代理會更美好。接口和類的劃分,本就不是很明顯,只是到了 Java 中才變得如此的細化。如果只從方法的聲明及是否被定義來考量,有一種兩者的混合體,它的名字叫抽象類。實現對抽象類的動態代理,相信也有其內在的價值。此 外,還有一些歷史遺留的類,它們將因為沒有實現任何接口而從此與動態代理永世無緣。如此種種,不得不說是一個小小的遺憾。
但是,不完美并不等于不偉大,偉大是一種本質,Java 動態代理就是佐例。

感謝閱讀,希望能幫助到大家,謝謝大家對本站的支持!

延伸 · 閱讀

精彩推薦
主站蜘蛛池模板: 扒开斗罗美女了的胸罩和内裤漫画 | 亚洲系列国产精品制服丝袜第 | 免费被靠视频动漫 | 欧美另类亚洲 | 农村老妇1乱69系列小说 | 草大逼 | 国产精品久久久久久久福利院 | 国产精品久久久久这里只有精品 | 国产91免费| 四虎院影永久在线观看 | 免费被靠视频动漫 | 500福利第一巨人导航 | 我们日本在线观看免费动漫下载 | 白丝尤物的下面被疯狂蹂躏 | 日本人与黑人做爰视频网站 | 国产午夜精品不卡视频 | 色综合色狠狠天天综合色 | 欧美影院一区二区 | 国产在视频线精品视频 | 亚洲狼人香蕉香蕉在线28 | 成人高清网站 | 日韩欧美在线一区二区三区 | 韩剧hd| free白嫩性hd| 四虎在线视频免费观看 | 国产一区国产二区国产三区 | 国色天香视频资源网 | 双性np肉文 | 精品无码一区二区三区中文字幕 | 调教女警花穿环上班 | 免费观看视频在线 | 国产亚洲自愉自愉 | 日韩高清一区二区三区不卡 | 美味情缘韩国在线观看视频 | 青青青在线免费 | 日本道三区播放区 | 欧美x×x| 黄德维| 色老头综合网 | 女人又色又爽又黄 | 国产亚洲精品福利在线 |