小張是一個普普統統的碼農,天天勤勤懇懇地碼代碼。某天中午小張剛要去吃飯,一個電話打到了他的手機上。「是XX公司的小張嗎?我是YY公司的王AA」。「哦,是王總啊,有什麼事情嗎?」。溝經過後,小張弄明白了,原來客戶有個需求,恰好負責這方面開發的是小張,客戶就直接找到了他。不太小張卻沒有答應客戶的請求,而是讓客戶找產品經理小李溝通。html
是小張着急去吃麪而甩鍋嗎?並非,只是爲了使故事能夠套到代理模式上。咱們先看一下代理模式的定義: * 爲其餘對象提供一種代理,以控制對這個對象的訪問。(Provide a surrogate or placeholder for another object to control access to it)java
對照定義,碼農小張能夠映射爲其餘對象,產品經理小李爲小張的代理。咱們經過JAVA代碼,表述上面事例。程序員
基於面向對象的思想,首先定義一個碼農接口,它有一個實現用戶需求的方法。app
1jvm 2ide 3函數 4工具 5源碼分析 |
//定義一個碼農接口,他能夠實現用戶需求 |
咱們假設小牛是JAVA程序員,定義一個JAVA碼農類,他經過JAA語言實現需求。
1 2 3 4 5 6 7 8 9 10 11 12 13 |
public class JavaCoder implements ICoder{ @Override |
委屈一下產品經理,將其命名爲碼農代理類,同時讓他實現ICoder接口。
1 2 3 4 5 6 7 8 9 10 11 12 13 |
|
上面一個接口,兩個類,就實現了代理模式。Are you kidding me?這麼簡單?是的,就是這麼簡單。 咱們經過一個場景類,模擬用戶找產品經理增長需求。
1 2 3 4 5 6 7 8 9 10 11 |
|
運行程序,結果以下:
1 |
|
產品經理充當了程序員的代理,客戶把需求告訴產品經理,並不須要和程序員接觸。看到這裏,有些機智的程序員發現了問題。你看,產品經理就把客戶的需求轉達了一下,怪不得我看產品經理這麼不爽。
產品經理固然不僅是轉達用戶需求,他還有不少事情能夠作。好比,該項目決定不接受新增功能的需求了,對修CoderProxy類作一些修改:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 |
|
這樣,當客戶再有增長功能的需求時,產品經理就直接回絕了,程序員無需再對這部分需求作過濾。
咱們對上面的事例作一個簡單的抽象:
代理模式包含以下角色:
代理模式優勢:
前面講的主要是靜態代理。那麼什麼是動態代理呢?
假設有這麼一個需求,在方法執行前和執行完成後,打印系統時間。這很簡單嘛,非業務邏輯,只要在代理類調用真實角色的方法前、後輸出時間就能夠了。像上例,只有一個implDemands方法,這樣實現沒有問題。但若是真實角色有10個方法,那麼咱們要寫10遍徹底相同的代碼。有點追求的碼農,確定會對這種方法感到很是不爽。有些機智的小夥伴可能想到了用AOP解決這個問題。很是正確。莫非AOP和動態代理有什麼關係?沒錯!AOP用的偏偏是動態代理。
代理類在程序運行時建立的代理方式被稱爲動態代理。也就是說,代理類並不須要在Java代碼中定義,而是在運行時動態生成的。相比於靜態代理, 動態代理的優點在於能夠很方便的對代理類的函數進行統一的處理,而不用修改每一個代理類的函數。對於上例打印時間的需求,經過使用動態代理,咱們能夠作一個「統一指示」,對全部代理類的方法進行統一處理,而不用逐一修改每一個方法。下面咱們來具體介紹下如何使用動態代理方式實現咱們的需求。
與靜態代理相比,抽象角色、真實角色都沒有變化。變化的只有代理類。所以,抽象角色、真實角色,參考ICoder和JavaCodr。
在使用動態代理時,咱們須要定義一個位於代理類與委託類之間的中介類,也叫動態代理類,這個類被要求實現InvocationHandler接口:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 |
|
當咱們調用代理類對象的方法時,這個「調用」會轉送到中介類的invoke方法中,參數method標識了咱們具體調用的是代理類的哪一個方法,args爲這個方法的參數。
咱們經過一個場景類,模擬用戶找產品經理更改需求。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 |
|
執行結果以下:
1 2 3 |
|
經過上述代碼,就實現了,在執行委託類的全部方法前、後打印時間。仍是那個熟悉的小牛,但咱們並無建立代理類,也沒有時間ICoder接口。這就是動態代理。
總結一下,一個典型的動態代理可分爲如下四個步驟:
若是隻是想用動態代理,看到這裏就夠了。但若是想知道爲何經過proxy對象,就可以執行中介類的invoke方法,以及生成的proxy對象是什麼樣的,能夠繼續往下看。
看到這裏的小夥伴,都是有追求的程序員。上面的場景類中,經過
1 2 |
|
動態產生了一個代理類。那麼這個代理類是如何產生的呢?咱們經過代碼一窺究竟。
Proxy類的newProxyInstance方法,主要業務邏輯以下:
1 2 3 4 5 6 |
|
上面代碼作了三件事:
上面的核心,就在於getProxyClass0方法:
1 2 3 4 5 6 7 8 9 10 11 |
|
在Proxy類中有個屬性proxyClassCache,這是一個WeakCache類型的靜態變量。它指示了類加載器和代理類之間的映射。因此proxyClassCache的get方法用於根據類加載器來獲取Proxy類,若是已經存在則直接從cache中返回,若是沒有則建立一個映射並更新cache表。
咱們跟一下代理類的建立流程:
調用Factory類的get方法,而它又調用了ProxyClassFactory類的apply方法,最終找到下面一行代碼:
1 2 |
|
就是它,生成了代理類。
經過上面的分析,咱們已經知道Proxy類動態建立代理類的流程。那建立出來的代理類究竟是什麼樣子的呢?咱們能夠經過下面的代碼,手動生成:
1 2 3 4 5 6 7 8 9 10 11 |
|
經過反編譯工具查看生成的class文件:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 |
|
這樣,咱們就理解,爲何調用代理類的implDemands方法,回去執行中介類的invoke方法了。