文章中若附原文鏈接,那部分內容對你有所幫助,請給原作者先點贊!
文章中若附原文鏈接,那部分內容對你有所幫助,請給原作者先點贊!
文章中若附原文鏈接,那部分內容對你有所幫助,請給原作者先點贊!
JAVA動態代理
借鑒:
https://www.zhihu.com/question/20794107/answer/658139129?utm_source=wechat_session&utm_medium=social&utm_oi=911918804941021184&utm_content=sec
https://blog.csdn.net/yangaiyu/article/details/73827043
-
若自己實作代碼增強,則需要為每個目標物件單獨撰寫一個代理Class物件然后用類加載器加載,實體化,再呼叫,這樣每個目標物件都得單獨地撰寫代理Class物件以達到目的(即靜態代理),若是每一個目標物件都需要我們自己寫一個相應的代理類來實作增強,那作業量將十分驚人,因此我們需要找到其中的相似點,提取出來,對其進行增強,才能減少我們的負擔(為什么選用動態代理的原因),
-
為了減少代理類地撰寫,我們類的訊息一般都由Class物件在JVM方法區中被加載(反射和new都是),若想不撰寫代理class還要有目標類的資訊,自然而然地可以想到介面,若能對介面進行動態代理,則可將實作該介面并呼叫該介面中的方法(可能不止實作一個介面)的目標類歸為一類進行代碼撰寫(這就是為什么要使用動態代理的原因),但是,介面并不能實體化
-
但java.lang.reflect.Proxy類有個getProxyLoader(ClassLoader,interfaces)方法,只要你給他傳入類加載器和一組介面,它就能給你回傳代理Class(并且可以帶有構造器進行實體化)

- 有了代理Class(代理Class為代理類->資料結構,代理物件為實體化的物件),我們可以通過該物件得到有參的構造器(基于InvocationHandle介面),我們就可以反射創建實體了,而基于上述介面的構造器可以基于實體化的InvocationHandle介面的物件實體化,使得代理物件通過handler物件中的invoke方法去增強目標物件(InvocationHandle介面是一個規范,代理物件中會有成員變數去接收它,并為他的proxy、method、args等傳參,為了便于設計把他提取出來,將功能模塊化)

InvocationHandler handler = new DynamicProxy(realSubject);
Object invoke(Object proxy, Method method, Object[] args) throws Throwable
proxy: 指代我們所代理的那個真實物件
method: 指代的是我們所要呼叫真實物件的某個方法的Method物件
args: 指代的是呼叫真實物件某個方法時接受的引數
可能會以為回傳的這個代理物件會是Calculator型別的物件,或者是InvocationHandler的物件,結果卻不是,首先我們解釋一下為什么我們這里可以將其轉化為Subject型別的物件?原因就是在getPorxyClass這個方法的第二個引數上,我們給這個代理物件提供了一組什么介面,那么我這個代理物件就會實作了這組介面,這個時候我們當然可以將這個代理物件強制型別轉化為這組介面中的任意一個,因為這里的介面是Subject型別,所以就可以將其轉化為Subject型別了,
同時我們一定要記住,以上獲取代理Class、得到有參建構式、實體化后創建的代理物件是在jvm運行時動態生成的一個物件,它并不是我們的InvocationHandler型別,也不是我們定義的那組介面的型別,而是在運行是動態生成的一個物件,并且命名方式都是這樣的形式,以$開頭,proxy為中,最后一個數字表示物件的標號,
- 上面的并沒有傳入目標物件,需要在invoke里新建相應的物件,我們常用的是傳入相應的目標物件,而將上面的封裝為一個函式,以適用于更多的物件呼叫,而更常用的是Proxy.newProxyInstance()方法,直接將上述流程都封裝了,
* public static Object newProxyInstance(ClassLoader loader, Class<?>[] interfaces, InvocationHandler h) throws IllegalArgumentException
loader:一個ClassLoader物件,定義了由哪個ClassLoader物件來對生成的代理物件進行加載
interfaces:一個Interface物件的陣列,表示的是我將要給我需要代理的物件提供一組什么介面,如果我提供了一組介面給它,那么這個代理物件就宣稱實作了該介面(多型),這樣我就能呼叫這組介面中的方法了
h:一個InvocationHandler物件,表示的是當我這個動態代理物件在呼叫方法的時候,會關聯到哪一個InvocationHandler物件上



- 之后在invoke中呼叫method.invoke時,即為代理物件呼叫真實物件的方法時,其會自動的跳轉到代理物件關聯的handler物件的invoke方法來進行呼叫(反射實作),可以深入getPorxyClass與創造構造器的三個步驟或newProxyInstance中查看相關實作,
- 以上便是動態代理的全部流程了

轉載請註明出處,本文鏈接:https://www.uj5u.com/houduan/139918.html
標籤:Java
下一篇:IO流
