今天,我就來講一下動態代理的設計模式。 動態代理的意義在於生成一個代理對象,來代理真實對象,從而控制真實對象的訪問。操作動態代理需要兩個步驟:一、代理對象和真實對象建立代理關係。二、實現代理對象的代理邏輯方法。 在Java中,有很多的動態代理技術。如:JDK、CGLIB、Javassist、ASM, ...
今天,我就來講一下動態代理的設計模式。
動態代理的意義在於生成一個代理對象,來代理真實對象,從而控制真實對象的訪問。操作動態代理需要兩個步驟:一、代理對象和真實對象建立代理關係。二、實現代理對象的代理邏輯方法。
在Java中,有很多的動態代理技術。如:JDK、CGLIB、Javassist、ASM,其中最常用的動態代理技術有兩種:一種是JDK動態代理,這是JDK自帶的功能;另一種就是CGLIB,這是第三方提供的一種技術。
這次主要講的是JDK動態代理和CGLIB動態代理。在JDK動態代理中,我們必須使用介面,而CGLIB就不需要。
JDK 動態代理
JDK 動態代理是 java.lang.reflect.* 包提供的方式,它必須藉助一個介面才能產生代理對象,所以我們先定義一個介面。代碼如下:
1 public interface HelloWorld { 2 3 public void sayHelloWorld(); 4 }
然後提供實現類來實現此介面。代碼如下:
public class HelloWorldImpl implements HelloWorld { @Override public void sayHelloWorld() { System.out.println("Hello World! 動態代理學習篇"); } }
這是最簡單的 Java 介面與實現類的關係。這時我們開始今天學習的內容,JDK動態代理。我們先要建立代理對象和真實服務對象的關係,然後實現代理邏輯。
在 JDK 動態代理中,要實現代理邏輯類必須去實現 java.lang.reflect.InvocationHandler 介面,它裡面定義了一個 invoke 方法,並且提供介面數組用於下掛代理對象。代碼如下:
public class JdkProxy implements InvocationHandler { //真實對象 private Object target = null; /** * 建立代理對象和真實對象的代理關係,並返回代理對象 * @param obj 真實對象 * @return 代理對象 */ public Object bind(Object target){ this.target = target; return Proxy.newProxyInstance(target.getClass().getClassLoader(), target.getClass().getInterfaces(), this); } /** * 代理方法邏輯 * @param proxy 代理對象 * @param method 當前調度方法 * @param args 當前方法的參數 * @return 代理結果返回 * @throws 異常 */ @Override public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { System.out.println("進入代理邏輯方法"); System.out.println("在調度真實對象之前的服務"); //相當於調用 sayHelloWorld 的方法 Object obj = method.invoke(target, args); System.out.println("在調度真實對象之後的服務"); return obj; } }
第1步,建立代理對象和真實對象的關係。這裡使用 bind 方法去完成,方法裡面首先用類的屬性 target 保存了真實對象,然後通過如下代碼建立並生成代理對象。
Proxy.newProxyInstance(target.getClass().getClassLoader(), target.getClass().getInterfaces(), this);
其中 newProxyInstance 方法包含三個參數。
第一個參數為:類載入器。
第二個參數為:把生成的動態代理對象下掛在哪些介面下。
第三個參數為:定義實現方法邏輯的代理類,this 表示當前對象,它必須實現 InvocationHandler 介面方法的 invoke 方法,它就是代理邏輯方法的現實方法。
第2步,實現代理邏輯方法。 invoke 方法可以實現代理邏輯, invoke 方法的三個參數的意義如下:
proxy:代理對象,就是 bind 方法生成的對象。
method:當前調度的方法。
args: 調度方法的參數。
測試一下JDK動態代理方法。代碼如下:
public class TestProxy { public static void main(String[] args) { JdkProxy jdkTest = new JdkProxy(); HelloWorld proxy = (HelloWorld)jdkTest.bind(new HelloWorldImpl()); proxy.sayHelloWorld(); } }
測試結果如下:
這就是 JDK 動態代理,它是一種常用的動態代理。