#### **參考文章**
[Android設計模式源碼解析之Proxy模式](http://blog.csdn.net/singwhatiwanna/article/details/44590179)
[《JAVA與模式》之代理模式](http://www.cnblogs.com/java-my-life/archive/2012/04/23/2466712.html)
[【設計模式】代理模式](http://www.cnblogs.com/chenpi/p/5190397.html)
[Java之代理](http://www.hmoore.net/alex_wsc/java/461708)
[Java之美[從菜鳥到高手演變]之設計模式二](http://blog.csdn.net/zhangerqing/article/details/8239539)
[《Android源碼設計模式解析與實戰》讀書筆記(十八)](http://blog.csdn.net/qq_17766199/article/details/50492805)
[CGLIB(Code Generation Library)詳解](http://blog.csdn.net/danchu/article/details/70238002)
[Java動態代理分析](http://blog.csdn.net/danchu/article/details/70146985)
#### **代理模式**
**基本概念**:
代理模式定義:為其他對象提供一種代理以控制對這個對象的訪問,代理對象起到中介作用,可去掉功能服務或增加額外的服務。代理模式又稱為委托模式。
**代理模式的使用場景**:當無法或不想直接訪問某個對象或訪問某個對象存在困難時可以通過一個代理對象來間接訪問,為了保證客戶端使用的透明性,委托對象與代理對象需要實現相同的接口。(**靜態代理模式**)
UML類圖

代碼如下所示
**抽象主題類**
~~~
public abstract class Subject {
/**
*一個普通的業務方法
/
public abstract void visit();
}
~~~
真正主題類
~~~
public class RealSubject extends Subject {
@Override
public void visit() {
// RealSubject 中visit 的具體邏輯
System .out.println("Real subject!”) ;
}
}
~~~
代理類
~~~
public class ProxySubject extends Subject {
private RealSubject mSubject;//持有真實主題的引用
public ProxySubject(RealSubject mSubject) {
this. mSubject = mSubject;
}
@Override
public void visit() {
//通過真實主題引用的對象調用真實主題中的邏輯方法
mSubject.visit();
}
}
~~~
客戶端類
~~~
public class Client {
public static void main(String() args) {
//構造一個真實主題對象
RealSubject real= new RealSubject() ;
//通過真實主題對象構造一個代理對象
ProxySubject proxy= new ProxySubject(real);
// 調用代理的相關方法
proxy.visit();
}
}
~~~
**角色介紹**
* **Subject :抽象主題類**。
該類的主要職責是**聲明**真實主題與代理的**共同接口方法**,該類**既可以是一個抽象類也可以是一個接口**。
* **RealSubject : 真實主題類**。
該類也稱為**被委托類**或**被代理類**,該類**定義了代理所表示的真實對象,由其執行具體的業務邏輯方法**,而客戶類則通過代理類間接地調用真實主題類中定義的方法。
* **ProxySubject:代理類**。
該類也稱為**委托類**或**代理類**,該類**持有一個對真實主題類的引用,在其所實現的接口方法中調用真實主題類中相應的接口方法執行,以此起到代理的作用。**
* **Client:客戶類**,即**使用代理類的類型**。
#### **代理模式的簡單實現**
例子:小民以前在公司上班時,就遇到過被老板拖欠工資甚至克扣工資的情況,這種情況下小民還是通過法律途徑來解決問題, 一旦小民選擇了走法律途徑解決該糾紛,那么不可避免地就需要請一個律師來作為自己的訴訟代理人,我們將訴訟的流程抽象在一個接口類中。以小民訴訟的流程舉例。那么需要代理律師代理,訴訟簡單流程:提交申請–>進行舉證–>開始辯護–>訴訟完成。
**訴訟接口類**:
~~~
public interface ILawsuit {
/**
* 提交申請
*/
void submit();
/**
* 進行舉證
*/
void burden();
/**
* 開始辯護
*/
void defend();
/**
* 訴訟完成
*/
void finish();
}
~~~
4 個方法非常簡單,都是訴訟的一般流程。
**具體訴訟人小民**:
~~~
public class XiaoMin implements ILawsuit{
@Override
public void submit() {
//小民申請仲裁
System.out.println("老板年底拖欠工資,特此申請仲裁!");
}
@Override
public void burden() {
//小民提交證據
System.out.println("這是合同書和過去一年的銀行工資流水!");
}
@Override
public void defend() {
//鐵證如山
System.out.println("證據確鑿,不需要再說什么!");
}
@Override
public void finish() {
//結果
System.out.println("訴訟成功,判決老板即日起七天內結算工資!");
}
}
~~~
該類實現!Lawsuit 并對其中4 個方法作出具體的實現邏輯,邏輯很簡單, 都只是輸出一段話而己, 當然, 小民自己是不會去打官司的,于是小民請個律師代替自己進行訴訟。
**代理律師**:
~~~
public class Lawyer implements ILawsuit{
private ILawsuit mLawsuit; //持有一個具體被代理者的引用
public Lawyer(ILawsuit lawsuit) {
this.mLawsuit = lawsuit;
}
@Override
public void submit() {
mLawsuit.submit();
}
@Override
public void burden() {
mLawsuit.burden();
}
@Override
public void defend() {
mLawsuit.defend();
}
@Override
public void finish() {
mLawsuit.finish();
}
}
~~~
律師類表示代理者律師,在該類里面會持有一個被代理者( 這里也就是上面的XiaoMin 類)的引用, 律師所執行的方法實質就是簡單地調用被代理者中的方法,下面來看看客戶類中具體的調用執行關系。
**開始仲裁**:
~~~
public class Client {
public static void main(String[] args) {
//構造出訴訟人小民
ILawsuit xiaomin = new XiaoMin();
//構造一個代理律師,并將小民傳遞進去
ILawsuit lawyer = new Lawyer(xiaomin);
//律師提交申請
lawyer.submit();
//律師進行舉證
lawyer.burden();
//律師代小民辯護
lawyer.defend();
//完成訴訟
lawyer.finish();
}
}
~~~
結果:
~~~
老板年底拖欠工資,特此申請仲裁!
這是合同書和過去一年的銀行工資流水!
證據確鑿,不需要再說什么!
訴訟成功,判決老板即日起七天內結算工資!
~~~
其實代理模式也很簡單,其主要還是一種**委托機制**,**真實對象將方法的執行委托給代理對象,而且委托得干凈利落毫不做作**,這也是為什么代理模式也稱為委托模式的原因,相信大家不難理解。除此之外,大家其實可以繼續發散思維,**其實我們的代理類完全可以代理多個被代理類**,就像上面的例子一樣, 一個律師可以代理多個人打官司,這是沒有任何問題的,而具體到底是代理的哪個人,這就要看代理類中所持有的實際對象類型,上述的例子中實際對象類型是XiaoMin,也就是代理的XiaoMin。
同樣我們也可以代理其他人,只需要實現ILawsuit即可。上面的代理模式也叫**靜態代理**,也就是**在代碼運行前代理類的class文件就已經存在**。那么相反,當然也會有動態代理,而**動態代理則與靜態代理相反**,**通過反射機制動態地生成代理者的對象,也就是說我們在code 階段壓根就不需要知道代理誰,代理誰我們將會在執行階段決定**。而Java 也給我們提供了一個便捷的動態代理接口lnvocationHandler,實現該接口需要重寫其調用方法invoke。
~~~
public class DynamicProxy implements InvocationHandler {
@Override
public Object invoke(Object proxy, Method method, Object[] args)
throws Throwable {--- --
return null;
}
}
~~~
在這里,我們**主要通過invoke 方法來調用具體的被代理方法,也就是真實的方法**。動態代理可以使我們的代碼邏輯更簡沽, 不過在這之前我們得首先完善動態代理類。
下面用動態代理實現上述例子:
Java提供了一個便捷的動態代理接口InvocationHandler,我們來實現它:
~~~
public class DynamicPorxy implements InvocationHandler{
private Object obj; //被代理類的引用
public DynamicPorxy(Object obj) {
this.obj = obj;
}
@Override
public Object invoke(Object proxy, Method method, Object[] args)
throws Throwable {
// 調用被代理類對象的方法
Object result = method.invoke(obj, args);
return result;
}
}
~~~
如上代碼所述,我們**聲明一個Object 的引用**,**該引用將指向被代理類**,而我們**調用被代理類的具體方法則在invoke 方法中執行**, 是不是很簡潔?也就是說我們原來**由代理類所做的工作現在由InvocationHandler 來處理, 不再需要關心到底代理誰**。
修改后的Client類:
~~~
public class Client {
public static void main(String[] args) {
//構造出訴訟人小民
ILawsuit xiaomin = new XiaoMin();
//1.靜態代理
//構造一個代理律師,并將小民傳遞進去
//ILawsuit lawyer = new Lawyer(xiaomin);
//--------------------------------------
//2.動態代理
//構造一個動態代理
DynamicPorxy proxy = new DynamicPorxy(xiaomin);
//獲取被代理類小民的ClassLoader
ClassLoader loader = xiaomin.getClass().getClassLoader();
//動態構造一個代理者律師
ILawsuit lawyer = (ILawsuit) Proxy.newProxyInstance(loader, new Class[]{ ILawsuit.class }, proxy);
//律師提交申請
lawyer.submit();
//律師進行舉證
lawyer.burden();
//律師代小民辯護
lawyer.defend();
//完成訴訟
lawyer.finish();
}
}
~~~
結果不變,由此可以看出**動態代理通過一個代理類來處理N多個被代理類,其實質是對代理者與被代理者解耦,使兩者直接沒有直接的耦合關系**。相對而言**靜態代理則只能為給定接口下的實現類做代理,如果接口不同那么就需要重新定義不同的代理類,較為復雜,但是靜態代理更符合面向對象原則。具體使用哪種方式,根據個人喜好。**
**靜態代理和動態代理是從code 方面來區分代理模式的兩種方式**。
**從適用范圍區分不同類型的代理實現**:

* **遠程代理(Remote Proxy)**:為某個對象在不同的內存地址空間提供局部代理。使系統可以將Server 部分的實現隱藏,以便Client 可以不必考慮Server 的存在。
為不同地理的對象,提供局域網代表對象。
* **虛擬代理(Virtual Proxy)**:使用一個代理對象表示一個十分耗資源的對象并在真正需要時才創建。
根據需要將資源消耗很大的對象進行延遲,真正需要時才進行創建。
* **保護代理(Protection Proxy)**:使用代理控制對原始對象的訪問。該類型的代理常被用于原始對象有不同訪問權限的情況。
* **智能引用(Smart Reference)**:在訪問原始對象時執行一些自己的附加操作并對指向原始對象的引用計數。
提供對目標對象額外的服務,**實際開發中智能引用代理應用最廣泛**。
這里要注意的是, [靜態和動態代理](http://www.hmoore.net/alex_wsc/java/490242)都可以應用于上述4 種情形,兩者是各自獨立的變化。
**靜態代理**:代理和被代理對象在代理之前是確定的,他們都實現相同的接口或者繼承相同的抽象類。

### **動態代理**:
* **背景**:
要為系統中的各種接口的類增加代理功能,那將需要太多的代理類,全部采用靜態代理方式,將是一件非常麻煩的事情!寫成百上千個代理類,會造成類爆炸,類膨脹。
#### **JDK動態代理**

Java動態代理位于**java.lang.reflect**包下,一般主要涉及到以下各類:
* **①、Interface InvocationHandler**
**Object invoke(Object proxy, Method method, Object[] args)**,在實際使用中,一般第一個參數是指代理類,method是被代理的方法,args是該方法的參數數組,沒有參數可以置空或者去掉;這個抽象方法在代理類中動態實現。
* **② class Proxy**:該類即為動態代理類
**Object newProxyInstance(ClassLoader loader, Class<?>[] interfaces, InvocationHandler h)**:返回代理類的一個實例,返回后的代理類可以當作被代理類使用(可使用代理類的在接口中聲明過的方法)
動態代理實現步驟:
1. 創建一個實現接口InvocationHandler的類,它必須實現invoke方法
2. 創建被代理的類以及接口
3. 調用Proxy的靜態方法,創建一個代理類
**object newProxyInstance(ClassLoader loader, Class<?>[] interfaces, InvocationHandler h)**
**JDK動態代理和[CGLIB](https://github.com/cglib/cglib)動態代理的區別**:
* **JDK動態代理**
* 一、只能代理實現了接口的類
* 二、沒有實現接口的類不能實現JDK的動態代理
* **CGLIB動態代理**
1. 針對類來實現代理的
2. 對指定目標類產生一個子類,通過方法攔截技術攔截所有父類方法的調用
**CGLIB是使用繼承的方式,所以不能對final修飾的類進行代理**
#### **CGLIB(Code Generation Library)動態代理**
CGLIB庫可以動態生成一個類的子類,一個類的子類也可以用作該類的代理,所以,如果要為一個沒有實現接口的類生成動態代理類,那么可以使用CGLIB庫。
關于CGLB的使用可以參考以下文章:
[cglib動態代理介紹(一)](http://blog.csdn.net/xiaohai0504/article/details/6832990)
[CGLib動態代理原理及實現](http://blog.csdn.net/yakoo5/article/details/9099133)
[CGLIB介紹與原理 ](http://blog.csdn.net/zghwaicsdn/article/details/50957474)
[系統架構設計——設計模式之代理模式(二)CGLIB動態代理實現](http://blog.csdn.net/qq_25689397/article/details/51427164)
[動態代理proxy與CGLib的區別](http://blog.csdn.net/hintcnuie/article/details/10954631)
[AOP的底層實現-CGLIB動態代理和JDK動態代理](http://blog.csdn.net/dreamrealised/article/details/12885739)
使用CGLIB需要導入cglb的jar包[cglib-nodep-3.2.5.jar](https://github.com/cglib/cglib/releases/tag/RELEASE_3_2_5),目前是3.2.5版本
示例:
**Train.class**
~~~
package com.cglib.proxy;
public class Train {
public void move() {
System.out.println("火車行駛中.........");
}
}
~~~
**CglibProxy.class**
~~~
package com.cglib.proxy;
import java.lang.reflect.Method;
import net.sf.cglib.proxy.Enhancer;
import net.sf.cglib.proxy.MethodInterceptor;
import net.sf.cglib.proxy.MethodProxy;
public class CglibProxy implements MethodInterceptor {
private Enhancer enhancer = new Enhancer();//創建代理類的屬性
/**
* 得到代理類
* @param clazz
* @return
*/
public Object getProxy(Class clazz) {
// 設置于創建子類的類,就是說為哪個類來產生代理類
enhancer.setSuperclass(clazz);
enhancer.setCallback(this);
return enhancer.create();
}
/**
* 攔截所有目標類方法的調用
* obj:目標類的實例
* method:目標方法的反射對象
* args:方法的參數
* proxy:代理類的實例
*/
@Override
public Object intercept(Object obj, Method method, Object[] args, MethodProxy proxy)
throws Throwable {
System.out.println("日志開始......");
// 代理類調用父類的方法
proxy.invokeSuper(obj, args);
System.out.println("日志結束.......");
return null;
}
}
~~~
**Client.class**
~~~
package com.cglib.proxy;
public class Client {
public static void main(String[] args) {
CglibProxy proxy = new CglibProxy();
Train t = (Train) proxy.getProxy(Train.class);
t.move();
}
}
~~~
輸出結果:
~~~
日志開始......
火車行駛中.........
日志結束.......
~~~
**JDK動態代理實現的思路**:
**實現功能:通過Proxy的newProxyInstance返回代理對象**
* 1、聲明一段代碼(動態產生代理)
* 2、編譯源碼(JDK Compiler API),產生新的類(代理類)
* 3、 將這個類load到內存當中,產生一個新的對象(代理對象)
* 4、return 代理對象
**代理模式實際應用**:
1、調用jar包或者庫library中的某一個方法,不能修改源碼,所以可以采用代理模式機制在方法前后添加一些邏輯:日志處理、時間、其它業務邏輯。這種模式也叫AOP(面向切面編程)