設計模式之代理模式(靜態代理和JDK動態代理)
一、什麼是代理
代理模式定義
為其他物件提供一種代理以控制對這個物件的訪問。代理物件起到中介作用,可去掉功能服務或增加額外的服務。
常見的代理模式
遠端代理:為不同地理的物件提供區域網待辦物件,通過遠端代理可以監控各個店鋪使之能直觀的瞭解店內資訊。
虛擬代理:根據需要將資源消耗很多的物件進行延遲,真正需要的時候進行建立。
智慧引用代理又分為靜態代理和動態代理兩種。下面重點介紹一些靜態代理和動態代理。
二、靜態代理
1.靜態代理:代理和被代理物件在代理之前是確定的,他們都實現相同的介面或者繼承相同的抽象類。具體的UML關係圖如下所示:
2.靜態代理的實現。現在模擬汽車在行駛過程中的示例。在汽車行駛前後增加“汽車開始行駛”和“汽車結束行駛”的日誌,並在最後統計輸出汽車行駛的時間。
Moveable介面
public interface Moveable {
void move();
}
在這裡Car類是實現了Moveable介面的被代理類
public class Car implements Moveable { @Override public void move() { // 實現開車 try { Thread.sleep(new Random().nextInt(1000)); System.out.println("汽車行駛中..."); } catch (InterruptedException e) { e.printStackTrace(); } } }
CarTimeProxy類是代理物件
public class CarTimeProxy implements Moveable { private Moveable m; public CarTimeProxy(Moveable m){ super(); this.m = m; } @Override public void move() { long startTime = System.currentTimeMillis(); System.out.println("汽車開始行駛...."); m.move(); long endTime = System.currentTimeMillis(); System.out.println("汽車結束行駛...汽車行駛時間:"+(endTime-startTime)+"ms!"); } }
測試類:
public class Client {
/**
* 測試類
* @param args
*/
public static void main(String[] args) {
Car car = new Car();
CarTimeProxy ctp = new CarTimeProxy(car);
ctp.move();
}
}
三、動態代理
動態代理:動態產生代理,實現對不同類,不同方法的代理。
動態代理的實現方式有兩種,一種是JDK動態代理,另外一種是CGLIB動態代理。
JDK動態代理和CGLIB動態代理區別
JDK動態代理
1.只能代理實現了介面的類
2.沒有實現介面的類不能實現JDK的動態代理
CGLIB動態代理
1.針對類來實現代理的
2.對指定目標類產生一個子類,通過方法攔截技術攔截所有父類方法的呼叫。
在這裡重點介紹以下JDK的動態代理。
JDK動態代理類位於java.lang.reflect包下,一般主要涉及到以下兩個類:
(1)Interface InvocationHandler:該介面中僅定義了一個方法
public object invoke(Object obj,Method method,Object[] args)在實際使用時,第一個引數obj一般是指代理類,method是被代理的方法,args為該方法的引數陣列。這個抽象方法在代理類中動態實現。
(2)Proxy:該類即為動態代理類
static Object newProxyInstance(ClassLoader loader,Class[] interfaces,InvocationHandler h):返回代理類的一個例項,返回後的代理類可以當作被代理類使用(可使用被代理類的在介面中宣告過的方法)
所謂Dynamic Proxy是這樣一種class:它是在執行時生成的class,該class需要實現一組interface,使用動態代理,必須實現InvocationHandler介面。
動態代理步驟:
1.建立一個實現介面InvocationHandler的類,它必須實現invoke方法
2.建立被代理的類以及介面
3.通過Proxy的靜態方法,建立一個代理類
newProxyInstance(ClassLoaderloader, Class[] interfaces, InvocationHandler h)
4.通過代理呼叫方法
具體程式碼實現:
1、需要動態代理的介面:複用上面的Moveable介面
2.需要代理的物件:複用上面的Car類
3.建立一個實現了InvocatHandler的類
public class TimeHandler implements InvocationHandler {
private Object target;
public TimeHandler(Object object){
this.target = object;
}
/**
*
* @param proxy 被代理物件
* @param method 被代理物件方法
* @param args 方法的引數
* @return 返回值
* @throws Throwable
*/
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
long startTime = System.currentTimeMillis();
System.out.println("汽車開始行駛....");
method.invoke(target);
long endTime = System.currentTimeMillis();
System.out.println("汽車結束行駛...\n汽車行駛時間:"+(endTime-startTime)+"ms");
return null;
}
}
4.客戶端測試類,通過Proxy的newProxyInstance方法,生成代理物件。
public class Client {
public static void main(String[] args) {
Car car = new Car();
InvocationHandler handler = new TimeHandler(car);
Class<? extends Car> cls = car.getClass();
Moveable moveable = (Moveable) Proxy.newProxyInstance(cls.getClassLoader(),cls.getInterfaces(),handler);
moveable.move();
}
}
在這裡多說一下,Java的JDK動態代理,也是Spring的AOP的實現原理。