Nintendo Switch 《CRYSTAR -慟哭之星-》繁體中文版今天上市!
一、什麼是代理?
代理是一種常用的設計模式,其目的就是為其他物件提供一個代理以控制對某個物件的訪問。代理類負責為委託類預處理訊息,過濾訊息並轉發訊息,以及進行訊息被委託類執行後的後續處理。
代理模式UML圖:
簡單結構示意圖:
為了保持行為的一致性,代理類和委託類通常會實現相同的介面,所以在訪問者看來兩者沒有絲毫的區別。通過代理類這中間一層,能有效控制對委託類物件的直接訪問,也可以很好地隱藏和保護委託類物件,同時也為實施不同控制策略預留了空間,從而在設計上獲得了更大的靈活性。Java 動態代理機制以巧妙的方式近乎完美地實踐了代理模式的設計理念。
二、Java動態代理類
Java動態代理類位於java.lang.reflect包下,一般主要涉及到以下兩個類:
(1)介面 InvocationHandler:該介面中僅定義了一個方法
public object invoke(Object obj,Method method, Object[] args)
在實際使用時,第一個引數obj一般是指代理類,method是被代理的方法,如上例中的request(),args為該方法的引數陣列。這個抽象方法在代理類中動態實現。
(2)Proxy:該類即為動態代理類,其中主要包含以下內容:
protected Proxy(InvocationHandler h):建構函式,用於給內部的h賦值。
static Class getProxyClass (ClassLoaderloader, Class[] interfaces):獲得一個代理類,其中loader是類裝載器,interfaces是真實類所擁有的全部介面的陣列。
static Object newProxyInstance(ClassLoaderloader, Class[] interfaces, InvocationHandler h):返回代理類的一個例項,返回後的代理類可以當作被代理類使用(可使用被代理類的在Subject介面中宣告過的方法)
所謂DynamicProxy是這樣一種class:它是在執行時生成的class,在生成它時你必須提供一組interface給它,然後該class就宣稱它實現了這些 interface。你當然可以把該class的例項當作這些interface中的任何一個來用。當然,這個DynamicProxy其實就是一個Proxy,它不會替你作實質性的工作,在生成它的例項時你必須提供一個handler,由它接管實際的工作。
在使用動態代理類時,我們必須實現InvocationHandler介面
通過這種方式,被代理的物件(SubjectImpl)可以在執行時動態改變,需要控制的介面(Subject介面)可以在執行時改變,控制的方式(DynamicSubject類)也可以動態改變,從而實現了非常靈活的動態代理關係。
動態代理步驟:
- 1.建立一個實現介面InvocationHandler的類,它必須實現invoke方法
- 2.建立被代理的類以及介面
- 3.通過Proxy的靜態方法newProxyInstance(ClassLoaderloader, Class[] interfaces, InvocationHandler h)建立一個代理
- 4.通過代理呼叫方法
三、JDK的動態代理具體使用
1、需要動態代理的介面:
/** * @Author lyh * @Date 2022/3/3 * 需要動態代理的介面 */ public interface Subject { /** * 說話 * @param str * @return */ String say(String str); }
2、需要代理的實際物件
/** * @Author lyh * @Date 2022/3/3 * 需要代理的實際物件 */ public class SubjectImpl implements Subject { @Override public String say(String str) { return str; } }
3、編寫處理器實現類
/** * @Author lyh * @Date 2022/3/3 * 處理器實現類 */ public class InvocationHandlerImpl implements InvocationHandler { /** * 這個就是我們要代理的真實物件 */ private Object subject; /** * 構造方法,給我們要代理的真實物件賦初值 * * @param subject */ public InvocationHandlerImpl(Object subject) { this.subject = subject; } /** * 該方法負責集中處理動態代理類上的所有方法呼叫。 * 呼叫處理器根據這三個引數進行預處理或分派到委託類例項上反射執行 * * @param proxy 代理類例項 * @param method 被呼叫的方法物件 * @param args 呼叫引數 * @return * @throws Throwable */ @Override public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { System.out.println("呼叫方法前的處理"); System.out.println("method"+method); //呼叫真實物件的方法 Object returnValue = method.invoke(subject, args); System.out.println("呼叫方法結束後的處理"); return returnValue; } }
4、測試
public class Test { public static void main(String[] args) { // 真實物件(被代理物件) Subject realSubject = new SubjectImpl(); // invocation InvocationHandlerImpl invocationHandler = new InvocationHandlerImpl(realSubject); ClassLoader classLoader = realSubject.getClass().getClassLoader(); Class<?>[] interfaces = realSubject.getClass().getInterfaces(); //呼叫Proxy的newProxyInstance 指定類裝載器、一組介面及呼叫處理器生成動態代理類例項 Subject subject = (Subject)Proxy.newProxyInstance(classLoader, interfaces, invocationHandler); System.out.println("代理物件型別"+subject.getClass().getName()); //通過代理物件呼叫方法 String say = subject.say("你好呀!"); System.out.println(say); } }
5、輸出結果
摘自:https://blog.csdn.net/jiankunking/article/details/52143504