一 代理模式java
定義:在訪問目標對象的時候,提供一種間接訪問的方法,經過代理對象去訪問目標對象,達到客戶端的目的。api
好處:保護目標對象;在目標對象的行爲基礎上,代理對象能夠增長本身的處理,使得同一個目標對象能夠知足不一樣的客戶端的目的。app
代理模式的模型:ide
涉及三個角色:函數
RealSubject:目標對象,也是真正要作事情的人。ui
Proxy:代理對象,持有對目標對象的引用,暴露給客戶端,經過操做目標對象來完成客戶端的目的。而且,代理對象能夠在操做目標對象的先後作一些自定義的行爲,靈活擴展了目標對象。this
Subject:目標對象和代理對象的抽象,以便在任何使用目標對象的地方均可以使用代理對象。Subject能夠是一個接口也能夠是一個抽象類。spa
二 靜態代理代理
以最簡單的形式實現上述模型code
public interface Subject { void doRequst(); } public class RealSubject implements Subject { @Override public void doRequst() { System.out.println("it's the thing i really want to do"); } } public class Proxy implements Subject { private Subject subject; public Proxy(Subject subject){ this.subject = subject; } @Override public void doRequst() { System.out.println("before do the real thing"); subject.doRequst(); System.out.println("after do the real thing"); } } public class Client { public static void main(String[] args) { Proxy proxy = new Proxy(new RealSubject()); proxy.doRequst(); } } /** before do the real thing it's the thing i really want to do after do the real thing **/
這種實現方式即常說的靜態代理,有幾個方面的約束:
1 代理對象和目標對象須要實現共同的接口,接口有變更,目標對象和代理對象都須要維護。
2 想要代理其餘的目標對象,須要新增代理類。
三 動態代理
先看java實現動態代理的幾個主要角色
1 Proxy :java.lang.reflect.Proxy,jdk api提供的代理類的主類,該類提供方法動態生成代理類,生成的時候須要指定一組接口(即代理類和目標對象要實現哪些接口)
public static Object newProxyInstance(ClassLoader var0, Class<?>[] var1, final InvocationHandler var2) throws IllegalArgumentException /** 提供了這個靜態方法用於動態生成代理類 var0: 目標對象的類加載器 var1: 代理類要實現哪些接口,即目標對象實現的接口 var2: 處理器,代理類具體要作什麼寫在處理器中 **/
2 InvocationHandler :java.lang.reflect.InvocationHandler
/** @param proxy the proxy instance that the method was invoked on 代理對象,執行invoke的時候實際上是在替這個proxy執行 @param method the {@code Method} instance corresponding to the interface method invoked on the proxy instance. The declaring class of the {@code Method} object will be the interface that the method was declared in, which may be a superinterface of the proxy interface that the proxy class inherits the method through. 目標對象要執行的方法 @param args an array of objects containing the values of the arguments passed in the method invocation on the proxy instance, or {@code null} if interface method takes no arguments. Arguments of primitive types are wrapped in instances of the appropriate primitive wrapper class, such as {@code java.lang.Integer} or {@code java.lang.Boolean}. 執行方法須要的參數 **/ public Object invoke(Object proxy, Method method, Object[] args) throws Throwable
java動態代理實例
public interface Subject { void doRequest(); } public class RealSubject1 implements Subject { @Override public void doRequest() { System.out.println("RealSubject1 want to sing"); } } public class RealSubject2 implements Subject { @Override public void doRequest() { System.out.println("RealSubject2 want to dance"); } } public class RealInvocationHandler implements InvocationHandler { private Object subject; public RealInvocationHandler(Object subject){ this.subject = subject; } @Override public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { System.out.println("before process"); Object result = method.invoke(subject,args); System.out.println("after process"); return result; } } public class Client { public static void main(String[] args) { Subject realSubject1 = new RealSubject1(); InvocationHandler handler1 = new RealInvocationHandler(realSubject1); Subject subject1 = (Subject) Proxy.newProxyInstance(realSubject1.getClass().getClassLoader(),realSubject1.getClass().getInterfaces(),handler1); subject1.doRequest(); System.out.println("-----------------------"); Subject realSubject2 = new RealSubject2(); InvocationHandler handler2 = new RealInvocationHandler(realSubject2); Subject subject2 = (Subject)Proxy.newProxyInstance(realSubject2.getClass().getClassLoader(),realSubject2.getClass().getInterfaces(),handler2); subject2.doRequest(); } } /** before process RealSubject1 want to sing after process ----------------------- before process RealSubject2 want to dance after process **/
與靜態代理作個比較:
不須要挨個寫代理類,想代理其餘的,動態new一個代理類
相關源碼解析
Proxy.newProxyInstance生成的代理具有什麼以及爲何能夠轉換成目標對象
protected InvocationHandler h; public static Object newProxyInstance(ClassLoader loader, Class<?>[] interfaces, InvocationHandler h) throws IllegalArgumentException { // 校驗handler if (h == null) { throw new NullPointerException(); } final Class<?>[] intfs = interfaces.clone(); final SecurityManager sm = System.getSecurityManager(); if (sm != null) { checkProxyAccess(Reflection.getCallerClass(), loader, intfs); } /* * Proxy維護了一個proxyClassCache,若是想要的代理類已經有實現了指定接口的loader定義好了,直接返回cache的備份 * 不然,經過ProxyClassFactory 生成一個代理類,實現指定的intfs */ Class<?> cl = getProxyClass0(loader, intfs); /* * Invoke its constructor with the designated invocation handler. */ try { //獲取構造函數,將傳進來的h賦給proxy內部持有的Invokerhanler對象 final Constructor<?> cons = cl.getConstructor(constructorParams); final InvocationHandler ih = h; if (sm != null && ProxyAccessHelper.needsNewInstanceCheck(cl)) { // create proxy instance with doPrivilege as the proxy class may // implement non-public interfaces that requires a special permission return AccessController.doPrivileged(new PrivilegedAction<Object>() { public Object run() { return newInstance(cons, ih); } }); } else { return newInstance(cons, ih); } } catch (NoSuchMethodException e) { throw new InternalError(e.toString()); } }
因此,Proxy生成的代理對象具有一個invokehandler對象的引用;而且實現了目標對象實現的接口,由於能夠轉換爲目標對象的抽象
InvokeHandler爲何能夠完成目標對象方法的執行
如上述例子中目標對象RealSubject1要執行doRequest方法,Proxy生成的代理類也會實現這個方法,大概以下:
public final void doRequest() { //這個會調用invokehandler的invoke方法,這裏的h便是父類Proxy的h,經過newProxyInstance傳進來的 try { this.h.invoke(this, m3, null); return; } catch (RuntimeException localRuntimeException) { throw localRuntimeException; } catch (Throwable localThrowable) { throw new UndeclaredThrowableException(localThrowable); } }
有了InvocationHandler 可使Proxy從具體的代碼邏輯抽離出來,更方便統一的生成代理類。
後續todo:
Proxy生成的代理對象的具體剖析
method.invoke具體作了什麼