代理模式:代理是一種經常使用的設計模式,其目的就是爲其餘對象提供一個代理以控制對某個對象的訪問。代理類負責爲委託類預處理消息,過濾消息並轉發消息,以及進行消息被委託類執行後的後續處理。不少能夠框架中都有用到,好比: spring的AOP的實現主要就是動態代理, mybatis的Mapper代理等。java
以下來看下代理模式的UML圖(來自百度圖片):spring
代理類和被代理類實現共同的接口, 其中代理類中包含一個被代理類的實例引用。代理模式能夠分爲靜態代理和動態代理,這裏主要學習下動態代理。動態代理做用能夠實現業務代理和通用邏輯代碼解耦,在不改變業務邏輯的同時,動態的給原邏輯代碼添加一些通用功能,好比打印調用日誌,權限斷定,事務處理等等。設計模式
下面用代碼實現動態代理:mybatis
1. 定義一我的的動做行爲接口app
package cn.aries.pattern.ProxyPattern; /** * 人的行爲接口 * @author aries */ public interface PersonAction { /** * 說話 */ public void personSay(); /** * 跑步 */ public void personRunning(); /** * 吃東西 */ public void personEating(); }
2. 建立人行爲的的實現類框架
package cn.aries.pattern.ProxyPattern; public class PersonActionImpl implements PersonAction{ @Override public void personSay() { System.out.println("人在說話..."); } @Override public void personRunning() { System.out.println("人在跑步..."); } @Override public void personEating() { System.out.println("人在吃東西..."); } }
3. 動態代理須要一個實現了InvoketionHandler接口的類ide
package cn.aries.pattern.ProxyPattern; import java.lang.reflect.InvocationHandler; import java.lang.reflect.Method; import java.lang.reflect.Proxy; public class ProxyPerson implements InvocationHandler{ //被代理的實例對象 PersonAction obj; private ProxyPerson(PersonAction obj){ this.obj = obj; } @Override public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { //執行方法以前打印動做開始。 System.out.println(method.getName() + "ation start ..."); //使用反射執行目標方法 method.invoke(obj, args); //在方法執行結束時打印動做結束。 System.out.println(method.getName() + "ation end ..."); return null; } //定義一個靜態方法生成代理對象 public static Object getProxyPersonAction(PersonAction obj){ PersonAction proxy = (PersonAction) Proxy.newProxyInstance(obj.getClass().getClassLoader(), obj.getClass().getInterfaces(), new ProxyPerson(obj)); return proxy; } }
4. 客戶端代碼函數
package cn.aries.pattern.ProxyPattern; public class App { public static void main(String[] args) throws Exception { //設置系統參數,將生成的代理類的class文件保存到本地 System.getProperties().put("sun.misc.ProxyGenerator.saveGeneratedFiles", "true"); PersonAction pa = new PersonActionImpl(); //調用生成代理類的方法 PersonAction proxyPa = (PersonAction) ProxyPerson.getProxyPersonAction(pa);
//用代理對象調用目標方法 proxyPa.personSay(); proxyPa.personRunning(); proxyPa.personEating(); //打印代理對象的父類 System.out.println(proxyPa.getClass().getSuperclass()); } }
執行結果:學習
personSayation start ...
人在說話...
personSayation end ...
personRunningation start ...
人在跑步...
personRunningation end ...
personEatingation start ...
人在吃東西...
personEatingation end ...
class java.lang.reflect.Proxyui
當方法在中的是分別執行咱們在目標方法執行先後添加的代碼。
5. 代理對象是經過Proxy.newProxyInstance(...)這個方法生成的,咱們進入源代碼查看下
public static Object newProxyInstance(ClassLoader loader,Class<?>[] interfaces,InvocationHandler h)throws IllegalArgumentException{ if (h == null) { throw new NullPointerException(); } final Class<?>[] intfs = interfaces.clone(); final SecurityManager sm = System.getSecurityManager(); if (sm != null) { checkProxyAccess(Reflection.getCallerClass(), loader, intfs); } /* * Look up or generate the designated proxy class.
這裏生成代理類的字節碼文件 */ Class<?> cl = getProxyClass0(loader, intfs); /* * Invoke its constructor with the designated invocation handler.
*/ try {
//在這裏獲取代理類的構造函數,從前面的運行結果中能夠得知,代理類是Proxy類的子類
//而constructorParams在Proxy類中是一個靜態的常量: private static final Class<?>[] constructorParams = { InvocationHandler.class };
//因此這裏獲取的帶InvocationHandler對象爲入參的構造函數,也就是其父類Proxy的構造函數:protected Proxy(InvocationHandler h){...} final Constructor<?> cons = cl.getConstructor(constructorParams); final InvocationHandler ih = h;
//這裏調用newInstance()方法建立代理對象,其內部實現是:return cons.newInstance(new Object[] {h} );使用反射經過含參(hanlder)生成代理對象。
//其中h賦值給了其父類Proxy類的成員變量: protected InvocationHandler 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()); } }
6. 到此我瞭解了代理對象的生產過程,可是代理對象和handler是什麼關係呢,又是如何調用其invoke(...)方法呢,這暫時是個謎團讓咱們來看下生成的代理類的源碼,這些就都清楚了。
注:System.getProperties().put("sun.misc.ProxyGenerator.saveGeneratedFiles", "true"); 這個是設置系統參數,將生產的代理類本身碼文件保存在本地,而後咱們經過反編譯就能夠得到其Java代碼。
package com.sun.proxy; import cn.aries.pattern.ProxyPattern.PersonAction; import java.lang.reflect.InvocationHandler; import java.lang.reflect.Method; import java.lang.reflect.Proxy; import java.lang.reflect.UndeclaredThrowableException; public final class $Proxy0 extends Proxy implements PersonAction { //這五個靜態變量前三個m0,m1,m2分別是代理類繼承的Object類的hashcode(),equals(),toString()方法 //其餘從m3開始是繼承的們定義的接口類的方法根據方法的多少m後面的數字遞增 private static Method m1; private static Method m3; private static Method m5; private static Method m0; private static Method m4; private static Method m2; static { try { //這裏使用靜態代碼塊對經過反射對代理對象中的方法進行實例化 m1 = Class.forName("java.lang.Object").getMethod("equals", new Class[] { Class.forName("java.lang.Object") }); m3 = Class.forName("cn.aries.pattern.ProxyPattern.PersonAction").getMethod("personEating", new Class[0]); m5 = Class.forName("cn.aries.pattern.ProxyPattern.PersonAction").getMethod("personRunning", new Class[0]); m0 = Class.forName("java.lang.Object").getMethod("hashCode", new Class[0]); m4 = Class.forName("cn.aries.pattern.ProxyPattern.PersonAction").getMethod("personSay", new Class[0]); m2 = Class.forName("java.lang.Object").getMethod("toString", new Class[0]); return; } catch (NoSuchMethodException localNoSuchMethodException) { throw new NoSuchMethodError(localNoSuchMethodException.getMessage()); } catch (ClassNotFoundException localClassNotFoundException) { throw new NoClassDefFoundError(localClassNotFoundException.getMessage()); } } public $Proxy0(InvocationHandler paramInvocationHandler)throws{ super(paramInvocationHandler); } //這裏是對咱們定義的personEating方法進行實現 //根據類文件咱們能夠看到,代理類繼承了Proxy類,因此其成員變量中包含一個Handler實例對象的引用 //在建立代理實例對象的時候,咱們使用的protected Proxy(InvocationHandler h) {this.h = h;}這個構造函數 //因此下面的h就是咱們傳進去的handler對象 //這裏使用handler對象調用本身的invoke()方法,m3就是咱們要執行的方法, //後面的方法的參數,若是有參數就傳對應的參數,沒有就傳null //此時咱們明白了代理對象和handler的關係,以及如何調用到invoke()方法有了明確的認識了。 public final void personEating()throws{ try { this.h.invoke(this, m3, null); return; }catch (Error|RuntimeException localError){ throw localError; }catch (Throwable localThrowable){ throw new UndeclaredThrowableException(localThrowable); } } //這裏原理同上,爲了節省空間這裏就不貼出來了 public final void personSay(){...} public final void personRunning(){...} public final int hashCode()throws{ try{ return ((Integer)this.h.invoke(this, m0, null)).intValue(); }catch (Error|RuntimeException localError){ throw localError; }catch (Throwable localThrowable){ throw new UndeclaredThrowableException(localThrowable); } } public final String toString()throws { try{ return (String)this.h.invoke(this, m2, null); }catch (Error|RuntimeException localError){ throw localError; }catch (Throwable localThrowable) { throw new UndeclaredThrowableException(localThrowable); } } public final boolean equals(Object paramObject)throws{ try{ return ((Boolean)this.h.invoke(this, m1, new Object[] { paramObject })).booleanValue(); }catch (Error|RuntimeException localError){ throw localError; }catch (Throwable localThrowable){ throw new UndeclaredThrowableException(localThrowable); } } }
寫完後瀏覽了一下,好像沒有發現被代理對象的引用在代理類中出現;而後想了下,代理類繼承了Proxy類,其中Proxy類中有咱們寫的InvoketionHandler對象的是實例,而這個handler實例中就存有咱們建立的被代理對象的實例引用,在invoke方法中,傳入的實例對象就是咱們穿件的這個被代理對象;這樣就間接的持有了被代理對象的實例引用。
到此動態代理的生成過程,以及是如何調用invoke()方法的原理已經搞清楚,到此本文完結。