自拍偷在线精品自拍偷,亚洲欧美中文日韩v在线观看不卡

這一次徹底搞懂JDK動(dòng)態(tài)代理

開發(fā) 前端
靜態(tài)代理這個(gè)模式本身有個(gè)大問題,若類方法數(shù)量越來越多的時(shí)候,代理類的代碼量十分龐大的。所以引入動(dòng)態(tài)代理.

[[409031]]

動(dòng)態(tài)代理 V.S 靜態(tài)代理

Proxy類的代碼被固定下來,不會(huì)因?yàn)闃I(yè)務(wù)的逐漸龐大而龐大

可以實(shí)現(xiàn)AOP編程,這是靜態(tài)代理無法實(shí)現(xiàn)的

解耦,如果用在web業(yè)務(wù)下,可以實(shí)現(xiàn)數(shù)據(jù)層和業(yè)務(wù)層的分離

動(dòng)態(tài)代理的優(yōu)勢(shì)就是實(shí)現(xiàn)無侵入式的代碼擴(kuò)展。

靜態(tài)代理這個(gè)模式本身有個(gè)大問題,若類方法數(shù)量越來越多的時(shí)候,代理類的代碼量十分龐大的。所以引入動(dòng)態(tài)代理

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

Java中動(dòng)態(tài)代理的實(shí)現(xiàn)的關(guān)鍵:

  • Proxy
  • InvocationHandler

InvocationHandler#invoke

  • method 調(diào)用的方法,即需要執(zhí)行的方法
  • args 方法的參數(shù)
  • proxy 代理類的實(shí)例 圖片

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

JDK動(dòng)態(tài)代理模式里有個(gè)攔截器,在JDK中,只要實(shí)現(xiàn)了InvocationHandler接口的類就是一個(gè)攔截器類。攔截器的作用:控制目標(biāo)對(duì)象的目標(biāo)方法的執(zhí)行。

攔截器的具體操作步驟:

1.引入類

目標(biāo)類和一些擴(kuò)展方法相關(guān)的類

2.賦值

調(diào)用構(gòu)造器,給相關(guān)對(duì)象賦值

3.合并邏輯處理

在invoke方法中把所有的邏輯結(jié)合在一起。最終決定目標(biāo)方法是否被調(diào)用

示例

思考如下問題:

代理對(duì)象由誰產(chǎn)生

JVM,不像靜態(tài)代理,我們得自己new個(gè)代理對(duì)象。

代理對(duì)象實(shí)現(xiàn)了什么接口

實(shí)現(xiàn)的接口是目標(biāo)對(duì)象實(shí)現(xiàn)的接口。同靜態(tài)代理中代理對(duì)象實(shí)現(xiàn)的接口。那個(gè)繼承關(guān)系圖還是相同的。代理對(duì)象和目標(biāo)對(duì)象都實(shí)現(xiàn)一個(gè)共同的接口。就是這個(gè)接口。所以Proxy.newProxyInstance()方法返回的類型就是這個(gè)接口類型。

代理對(duì)象的方法體是什么

代理對(duì)象的方法體中的內(nèi)容就是攔截器中invoke方法中的內(nèi)容。

所有代理對(duì)象的處理邏輯,控制是否執(zhí)行目標(biāo)對(duì)象的目標(biāo)方法。都是在這個(gè)方法里面處理的。

攔截器中的invoke方法中的method參數(shù)是在什么時(shí)候賦值的

在客戶端,代理對(duì)象調(diào)用目標(biāo)方法的時(shí)候,此實(shí)例中為:

  1. proxyObj.business(); 

實(shí)際上進(jìn)入的是攔截器中的invoke方法,這時(shí)攔截器中的invoke方法中的method參數(shù)會(huì)被賦值。

為啥這叫JDK動(dòng)態(tài)代理

因?yàn)樵搫?dòng)態(tài)代理對(duì)象是用JDK相關(guān)代碼生成。

很多同學(xué)對(duì)動(dòng)態(tài)代理一直很迷糊,在于理解錯(cuò)了

  1. proxyObj.business(); 
  2. $Proxy0 

沒有發(fā)現(xiàn)這個(gè) proxyObj 和 Proxy 類之間的聯(lián)系,一直好奇

最后調(diào)用的business()是怎么和 invoke() 聯(lián)系上的?

invoke又怎么知道business的存在?

因?yàn)榇蠖嗤瑢W(xué)不知道 $Proxy0 類,看看下面的 $Proxy0 源碼,相信你完全可以理解動(dòng)態(tài)代理了。

我們雖然沒有顯式調(diào)用invoke,但該方法確實(shí)被執(zhí)行了。

可以從newProxyInstance方法作為突破口,我們先來看一下Proxy類中newProxyInstance方法的源代碼:

  1. public static Object newProxyInstance(ClassLoader loader, 
  2.                                       Class<?>[] interfaces, 
  3.                                       InvocationHandler h) { 
  4.     final Class<?>[] intfs = interfaces.clone(); 
  5.     final SecurityManager sm = System.getSecurityManager(); 
  6.     if (sm != null) { 
  7.         checkProxyAccess(Reflection.getCallerClass(), loader, intfs); 
  8.     } 
  9.  
  10.     /* 
  11.      * 查找或生成指定的代理類 
  12.      * 創(chuàng)建代理類$Proxy0 
  13.      * $Proxy0類實(shí)現(xiàn)了interfaces的接口,并繼承了Proxy類 
  14.      */ 
  15.     Class<?> cl = getProxyClass0(loader, intfs); 
  16.  
  17.     /* 
  18.      * 使用指定的調(diào)用處理程序調(diào)用其構(gòu)造器 
  19.      */ 
  20.     try { 
  21.         if (sm != null) { 
  22.             checkNewProxyPermission(Reflection.getCallerClass(), cl); 
  23.         } 
  24.         // 形參為InvocationHandler類型的構(gòu)造器 
  25.         final Constructor<?> cons = cl.getConstructor(constructorParams); 
  26.         final InvocationHandler ih = h; 
  27.         if (!Modifier.isPublic(cl.getModifiers())) { 
  28.             AccessController.doPrivileged(new PrivilegedAction<Void>() { 
  29.                 public Void run() { 
  30.                     cons.setAccessible(true); 
  31.                     return null
  32.                 } 
  33.             }); 
  34.         } 
  35.         return cons.newInstance(new Object[]{h}); 
  36.     } ... 

Proxy.newProxyInstance 做了什么呢?

  • 根據(jù)參數(shù)loader和interfaces調(diào)用方法 getProxyClass(loader, interfaces)創(chuàng)建代理$Proxy0類。$Proxy0類 實(shí)現(xiàn)了interfaces的接口,并繼承了Proxy類
  • 實(shí)例化$Proxy0,并在構(gòu)造器把DynamicSubject傳過去,接著$Proxy00調(diào)用父類Proxy的構(gòu)造器,為h賦值

$Proxy0的源碼:

  1. package com.sun.proxy; 
  2.  
  3. public final class $Proxy0 extends Proxy implements TargetInterface { 
  4.     private static Method m1; 
  5.     private static Method m3; 
  6.     private static Method m2; 
  7.     private static Method m0; 
  8.  
  9.     public $Proxy0(InvocationHandler var1) throws  { 
  10.         super(var1); 
  11.     } 
  12.  
  13.     public final boolean equals(Object var1) throws  { 
  14.         try { 
  15.             return (Boolean)super.h.invoke(this, m1, new Object[]{var1}); 
  16.         }... 
  17.     } 
  18.  
  19.     public final void business() throws  { 
  20.         try { 
  21.             super.h.invoke(this, m3, (Object[])null); 
  22.         }... 
  23.     } 
  24.  
  25.     public final String toString() throws  { 
  26.         try { 
  27.             return (String)super.h.invoke(this, m2, (Object[])null); 
  28.         }... 
  29.     } 
  30.  
  31.     public final int hashCode() throws  { 
  32.         try { 
  33.             return (Integer)super.h.invoke(this, m0, (Object[])null); 
  34.         }... 
  35.     } 
  36.  
  37.     static { 
  38.         try { 
  39.             m1 = Class.forName("java.lang.Object").getMethod("equals", Class.forName("java.lang.Object")); 
  40.             m3 = Class.forName("com.javaedge.design.pattern.structural.proxy.dynamicproxy.jdkdynamicproxy.TargetInterface").getMethod("business"); 
  41.             m2 = Class.forName("java.lang.Object").getMethod("toString"); 
  42.             m0 = Class.forName("java.lang.Object").getMethod("hashCode"); 
  43.         }... 
  44.     } 

接著把得到的$Proxy0實(shí)例強(qiáng)轉(zhuǎn)成TargetInterface,并將引用賦給TargetInterface。當(dāng)執(zhí)行proxyObj.business(),就調(diào)用了$Proxy0類中的business()方法,進(jìn)而調(diào)用父類Proxy中的h的invoke()方法。即InvocationHandler.invoke()。

最后提醒Proxy#getProxyClass返回的是Proxy的Class類,而非很同學(xué)想當(dāng)然認(rèn)為的“被代理類的Class類”! 

本文轉(zhuǎn)載自微信公眾號(hào)「JavaEdge」,可以通過以下二維碼關(guān)注。轉(zhuǎn)載本文請(qǐng)聯(lián)系JavaEdge公眾號(hào)。

 

責(zé)任編輯:武曉燕 來源: JavaEdge
相關(guān)推薦

2021-08-29 08:14:30

GPU CSS gpu

2024-05-15 10:14:00

CRDT數(shù)據(jù)類型協(xié)同編輯

2019-11-08 16:05:54

Promise前端鏈?zhǔn)秸{(diào)用

2024-03-11 08:47:30

CRDT數(shù)據(jù)類型協(xié)同編輯

2019-09-12 09:40:34

秒殺系統(tǒng)高并發(fā)

2018-08-07 14:45:52

編程語言JavaScripthtml

2021-03-11 12:15:37

Kubernetes云原生容器

2021-04-28 09:55:52

JavaLock接口并發(fā)編程

2020-08-13 07:04:45

跨域CORS瀏覽器

2019-06-05 13:00:00

2016-03-31 17:01:26

桂林甲天下

2018-07-23 16:13:27

Google歐盟Android

2024-05-20 00:00:00

代碼主線程

2024-10-09 12:05:27

2025-04-09 10:36:32

2019-04-12 11:25:24

華為

2016-11-08 07:58:02

樂視難關(guān)科技新聞早報(bào)

2014-07-18 17:14:16

小米蘋果雷軍

2016-01-06 11:15:03

VR

2019-11-05 11:17:11

Java虛擬機(jī)技術(shù)Java 堆
點(diǎn)贊
收藏

51CTO技術(shù)棧公眾號(hào)