首先讲讲代理
举个栗子,我们买火车票有很多的方式,但是归结到底都是从12306买的。从前买票需要去火车站去买。然而现在能在网上买。在火车站买火车票就是一个原型,一个目标对象,一个被代理对象。在网上形形色色的买票的第三方,都称之为代理,是对原型目标的一个增强。
这是一个简单的概念。然后show the code。一辆车car实现了Moveable 接口中的move方法能够动起来。但是这辆车还想计算一下自己开了多久时间。因此需要加入计时功能(增强代码)。它可以在自己的类中实现。
接口
public interface Moveable {
void move();
}
实现了接口的普通类,能够作为被代理对象
public class Car implements Moveable{
public void move(){
//增强代码
不重复的业务代码
//增强代码
}
}
假如一个人也想要计时方法怎么办,复写一遍?no。太low了。
这个时候就得把增强代码给抽离出来,放在一个实现了invocationHandler接口的方法处理器中,这个处理器能够接收到目标对象,并且能对目标方法增强,实现一些重复性的需求代码(增强)
编写计时方法处理器
public class TimeHandler implements InvocationHandler {
public Object target;//目标对象,被代理对象
public TimeHandler(Object target) {
super();
this.target = target;
}
/**
* InvocationHandler只有一个类
* 第一个是被代理对象,不能直接使用
* 第二个是被代理对象要增强的方法
* 第三份是被代理方法参数
*
* 返回值是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)+"ms"); //增强代码
return null;
}
}
当一个实现了对应接口的类,比如Car实现了Moveable接口。需要相应的增强就采用JDK提供的动态代理。动态的产生一个符合需求的代理对象(增强代码+原来的代码聚合),需要的原材料就是一个目标对象,一个方法处理器,经过Proxy的静态方法newProxyInstance获取到增强后的目标对象(即代理对象)。
实现
public class Test {
public static void main(String[] args) {
Car car = new Car();
InvocationHandler ih = new TimeHandler(car);
//获取car的Class对象,用于创建代理对象
Class<? extends Car> cls = car.getClass();
/**
* 基于反射机制的动态创建代理类对象
* loader:被代理类的类加载器
* interfaces:实现了哪些接口
* h:事件处理器
*/
//***重点**** 这里把返回的动态对象强转型为了有目标方法的接口类型的类
Moveable CarProxy = (Moveable) Proxy.newProxyInstance(cls.getClassLoader(),
cls.getInterfaces(),ih);
newProxyInstancce1.move();
}
}
以上就是基于JDK提供的Proxy类实现的动态代理
几个术语
增强:就是一段代码,用于在运行时加在目标对象的目标方法上的代码
目标对象:就是这个对象需要一个功能(增强),但是这个功能在这个对象里面太啰嗦,而且这个功能又能够在和这个对象实现同一接口的其他对象中使用到。
代理对象:目标对象在被增强后的一个新的对象,实现和目标对象一样的接口,否则无法完成含增强代码的方法的调用。
理解:
JDK动态代理的本质,就是利用类的反射机制,在运行时把目标对象重新打造成,利用嵌套调用聚合一个增强方法,并返回一个增强后的代理对象,只要强转型成接口类型的类就能使用增强后的方法。