一、什么是代理
代理模式定义
为其他对象提供一种代理以控制对这个对象的访问。代理对象起到中介作用,可去掉功能服务或增加额外的服务。
常见的代理模式
远程代理:为不同地理的对象提供局域网待办对象,通过远程代理可以监控各个店铺使之能直观的了解店内信息。
虚拟代理:根据需要将资源消耗很多的对象进行延迟,真正需要的时候进行创建。
智能引用代理又分为静态代理和动态代理两种。下面重点介绍一些静态代理和动态代理。
二、静态代理
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的实现原理。