代理描述
1.生活中:
代理就是一個人或者一個組織代表其他人去做一件事的現實生活中的。在一些情況下,一個客戶不想或者不能夠直接引用一個對象,而代理對象可以在用戶端和目标對象之間起到中介的作用。
2.官方:
代理模式是對象的結構模式。代理模式給某一個對象提供一個代理對象,并由代理對象控制對原對象的引用
一、靜态代理
類圖結構如下

在代理模式中的角色:
● 抽象主題角色:聲明了目标對象和代理對象的共同接口,這樣一來在任何可以使用目标對象的地方都可以使用代理對象。
● 真實主題角色:定義了代理對象所代表的目标對象。
● 代理主題角色:代理對象内部含有目标對象的引用,進而可以在任何時候操作目标對象;代理對象提供一個與目标對象相同的接口,以便可以在任何時候替代目标對象。代理對象通常在用戶端調用傳遞給目标對象之前或之後,執行某個操作,而不是單純地将調用傳遞給目标對象。它可以增加一些真實主題裡面沒有的功能。
生活中的例子:過年加班比較忙,沒空去買火車票,這時可以打個電話到附近的票務中心,叫他們幫你買張回家的火車票,當然這會附加額外的勞務費。但要清楚票務中心自己并不賣票,隻有火車站才真正賣票,票務中心賣給你的票其實是通過火車站實作的。這點很重要!
上面這個例子,你就是“客戶”,票務中心就是“代理角色”,火車站是“真實角色”,賣票稱為“抽象角色”!
代碼
抽象主題角色
真實主題角色
代理主題角色(添加了身份驗證功能)
第二個代理主題角色(添加了日志功能)
用戶端
結果:
身份驗證————–
售票
日志…
改簽
從上面例子可以看出 用戶端通過代理來購票 而代理實際上不能賣票給客戶,他實際上是通過目标對象賣票給客戶的,也就是說他是通過真實主題的目标對象實作給用戶端賣票的功能,他隻是一個中介,但我們可以在它裡面增加一些功能,比如身份驗證或者宣傳打廣告等其他的功能。
靜态代理類:在程式運作前,代理類的.class檔案就已經存在了,已确定被代理的對象
靜态代理:
優點:對真實對象進行封裝,不會修改目标類的代碼。
缺點:
1.多個不同類型目标對象需要代理時,我就需要建立多個代理類,造成類的膨脹
2.代碼的備援
3.編譯期加入,不夠靈活
二、動态代理
描述(這個描述從網上看到的,相對比較容易了解)
動态代理(dynamic proxy):相比靜态代理,動态代理具有更強的靈活性,因為它不用在我們設計實作的時候就指定某一個代理類來代理哪一個被代理對象,我們可以把這種指定延遲到程式運作時由jvm來實作。
所謂代理,就是需要代理類和被代理類有相同的對外接口或者說成服務,是以代理類一般都必須實作了所有被代理類已實作的接口,因為接口就是制定了一系列對外服務的标準。
1.jdk實作動态代理
正因為動态代理有這樣靈活的特性,是以我們在設計動态代理類(dynamicproxy)時不用顯式地讓它實作與真實主題類(realsubject)相同的接口(interface),而是把這種實作推遲到運作時。
為了能讓dynamicproxy類能夠在運作時才去實作realsubject類已實作的一系列接口并執行接口中相關的方法操作,需要讓dynamicproxy類實作jdk自帶的java.lang.reflect.invocationhandler接口,該接口中的invoke()方法能夠讓dynamicproxy執行個體在運作時調用被代理類的“對外服務”,即調用被代理類需要對外實作的所有接口中的方法,也就是完成對真實方法的調用,java幫助文檔中稱這些真實方法為處理程式。
按照上面所述,我們肯定必須先把被代理類realsubject已實作的所有interface都加載到jvm中,不然jvm怎麼能夠找到這些方法呢?明白了這個道理,那麼我們就可以建立一個被代理類的執行個體,獲得該執行個體的類加載器classloader。
所謂的類加載器classloader,就是具有某個類的類定義,即類的内部相關結構(包括繼承樹、方法區等等)。
更重要的是,動态代理模式可以使得我們在不改變原來已有的代碼結構的情況下,對原來的“真實方法”進行擴充、增強其功能,并且可以達到控制被代理對象的行為的目的。請詳看下面代碼中的dynamicproxy類,其中必須實作的invoke()方法在調用被代理類的真實方法的前後都可進行一定的特殊操作。這是動态代理最明顯的優點
類圖
結果同上
優缺點
優點:
1、一個動态代理類更加簡單了,可以解決建立多個靜态代理的麻煩,避免不斷的重複多餘的代碼
2、調用目标代碼時,會在方法“運作時”動态的加入,決定你是什麼類型,才調誰,靈活
1、系統靈活了,但是相比而言,效率降低了,比靜态代理慢一點
2、動态代理比靜态代理在代碼的可讀性上差了一點,不太容易了解
3、jdk動态代理隻能對實作了接口的類進行代理
總結
各有各的好,具體情況具體讨論
2.cglib實作動态代理
描述(網上整理)
aop的源碼中用到了兩種動态代理來實作攔截切入功能:jdk動态代理和cglib動态代理。
兩種方法同時存在,各有優劣。jdk動态代理是由java内部的反射機制來實作的 ,cglib動态代理底層則是借助asm來實作的。總的來說,反射機制在生成類的過程中比較高效,而asm在生成類之後的相關執行過程中比較高效(可以通過将asm生成的類進行緩存,這樣解決asm生成類過程低效問題)。還有一點必須注意:jdk動态代理的應用前提,必須是目标類基于統一的接口。如果沒有上述前提,jdk動态代理不能應用。由此可以看出,jdk動态代理有一定的局限性,cglib這種第三方類庫實作的動态代理應用更加廣泛, 且在效率上更有優勢。
jdk的動态代理機制隻能代理實作了接口的類,否則不能實作jdk的動态代理,cglib是針對類來實作代理的,他的原理是對指定的目标類生成一個子類,并覆寫其中方法實作增強,但因為采用的是繼承,是以不能對final修飾的類進行代理。
介紹:
cglib的核心類:
net.sf.cglib.proxy.enhancer – 主要的增強類
net.sf.cglib.proxy.methodinterceptor – 主要的方法攔截類,它是callback接口的子接口,需要使用者實作
net.sf.cglib.proxy.methodproxy – jdk的java.lang.reflect.method類的代理類,可以友善的實作對源對象方法的調用,如使用:
object o = methodproxy.invokesuper(proxy, args);//雖然第一個參數是被代理對象,也不會出現死循環的問題。
net.sf.cglib.proxy.methodinterceptor接口是最通用的回調(callback)類型,它經常被基于代理的aop用來實作攔截(intercept)方法的調用。這個接口隻定義了一個方法
public object intercept(object object, java.lang.reflect.method method,
object[] args, methodproxy proxy) throws throwable;
第一個參數是代理對像,第二和第三個參數分别是攔截的方法和方法的參數。原來的方法可能通過使用java.lang.reflect.method對象的一般反射調用,或者使用 net.sf.cglib.proxy.methodproxy對象調用。net.sf.cglib.proxy.methodproxy通常被首選使用,因為它更快