代理模式
爲其他對象提供一種代理以控制對這個對象的訪問
代理對象起中介作用,可去掉功能服務或增加額外的服務
對象消耗太多資源,並不是每一條邏輯路徑都需要這個對象,延遲創建對象的想法
限制訪問某個對象,提供一組方法給普通用戶,特殊方法給管理員用戶
遠程代理
Remote Proxy
爲不同地理的對象,提供局域網代表對象
遠程代理又稱之爲大師(Ambassador)
虛擬代理
virtual Proxy
根據需要將資源消耗很大的對象進行延遲真正需要的時候進行創建
保護代理
權限控制
智能引用代理
提供額外的服務
取代簡單的指針,它在訪問對象時執行一些附加操作
Copy-on-Write代理
虛擬代理的一種,把複製(克隆)操作延遲到只有客戶端真正需要時才執行
兩種實現方式
- 靜態代理
- 動態代理
靜態代理
代理和被代理對象在代理之前是確定的,他們實現相同的接口或者繼承相同的抽象類
汽車行駛
package proxyDemo;
public interface Moveable {
void move();
}
package proxyDemo;
import java.util.Random;
public class Car implements Moveable {
@Override
public void move() {
long startTime = System.currentTimeMillis();
System.out.println("汽車開始行駛");
try {
System.out.println("汽車行駛中");
Thread.sleep(new Random().nextInt(1000)); //隨即產生一個大於0小於1000的整數;用進程的例子模擬汽車行駛
} catch (InterruptedException e) {
e.printStackTrace();
}
long endTime = System.currentTimeMillis();
System.out.println("汽車結束行駛");
System.out.println("汽車行駛時間:"+(endTime-startTime)+"ms");
}
}
使用代理方式
import java.util.Random;
public class Car implements Moveable {
@Override
public void move() {
try {
System.out.println("汽車行駛中");
Thread.sleep(new Random().nextInt(10000));
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
package proxyDemo;
public class proxyCar extends Car {
@Override
public void move() {
long startTime = System.currentTimeMillis();
System.out.println("汽車開始行駛");
super.move();
long endTime = System.currentTimeMillis();
System.out.println("汽車結束行駛");
System.out.println("汽車行駛時間:"+(endTime-startTime)+"ms");
}
}
二者的測試類
package proxyDemo;
public class Test {
public static void main(String[] args) {
// Car benz = new Car();
// benz.move();
Moveable m = new proxyCar();
m.move();
}
}
- 抽象對象 聲明瞭目標對象和代理對象的共同接口
- 目標對象 定義了代理對象所代表的目標對象
- 代理對象 內部含有目標對象的引用,從而在任何時候操縱目標對象,代理對象提供了與目標對象相同的接口,在任何時候可以替代目標對象.
JDK動態代理
java動態代理類位於java.lang.reflect包下,一般主要涉及兩個類:
1.Interface InvocationHandler
public object invoke(Object obj,Method method,Object[] args)
這個抽象方法在代理類中動態實現
2.Proxy
static Object newProxyInstance(ClassLoader loader,Class[] interfaces,InvocationHandler h)
返回代理類的一個實例,返回後的代理類可以當作被代理類使用
代碼如下
package jdkproxy;
public interface Moveable {
void move();
}
package jdkproxy;
public class Car implements Moveable{
public void move()
{
System.out.println("---汽車行駛中---");
}
}
package jdkproxy;
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;
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
// TODO Auto-generated method stub
System.out.println("---時間處理---");
method.invoke(target);
System.out.println("---時間結束---");
return null;
}
}
package jdkproxy;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Proxy;
//JDK動態代理測試類
public class Test {
public static void main(String[] args) {
Car car = new Car();
InvocationHandler h = new TimeHandler(car);
Class<?> cls = car.getClass();
Moveable m =(Moveable)Proxy.newProxyInstance(cls.getClassLoader(), cls.getInterfaces(),h);
m.move();
}
}
cglib
導入jar包,cglib-nodep-().jar
JDK實現動態代理需要實現類通過接口定義業務方法,對於沒有接口的類,如何實現動態代理呢?
CGLIB是直接繼承代理
性能:CGLib>JDK
時間耗費:JDK時間效率高
單例的對象使用CGLib
代碼示例
public class SayHello {
public void say(){
System.out.println("hello everyone");
}
}
public class CglibProxy implements MethodInterceptor{
private Enhancer enhancer = new Enhancer();
public Object getProxy(Class clazz){
//設置需要創建子類的類
enhancer.setSuperclass(clazz);
enhancer.setCallback(this);
//通過字節碼技術動態創建子類實例
return enhancer.create();
}
//實現MethodInterceptor接口方法
public Object intercept(Object obj, Method method, Object[] args,
MethodProxy proxy) throws Throwable {
System.out.println("前置代理");
//通過代理類調用父類中的方法
Object result = proxy.invokeSuper(obj, args);
System.out.println("後置代理");
return result;
}
}
public class DoCGLib {
public static void main(String[] args) {
CglibProxy proxy = new CglibProxy();
//通過生成子類的方式創建代理類
SayHello proxyImp = (SayHello)proxy.getProxy(SayHello.class);
proxyImp.say();
}
}
JDK動態代理的內部實現
動態代理實現思路
實現功能:通過Proxy的newProxyInstance返回代理對象
1. 聲明一段源碼(動態產生代理)
2. 編譯源碼(JDK Compiler API),產生新的類(代理類)
3. 將這個類load到內存當中,產生一個新的對象(代理對象)
4. return 代理對象