代理設計模式再生活中應該很常見了,如今各類中間商的貨物代售方便了咱們的生活也增長了咱們生活的成本。這種生活中的中間商行爲就是一種代理模式。java
拿一個品牌來講明:編程
在編程領域中通常存在兩種代理模式設計模式
接下來咱們先來看靜態代理ide
僅僅用來代理一個類的行爲。函數
代碼演示一下:工具
class NaiKe { void run() { System.out.println("耐克"); } } //代理類 class ShoesProxy extends NaiKe{ @Override void run() { System.out.println("agency shoes before"); super.run(); System.out.println("agency shoes after"); } }
class NaiKe{ void run() { System.out.println("耐克"); } } class ShoesProxy { NaiKe naiKe = new NaiKe(); void run() { System.out.println("agency shoes before"); naiKe.run(); System.out.println("agency shoes after"); } }
public class ProxyDesgin { public static void main(String[] args) { Shoes shoes = new ShoesProxy(new ShoesTimer(new NaiKe())); shoes.run(); } } abstract class Shoes{ abstract void run(); } class NaiKe extends Shoes{ @Override void run() { System.out.println("耐克"); } } class Adi extends Shoes{ @Override void run() { System.out.println("阿迪達斯"); } } //代理類 class ShoesProxy extends Shoes { Shoes shoes ; public ShoesProxy(Shoes shoes){ this.shoes = shoes ; } void run() { System.out.println("agency shoes before"); shoes.run(); System.out.println("agency shoes after"); } } class ShoesTimer extends Shoes { Shoes shoes ; public ShoesTimer(Shoes shoes){ this.shoes = shoes ; } void run() { System.out.println("log timer shoes before"); shoes.run(); System.out.println("log timer shoes after"); } }
畫個圖瞅瞅靜態代理this
這個就是靜態代理,兄弟們應該已經發現了它的缺點,只能指定本身想要進行代理的類,而不能對全部的類進行代理,擴展性太差,因此引出了動態代理設計
談到動態代理,腦子裏第一個出現的確定就是Java
動態代理了。咱們先來聊一下Java
動態代理。代理
先來看一個動態代理的案例code
NaiKe naiKe = new NaiKe(); Shoes shoes = (Shoes) Proxy.newProxyInstance(NaiKe.class.getClassLoader(), new Class[]{Shoes.class}, new InvocationHandler() { @Override public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { System.out.println("begin timer : " + System.currentTimeMillis()); method.invoke(naiKe,args); System.out.println("after timer : " + System.currentTimeMillis()); return null; } }); shoes.run();
咱們看一下動態代理的源碼。
咱們能夠經過如下方式讓JVM
將動態生成的代理類保存到咱們的項目中
JDK1.8
使用System.getProperties().put("sun.misc.ProxyGenerator.saveGeneratedFiles", "true");
JDK1.8
以上能夠使用1 System.getProperties().put("jdk.proxy.ProxyGenerator.saveGeneratedFiles", "true");
生成的代理類以下:
final class $Proxy0 extends Proxy implements Shoes { private static Method m1; private static Method m3; private static Method m2; private static Method m0; public $Proxy0(InvocationHandler var1) throws { super(var1); } public final boolean equals(Object var1) throws { } public final void run() throws { try { super.h.invoke(this, m3, (Object[])null); } catch (RuntimeException | Error var2) { throw var2; } catch (Throwable var3) { throw new UndeclaredThrowableException(var3); } } public final String toString() throws { } public final int hashCode() throws { } static { try { m1 = Class.forName("java.lang.Object").getMethod("equals", Class.forName("java.lang.Object")); m3 = Class.forName("desgin.proxy.Shoes").getMethod("run"); m2 = Class.forName("java.lang.Object").getMethod("toString"); m0 = Class.forName("java.lang.Object").getMethod("hashCode"); } catch (NoSuchMethodException var2) { throw new NoSuchMethodError(var2.getMessage()); } catch (ClassNotFoundException var3) { throw new NoClassDefFoundError(var3.getMessage()); } } }
從這個類的結構中,咱們能夠看出不少的東西
JAVA
動態代理僅僅只能代理接口。(類單繼承,代理對象默認繼承Proxy類)invoke
方法。上面兩個也是動態代理的原理了。咱們來仔細看一下咱們的run()
方法,也就是咱們代理對象要實現的接口
public final void run() throws { try { super.h.invoke(this, m3, (Object[])null); } catch (RuntimeException | Error var2) { throw var2; } catch (Throwable var3) { throw new UndeclaredThrowableException(var3); } }
h
,父類的h
是InvocationHandler
,而後調用了invoke
方法執行了咱們的執行邏輯。這個就是動態代理的所有實現過程
還有一個很是牛逼的點,它怎麼生成的這個代理類。來看一下代理的全過程
圖中的ASM
就是爲咱們動態生成一個代理類的工具,它直接操做了Class
字節碼的二進制,而後建立了一個代理類,返回給咱們。
Java
動態代理就聊到這裏了。下面看一看CGLIb
和AOP
彌補了Java
動態代理的不足,CGLIB
動態代理能夠代理類。它直接建立了一個被代理對象的子類,實現了對其的代理過程。咱們來看一下它的代理過程
//打印生成的代理對象,放置於當前項目下 System.setProperty(DebuggingClassWriter.DEBUG_LOCATION_PROPERTY, "."); //建立Enhancer對象,相似於JDK動態代理的Proxy類,下一步就是設置幾個參數 Enhancer enhancer = new Enhancer(); //設置目標類的字節碼文件 enhancer.setSuperclass(Tank.class); //設置回調函數 enhancer.setCallback(new MethodInterceptor() { @Override public Object intercept(Object o, Method method, Object[] objects, MethodProxy methodProxy) throws Throwable { methodProxy.invokeSuper(o,objects); return null; } }); //這裏的creat方法就是正式建立代理類 Tank proxyDog = (Tank)enhancer.create(); //調用代理類的eat方法 proxyDog.tank();
仍是和Java
動態代理類似,傳入一個須要代理的Class
,設置代理的回調函數。而後調用create
建立一個代理對象,調用代理對象的方法。
代理第一行能夠輸出代理對象,會生成三個代理對象。
查看中間那個,能夠看到咱們被代理對象的方法
public class Tank$$EnhancerByCGLIB$$a4ec679a extends Tank implements Factory { //構造方法 public Tank$$EnhancerByCGLIB$$a4ec679a() { CGLIB$BIND_CALLBACKS(this); } //被代理方法 final void tank() { MethodInterceptor var10000 = this.CGLIB$CALLBACK_0; if (var10000 == null) { CGLIB$BIND_CALLBACKS(this); var10000 = this.CGLIB$CALLBACK_0; } if (var10000 != null) { //調用加強的方法 var10000.intercept(this, CGLIB$tank$0$Method, CGLIB$emptyArgs, CGLIB$tank$0$Proxy); } else { super.tank(); } } }
在以前的CGLIB
動態代理實現中,咱們看到了攔截的回調中傳入了四個參數,從上面的源碼中能夠看到對應參數的做用。
Object o
表明生成的代理對象Method method
表明當前代理對象調用的方法Object[] objects
表明方法的參數MethodProxy methodProxy
咱們調用方法的方法代理,它沒有使用Java
自己的反射,而是動態生成一個新的類,(繼承FastClass
),向類中寫入委託類實例直接調用方法的語句。咱們能夠看一下superinvoke
的源碼
public Object invokeSuper(Object obj, Object[] args) throws Throwable { try { this.init(); MethodProxy.FastClassInfo fci = this.fastClassInfo; return fci.f2.invoke(fci.i2, obj, args); } catch (InvocationTargetException var4) { throw var4.getTargetException(); } } private static class FastClassInfo { FastClass f1; FastClass f2; int i1; int i2; private FastClassInfo() { } }
一個圖理解CgLib
動態代理過程
寫了這麼多,感受對於代理設計模式講解的篇幅不是很大,而是着重講解了動態代理的實現方式。總的而言,代理設計模式與咱們平常生活很是的接近,生活中的事物幾乎都在被代理,因此這個設計模式應該很好懂,因此着重講解了動態代理的實現方式。