代理模式是二十多種設計模式中的一個,屬於比較經常使用的設計模式。本質上就是用來委託咱們生成的代理類去完成一些額外的功能,這樣可以達到解耦、封裝的目的。
一般能夠用在RPC、AOP中。好比在RPC中,當咱們調用遠程方法時,須要委託代理類幫助咱們去經過網絡鏈接遠程的服務提供者,幫助咱們將消息編碼發送給服務端,幫咱們接受服務端發來的結果。java
在代理模式中,一般指的時靜態代理。設計模式
這是靜態代理的UML圖。代理的思想是:代理類ProxySubject擁有實際類RealSubject的相同方法doSomething(實現相同的一個接口),同時代理類內聚了實際類(即傳入實際類的一個引用),在代理類的doSomething方法中,經過實際類的引用調用實際類的doSomething方法,並在調用先後加入須要代理實現的額外功能。這樣咱們就能夠經過調用代理類的相同方法來達到咱們的目的。
舉個例子:網絡
interface Subject{ void doSomething(); }
class RealSubject implements Subject{ void doSomething(){ System.out.println("doSomething"); } }
class ProxySubject implements Subject{ private Subject target; public ProxySubject(Subject target){ this.target = target; } void doSomething(){ //do before System.out.println("do before"); target.doSomething();//調用realSubject的doSomething方法 //do after System.out.println("do after"); } }
class ProxyTest{ public static void main(String args[]){ //生成代理類,並將實際類傳入 ProxySubject proxy = new ProxySubject(new RealSubject()); proxy.doSomething(); } }
以上,經過代理類執行實際類相同的方法,咱們能夠運行額外的功能。這裏不只會運行實際類doSomething方法裏面的打印「doSomething」,還會在以前打印「do before",以後打印」do after",這兩個即爲額外的功能。框架
上面的靜態代理其實存在一個問題,一個實際類對應一個代理類,而不少時候須要代理實現的額外功能是相同的,好比咱們要在A類的某個方法調用前打印「before」,B類的某個方法調用前打印「before」,C類也有這個需求,若是用靜態代理,咱們須要寫A類的代理,B類的代理,C類的代理。。。這樣豈不是要累死。
java當中的動態代理就是爲了這個解決這個問題。其實思路也很簡單,不用去管A類、B類、C類仍是什麼其餘類,統一用反射調用實際類的方法。
java提供了動態代理類Proxy,使用其中的靜態方法Proxy.newProxyInstance(ClassLoader loader,Class<?>[] interfaces, InvocationHandler h)來動態生成代理類。interfaces爲實際類的接口,對應上面圖中的Subject,loader爲接口的Classloader,InvocationHandler接口有一個invoke方法須要本身實現,咱們委託代理類實現的額外功能便放在該方法裏。須要注意的是由此看出java的動態代理須要有接口才能使用。若是不用接口實現動態代理只能求助於cglib這類字節碼加強框架。
下面是動態代理的通常實現方法:ide
public class InvokeProxy implements InvocationHandler{ private Object target; public Object bind(Object target){ this.target = target; return Proxy.newProxyInstance(target.getClass().getClassLoader(), target.getClass().getInterfaces(), this); } @Override public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { System.out.println("do something before"); method.invoke(target, args); System.out.println("do something after"); return null; /* 若是反射調用的方法有返回值: Object result; result = method.invoke(target, args); return result; */ } }
一樣有接口Subject:this
interface Subject{ void doSomething(); }
假設類A實現了Subject接口,能夠根據以下代碼生成A的代理編碼
public class ProxyTest { public static void main(String[] args) { Subject proxyA = (Subject)new InvokeProxy().bind(new A()); proxyA.doSomething(); } }
若是還有類B實現了Subject接口,咱們只需更改上面的代碼便可,而不用像靜態代理那樣重複的編寫代碼。這就是動態代理相對於靜態代理的意義。spa