1. 程式人生 > >為什麼動態代理只能基於介面?

為什麼動態代理只能基於介面?

動態代理類(以下簡稱為代理類)是一個實現在建立類時在執行時指定的介面列表的類,該類具有下面描述的行為。 代理介面 是代理類實現的一個介面。 代理例項 是代理類的一個例項。 每個代理例項都有一個關聯的呼叫處理程式 物件,它可以實現介面 InvocationHandler。通過其中一個代理介面的代理例項上的方法呼叫將被指派到例項的呼叫處理程式的 Invoke 方法,並傳遞代理例項、識別呼叫方法的 java.lang.reflect.Method 物件以及包含引數的 Object 型別的陣列。呼叫處理程式以適當的方式處理編碼的方法呼叫,並且它返回的結果將作為代理例項上方法呼叫的結果返回。

代理類具用以下屬性:

代理類是公共的、最終的,而不是抽象的。
未指定代理類的非限定名稱。但是,以字串 "$Proxy" 開頭的類名空間應該為代理類保留。
代理類擴充套件 java.lang.reflect.Proxy。
代理類會按同一順序準確地實現其建立時指定的介面。
如果代理類實現了非公共介面,那麼它將在與該介面相同的包中定義。否則,代理類的包也是未指定的。注意,包密封將不阻止代理類在執行時在特定包中的成功定義,也不會阻止相同類載入器和帶有特定簽名的包所定義的類。
由於代理類將實現所有在其建立時指定的介面,所以對其 Class 物件呼叫 getInterfaces 將返回一個包含相同介面列表的陣列(按其建立時指定的順序),對其 Class 物件呼叫 getMethods 將返回一個包括這些介面中所有方法的 Method 物件的陣列,並且呼叫 getMethod 將會在代理介面中找到期望的一些方法。
如果 Proxy.isProxyClass 方法傳遞代理類(由 Proxy.getProxyClass 返回的類,或由 Proxy.newProxyInstance 返回的物件的類),則該方法返回 true,否則返回 false。
代理類的 java.security.ProtectionDomain 與由引導類載入器(如 java.lang.Object)載入的系統類相同,原因是代理類的程式碼由受信任的系統程式碼生成。此保護域通常被授予 java.security.AllPermission。
每個代理類都有一個可以帶一個引數(介面 InvocationHandler 的實現)的公共構造方法,用於設定代理例項的呼叫處理程式。並非必須使用反射 API 才能訪問公共構造方法,通過呼叫 Proxy.newInstance 方法(將呼叫 Proxy.getProxyClass 的操作和呼叫帶有呼叫處理程式的構造方法結合在一起)也可以建立代理例項。
代理例項具有以下屬性:

提供代理例項 proxy 和一個由其代理類 Foo 實現的介面,以下表達式將返回 true:
     proxy instanceof Foo
並且以下的強制轉換操作將會成功(而不丟擲 ClassCastException):
     (Foo) proxy
每個代理例項都有一個關聯的呼叫處理程式,它會被傳遞到其構造方法中。靜態 Proxy.getInvocationHandler 方法將返回與作為其引數傳遞的代理例項相關的呼叫處理程式。
代理例項上的介面方法呼叫將按照該方法的文件描述進行編碼,並被指派到呼叫處理程式的 Invoke 方法。
在代理例項上的 java.lang.Object 中宣告的 hashCode、equals 或 toString 方法的呼叫將按照與編碼和指派介面方法呼叫相同的方式進行編碼,並被指派到呼叫處理程式的 invoke 方法,如上所述。傳遞到 invoke 的 Method 物件的宣告類是 java.lang.Object。代理類不重寫從 java.lang.Object 繼承的代理例項的其他公共方法,所以這些方法的呼叫行為與其對 java.lang.Object 例項的操作一樣。
在多代理介面中重複的方法
當代理類的兩個或多個介面包含一個具有相同名稱和引數簽名的方法時,代理類的介面順序變得非常重要。在代理例項上呼叫重複方法 時,傳遞到呼叫處理程式的 Method 物件沒有必要成為其宣告類可以從介面(通過該介面呼叫代理方法)的引用型別指派的物件。此限制存在的原因是,生成的代理類中的相應方法實現無法確定它通過哪一個介面呼叫。因此,在代理例項上呼叫重複方法時,第一個介面中的方法的 Method 物件包含介面的代理類列表中的方法(直接或通過超級介面繼承),該物件會傳遞到呼叫處理程式的 invoke 方法,無論該方法呼叫通過哪一種引用型別發生。

如果代理介面包含某一方法,它的名稱和引數簽名與 java.lang.Object 的 hashCode、equals 或 toString 方法相同,那麼在代理例項上呼叫這樣的方法時,傳遞到呼叫處理程式的 Method 物件將使 java.lang.Object 成為其宣告類。換句話說,java.lang.Object 公共的非最終方法理論上在所有代理介面之前,以便確定哪一個 Method 物件傳遞到呼叫處理程式。

還要注意,當重複方法被指派到呼叫處理程式時,invoke 方法只可以丟擲經過檢查的異常型別,該異常型別可以使用所有 代理介面(可以通過它呼叫)中方法的 throws 子句指派一種異常型別。如果 invoke 方法丟擲一個經過檢查的異常,該異常沒有指派給任何由一個代理介面(可以通過它呼叫)中的方法宣告的異常型別,那麼該代理例項上的呼叫將丟擲一個未經檢查的 UndeclaredThrowableException。此限制表示並非所有的由傳遞到 invoke 方法的 Method 物件上呼叫 getExceptionTypes 返回的異常型別都可以由 invoke 方法成功丟擲。

相關推薦

為什麼動態代理只能基於介面?

動態代理類(以下簡稱為代理類)是一個實現在建立類時在執行時指定的介面列表的類,該類具有下面描述的行為。 代理介面 是代理類實現的一個介面。 代理例項 是代理類的一個例項。 每個代理例項都有一個關聯的呼叫處理程式 物件,它可以實現介面 InvocationHandler。通過其

Java 動態代理基於什麽原理(還沒整理完)

logs 判斷 java代碼 動態生成 voc https retrofit 哪些 AS 1> Java的反射機制在平時的業務開發過程中很少用到,但是在一些基礎框架的搭建上應用非常廣泛 2>什麽是Java反射機制 Java反射機制是在運行狀態中,對於任意一個類,

動態代理基於什麼原理?

反射機制是java語言提供的一種基礎功能,賦予程式在執行時自省的能力。通過反射我們可以直接操作類或者物件,比如獲取某個物件的類定義,獲取類宣告的屬性和方法,呼叫方法或者構造物件,甚至可以執行時修改類定義。 動態代理是一種方便執行時動態構建代理、動態處理代理方法呼叫的機制,很多場景都是利用類似機制

【Java核心技術】 動態代理基於什麼原理

代理模式(通過代理靜默地解決一些業務無關的問題,比如遠端、安全、事務、日誌、資源關閉……讓應用開發者可以只關心他的業務)     靜態代理:事先寫好代理類,可以手工編寫,也可以用工具生成。缺點是每個業務類都要對應一個代理類,非常不靈活。    &

Java 反射機制和動態代理基於什麼原理,瞭解過嗎?

工作多年以及在面試中,我經常能體會到,有些面試者確實是認真努力工作,但坦白說表現出的能力水平卻不足以通過面試,通常是兩方面原因: 1、“知其然不知其所以然”。 做了多年技術,開發了很多業務應用,但似乎並未思考過種種技術選擇背後的邏輯。坦白說,我並不放心把具有一定深度的任務交給他。 2、

Java動態代理(JDK介面代理和Cglib類代理

代理模式 代理模式是常用的java設計模式,它的特徵是代理類與委託類有同樣的介面,代理類主要負責為委託類預處理訊息、過濾訊息、把訊息轉發給委託類,以及事後處理訊息等。代理類與委託類之間通常會存在關聯關係,一個代理類的物件與一個委託類的物件關聯,代理類的物件本身並不真正實現服

java中動態代理實現基於feign的第三方服務的呼叫

一,Feign靜態工廠/** * <p> * 服務預設連線延遲為10s,讀取延遲為60s。如果有大的批量任務,或者特殊場景,請自行設定 {@link Request.Options} * <p> * 服務預設retry策略為失敗之後不重試。對於某些讀

基於介面和子類的兩種動態代理的解析及使用

基於介面: package com.itheima.proxy; import java.lang.reflect.InvocationHandler; import java.lang.reflect.Method; import java.lang.reflect.P

由service層介面有什麼用?引申到基於JDK原生和CGLIB動態代理實現spring事務管理的機制的思考

問題1:Services層為什麼要用(Services介面 類 + Services介面實現 類)分開,這樣做有什麼好處? 總結: 1.程式設計介面化, 2.Spring的事物管理預設用的是java動態代理。 問題2:Spring事物管理實現的機制

Spring之AOP的實現(JDK動態代理只能代理介面,不能代理類)

通過動態代理物件,我們可以在動態代理類中加自己想要加的邏輯,而不需要在真實物件的類中新增自己想要的邏輯,提高了程式碼的擴充套件性,降低了耦合性。 java的動態代理機制,缺點:只能代理介面不能代理類。 在學習Spring的時候,我們知道Spring主要有兩大思想,一個

最簡單的動態代理例項(spring基於介面代理的AOP原理)

JDK的動態代理是基於介面的 package com.open.aop; public interface BusinessInterface { public void processBusiness(); }目標物件package com.open.aop; public cl

基於動態代理的WebAPI/RPC/webSocket框架,一套介面定義,多個通訊方式

API/RPC/webSocket三個看起來好像沒啥相同的地方,在開發時,服務端,客戶端實現程式碼也大不一樣 最近整理了一下,通過動態代理的形式,整合了這些開發,都通過統一的介面約束,服務端實現和客戶端呼叫 基於這樣的形式,WebAPI/RPC/webSocket只需要定義一套介面,就能達到通用的效果 &nb

基於JDK的動態代理技術詳解

end course log 些許 private provide url 模仿 ade 雖然對於Spring的基本思想Aop是基於動態代理和CGlib這一點很早就有所認識,但是什麽是動態代理卻不甚清楚。為了對Spring加深理解,我覺得好好學習一下java

基於JDK實現的動態代理

  JDK動態代理是基於java.lang.reflect.*包提供的方式,他必須藉助一個接口才能產生代理物件,所以先定義介面: 實現類 ​​​​​ 此時可以開始實現動態代理了,首先建立起真實物件和代理物件的關係,然後實現代理邏輯。

通過Python利用ADSL伺服器和tinyproxy構建資料自己的動態代理IP池,用django+redis做web服務,提供IP介面

應公司業務需求需要在一些地方使用代理,要求連通率高,速度快,最主要的還要便宜,對比多家供應商後,最後還是決定自購撥號服務搭建代理IP池。 需要配置:1.一臺或多臺adsl伺服器(用以提供IP,可網上購買,通過ssh同域名連線)2.一臺正常固定IP伺服器擁來搭建IP代理池。(統一配置:python

Mybatis動態代理介面實現資料庫操作

  mybatis動態代理實現資料庫的增改刪查功能和pojo包裝類對映   工程結構搭建 在工程src包下建立兩個空包,cn.mybatis.xhchen.entity和cn.mybatis.xhchen.mapper 工程中建立建立檔案集conf

SpringBoot基於RateLimiter+AOP動態的為不同介面限流

1.首先介面限流演算法:       1.計數器方式(傳統計數器缺點:臨界問題 可能違背定義固定速率原則)      2.令牌桶方式           

基於JDK的動態代理

代理模式是GOF提出的23種設計模式中最為經典的模式之一,代理模式是物件的結構模式,它給某一個物件提供一個代理物件,並由代理物件控制對原物件的引用。簡單的說,代理物件可以完成比原物件更多的職責,當需要為原物件新增橫切關注功能時,就可以使用原物件的代理物件。 下面是一個簡單的入門

基於動態代理 Mock Dubbo 服務的實現方案

序言 背景概述 公司目前 Java 專案提供服務都是基於 Dubbo 框架的,而且 Dubbo 框架已經成為大部分國內網際網路公司選擇的一個基礎元件。 在日常專案協作過程中,其實會碰到服務不穩定、不滿足需求場景等情況,很多開發都會通過在本地使用 Mocktio 等單測工具作為自測輔助。那

轉:JDK動態代理為什麼必須用介面以及與CGLIB的對比

參考連結: JDK動態代理為什麼必須用介面以及與CGLIB的對比 文章中提到:試驗了JDK動態代理與CGLIB動態代理。從Spring的AOP框架介紹中得知對於使用介面的類,Spring使用JDK動態代理(原來做專案中試圖從Bean強制轉換為實現類,結果報錯,原來是這麼回事),沒有介面的就使用別的