相比於靜態代理,動態代理避免了開發者編寫各個繁鎖的靜態代理類,只需指定一組接口及目標類對象就能動態地獲取代理對象。
使用動態代理的六大步驟:
1 通過實現InvocationHandler接口來自定義自己的InvocationHandler。
2 通過Proxy類的getProxyClass方法獲取代理類。
3 通過反射機制獲取代理類的構造方法,方法簽名為getConstructor(InvocationHandler.class)。
4 將目標對象作為參數傳入,通過構造方法獲取自定義的InvocationHandler實例對象。
5 將自定義的InvocationHandler實例對象作為參數傳入,通過構造方法獲取代理對象。
6 代理對象調用目標方法。
JDK Proxy HelloWorld
1 package com.yao.proxy; 2 3 public interface Helloworld { 4 void sayHello(); 5 }
1 package com.yao.proxy; 2 3 import com.yao.HelloWorld; 4 5 public class HelloworldImpl implements HelloWorld { 6 public void sayHello() { 7 System.out.print("hello world"); 8 } 9 }
1 package com.yao.proxy; 2 3 import java.lang.reflect.InvocationHandler; 4 import java.lang.reflect.Method; 5 6 public class MyInvocationHandler implements InvocationHandler{ 7 private Object target; 8 public MyInvocationHandler(Object target) { 9 this.target=target; 10 } 11 public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { 12 System.out.println("method :"+ method.getName()+" is invoked!"); 13 return method.invoke(target,args); // 執行相應的目標方法 14 } 15 }
target屬性表示代理的目標對象。InvocationHandler是連接代理對象與目標對象的自定義中間類MyInvocationHandler必須實現的接口,只有一個方法public Object invoke(Object proxy, Method method, Object[] args)。在這個方法中,Proxy通過newProxyInstance方法創建代理對象,method表示目標對象被調用的方法,args表示目標對象被調用方法的形參列表。
1 package com.yao.proxy; 2 3 import com.yao.HelloWorld; 4 import java.lang.reflect.Constructor; 5 import java.lang.reflect.InvocationHandler; 6 import java.lang.reflect.InvocationTargetException; 7 import java.lang.reflect.Proxy; 8 9 public class JDKProxyTest { 10 public static void main(String[]args) throws NoSuchMethodException, IllegalAccessException, InvocationTargetException, InstantiationException { 11 // 這里有兩種寫法,采用復雜的一種寫法,有助於理解。 12 Class<?> proxyClass= Proxy.getProxyClass(JDKProxyTest.class.getClassLoader(),HelloWorld.class); 13 final Constructor<?> cons = proxyClass.getConstructor(InvocationHandler.class); 14 final InvocationHandler ih = new MyInvocationHandler(new HelloworldImpl()); 15 HelloWorld helloWorld = (HelloWorld)cons.newInstance(ih); 16 helloWorld.sayHello(); 17 18 // 下面是簡單的一種寫法,本質上和上面是一樣的 19 /* 20 HelloWorld helloWorld=(HelloWorld)Proxy. 21 newProxyInstance(JDKProxyTest.class.getClassLoader(), 22 new Class<?>[]{HelloWorld.class}, 23 new MyInvocationHandler(new HelloworldImpl())); 24 helloWorld.sayHello(); 25 */ 26 } 27 28 }
參考資料