jdk的代理模式
1.代理模式的定義:
爲其他對象提供一種代理一控制對這個對象的訪問,代理對對象起到中介作用,用於去掉部分功能服務或者是增加一些額外的服務
2.靜態代理:
代理和被代理之間的關係是確定的,他們都是實現相同的接口或者是繼承相同的抽象類;
創建接口
public interface Moveable {
void move();
}
創建車實現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();
}
}
}
① 繼承的方式:
創建Car2_以繼承的方式實現靜態代理:
public class Car2 extends Car {
@Override
public void move() {
long starttime = System.currentTimeMillis();
System.out.println("汽車開始行駛....");
super.move();
long endtime = System.currentTimeMillis();
System.out.println("汽車結束行駛.... 汽車行駛時間:"
+ (endtime - starttime) + "毫秒!");
}
}
② 聚合的方式:
創建Car3__以聚合的方式實現靜態代理:
public class Car3 implements Moveable {
public Car3(Car car) {
super();
this.car = car;
}
private Car car;
@Override
public void move() {
long starttime = System.currentTimeMillis();
System.out.println("汽車開始行駛....");
car.move();
long endtime = System.currentTimeMillis();
System.out.println("汽車結束行駛.... 汽車行駛時間:"
+ (endtime - starttime) + "毫秒!");
}
}
兩者之間都可以實現靜態代理,但是相比之下,使用聚合的方式更好:
比如: 上面的例子只是增加了時間記錄那麼需要創建一個Car2,那麼如果在增加一個記錄行駛日誌呢?那麼就要再創建一個Car4,再增加一個權限呢?那麼就需要再創建一個Car5來繼承Car4,.........這樣的話沒增加一個功能就需要創建一個實例.但是使用聚合的方式就不會這樣了
同樣創建一個move接口:
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();
}
}
}
創建時間代理_用於記錄時間
public class CarTimeProxy implements Moveable {
public CarTimeProxy(Moveable m) {
super();
this.m = m;
}
private Moveable m;
@Override
public void move() {
long starttime = System.currentTimeMillis();
System.out.println("汽車開始行駛....");
m.move();
long endtime = System.currentTimeMillis();
System.out.println("汽車結束行駛.... 汽車行駛時間:"
+ (endtime - starttime) + "毫秒!");
}
}
創建日誌代理_用於記錄日誌
public class CarLogProxy implements Moveable {
public CarLogProxy(Moveable m) {
super();
this.m = m;
}
private Moveable m;
@Override
public void move() {
System.out.println("日誌開始....");
m.move();
System.out.println("日誌結束....");
}
}
創建測試類
public static void main(String[] args) {
Car car = new Car();
CarLogProxy clp = new CarLogProxy(car);
CarTimeProxy ctp = new CarTimeProxy(clp);
clp.move();//此時是先執行日誌,再執行記錄行駛時間
ctp.move();//此時是先執行記錄行駛時間,再執行記錄日誌
}
這樣可以看出聚合相比於繼承要靈活了很多
但是,像權限,日誌,時間這種公共的代理,後面如果再創建了一個其他對象,如飛機,火車,自行車呢?那是不是就要創建不同的實例呢?然後這種情況下就需要用到動態代理了
3.動態代理
動態代理的原理圖如下所示:
Java動態代理類位於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[] interf aces,
InvocationHandler h): 返回代理類的一個實例,返回後的代理類可以當作被
代理類使用(可使用被代理類的在接口中聲明過的方法)
示例:
創建時間處理的handler
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
public class TimeHandler implements InvocationHandler {
public TimeHandler(Object target) {
super();
this.target = target;
}
private Object target;
/*
* 參數:
* proxy 被代理對象
* method 被代理對象的方法
* args 方法的參數
* 返回值:
* Object 方法的返回值
* */
@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("汽車結束行駛.... 汽車行駛時間:"
+ (endtime - starttime) + "毫秒!");
return null;
}
}
JDK動態代理測試:
/**
* JDK動態代理測試類
*/
public static void main(String[] args) {
Car car = new Car();
InvocationHandler h = new TimeHandler(car);
Clas s<?> cls = car.getClass();
/**
* loader 類加載器
* interfaces 實現接口
* h InvocationHandler
*/
Moveable m = (Moveable)Proxy.newProxyInstance(cls.getClassLoader(),
cls.getInterfaces(), h);
m.move();
}
總結:
動態代理實現步驟
1.創建一個實現接口InvocationHandler的類,它
必須實現i nvoke方法
2.創建被代理的類以及接口
3.調用Proxy的靜態方法,創建一個代理類
newProxyInstance(ClassLoader loader,Class[]
interfaces,InvocationHandler h)
4.通過代理調用方法
動態代理實現思路
實現功能: 通過Proxy的newProxyInstance返回代理對象
1、聲明一段源碼(動態產生代理)
2、編譯源碼(JDK Compiler API),產生新的類(代理類)
3、將這個類load到內存當中,產生一個新的對象(代理對象)
4、return 代理對象