Java動態代理--Proxy.newProxyInstance
阿新 • • 發佈:2018-11-11
一、代理模式
主要用來做方法的增強,讓你可以在不修改原始碼的情況下,增強一些方法,在方法執行前後做任何你想做的事情(甚至根本不去執行這個方法),因為在InvocationHandler的invoke方法中,你可以直接獲取正在呼叫方法對應的Method物件,具體應用的話,比如可以新增呼叫日誌,做事務控制等。動態代理是設計模式當中代理模式的一種。
package proxy; public interface Subject { /** * 想在hello這個方法前後執行 相應的列印邏輯 * @param str */ public void hello(String str); } package proxy; public class RealSubject implements Subject { @Override public void hello(String str) { System.out.println("hello: " + str); } }
package proxy; import java.lang.reflect.InvocationHandler; import java.lang.reflect.Method; public class DynamicProxy implements InvocationHandler { //這個就是我們要代理的真實物件 private Object subject; //構造方法,給我們要代理的真實物件賦初值 public DynamicProxy(Object subject) { this.subject = subject; } /** * * @param object 指代我們所代理的那個真實物件 * @param method 指代的是我們所要呼叫真實物件的某個方法的Method物件 * @param args 指代的是呼叫真實物件某個方法時接受的引數 * @return * @throws Throwable */ @Override public Object invoke(Object object, Method method, Object[] args) throws Throwable { // 在代理真實物件前我們可以新增一些自己的操作 System.out.println("before hello==============="); System.out.println("Method:" + method); //當代理物件呼叫真實物件的方法(subject.rent();和subject.hello("world");)時,實際上執行的都是該invoke方法裡面的程式碼 //public Object invoke(Object object, Method method, Object[] args) throws Throwable method.invoke(subject, args); // 在代理真實物件後我們也可以新增一些自己的操作 System.out.println("after hello==============="); return null; } }
package proxy; import java.lang.reflect.InvocationHandler; import java.lang.reflect.Proxy; public class Client { public static void main(String[] args) { // 我們要代理的真實物件 Subject realSubject = new RealSubject(); // 我們要代理哪個真實物件,就將該物件傳進去,最後是通過該真實物件來呼叫其方法的 InvocationHandler handler = new DynamicProxy(realSubject); /* * 通過Proxy的newProxyInstance方法來建立我們的代理物件,我們來看看其三個引數 * 第一個引數 handler.getClass().getClassLoader() ,我們這裡使用handler這個類的ClassLoader物件來載入我們的代理物件 * 一個ClassLoader物件,定義了由哪個ClassLoader物件來對生成的代理物件進行載入 * * 第二個引數realSubject.getClass().getInterfaces(),我們這裡為代理物件提供的介面是真實物件所實行的介面, * 表示我要代理的是該真實物件,這樣我就能呼叫這組介面中的方法了 * 一個Interface物件的陣列,表示的是我將要給我需要代理的物件提供一組什麼介面,如果我提供了一組介面給它, * 那麼這個代理物件就宣稱實現了該介面(多型),這樣我就能呼叫這組介面中的方法了 * * 第三個引數handler, 我們這裡將這個代理物件關聯到了上方的 InvocationHandler 這個物件上 * 一個InvocationHandler物件,表示的是當我這個動態代理物件在呼叫方法的時候,會關聯到哪一個InvocationHandler物件上 */ Subject subject = ( Subject) Proxy.newProxyInstance(handler.getClass().getClassLoader(), realSubject.getClass().getInterfaces(), handler); System.out.println(subject.getClass().getName()); subject.hello("world"); } }
列印結果:
com.sun.proxy.$Proxy0
before hello===============
Method:public abstract void proxy.Subject.hello(java.lang.String)
hello: world
after hello===============
Process finished with exit code 0