沒事的時候翻看lang.reflect包下的代碼,發現有兩部份內容:涉及反射和動態代理。
不少地方均可以看到動態代理的影子,只是一直沒仔細看下。
在學習以前,先提出幾個問題,帶着問題來看代碼:
1.什麼是動態代理?
2.爲何使用動態代理?
3.使用它有哪些好處?
4.哪些地方須要動態代理?
--------------------分隔線-----------------------------
和動態代理有關的有兩個類
1.interface InvocationHandler
Object invoke(Object proxy, Method method, Object[] args)
只這一個方法,後面再說
2.class Proxy
真正表示動態代理的類,提供兩個靜態方法:
Class<?> getProxyClass(ClassLoader loader, Class<?>[] interface)
用來產生代理類,參數要提供interface數組,它會生成這些interface的「虛擬實現」,
用來冒充真實的對象。
Object newProxyInstance(ClassLoader loader, Class<?>[] interfaces, InvocationHandler h)
產生代理對象,多了InvocationHandler參數(只是InvocationHandler接口的實現類),
它與代理對象關聯,當請求分發到代理對象後,會自動執行h.invoke(...)方法,
invoke方法就是咱們用來作N多事情的地方 -_-。
--------------------分隔線-----------------------------
看完上面的代碼,大體明白動態代理的含義:
A接口有c方法,類B實現A接口,本來應該是執行B類中的c方法,可如今不這樣作;
我聲明產生B類的代理類B',由它來冒充B類的「兄弟」並「實現」A接口,
對外界來講B'應該也有c方法,可當真正調用它的時候,
它會去執行與它關聯InvocationHandler的invoke()方法,
在這個方法裏面你能夠作不少事情。這樣,這個請求就被「代理」到其它地方去了。
下面是根據個人理解畫的一個說明圖
--------------------分隔線-----------------------------
引用網上的一個例子來講明問題(有部分改動,轉載自:http://callan.iteye.com/blog/161806)
真實的接口: java
public interface Hello { void sayHello(String to); void print(String p); }
它的真實實現類:數組
public class HelloImpl implements Hello { public void sayHello(String to) { System.out.println("Say hello to " + to); } public void print(String s) { System.out.println("print : " + s); } }
在這裏生成與代理類相關聯的InvocationHandler對象 學習
public class LogHandler implements InvocationHandler { private Object dele; public LogHandler(Object obj) { this.dele = obj; } public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { doBefore(); //在這裏徹底能夠把下面這句註釋掉,而作一些其它的事情 Object result = method.invoke(dele, args); after(); return result; } private void doBefore() { System.out.println("before...."); } private void after() { System.out.println("after...."); } }
最後是測試類:測試
public class ProxyTest { public static void main(String[] args) { HelloImpl impl = new HelloImpl(); LogHandler handler = new LogHandler(impl); //這裏把handler與impl新生成的代理類相關聯 Hello hello = (Hello) Proxy.newProxyInstance(impl.getClass().getClassLoader(), impl.getClass().getInterfaces(), handler); //這裏不管訪問哪一個方法,都是會把請求轉發到handler.invoke hello.print("All the test"); hello.sayHello("Denny"); } }
這裏是輸出結果: this
before.... spa
print : All the test 代理
after.... 日誌
before.... code
Say hello to Denny 對象
after....
--------------------分隔線-----------------------------
最後試着來回答以前提出的問題:
1.什麼是動態代理?
一種用於轉發請求,進行特殊處理的機制,「動態」應該指的是「運行期」。
2.爲何使用動態代理?
能夠對請求進行任何處理(如事務,日誌等,這都是網上說的,我固然能夠作任何處理)
3.使用它有哪些好處?
如上
4.哪些地方須要動態代理?
不容許直接訪問某些類;對訪問要作特殊處理等,我只能想到這些。
--------------------分隔線-----------------------------
其它一些想法:
1.若是想聲明產生B類的代理類,那個B類必需要實現接口,若是沒有接口,
代理類就不能假裝成B類的「兄弟」,也就沒有存在的意思,
其實也能夠假裝成B類的「孩子」,對外他們有共同的接口,能夠這樣作吧?
2.當請求代理類的方法時,這個請求會被轉到執行與代理類關聯InvocationHandler
的invoke方法。那InvocationHandler究竟是什麼?對它的理解能夠是這樣:
它用來處理方法的調用,實現類也有一樣的意義;與代理類對象相關聯則表示,
它就是負責處理代理類應該有的動做,把全部的方法請求分發到invoke這個方法上。
--------------------分隔線-----------------------------
學習後總結,既能夠全面地觀察分析,又能加深印象。
若是個人理解有誤,別人的指證會對我產生積極影響。
若是個人理解正確,幫助其它人理解是個人榮幸。
初學者,請多多指教。