1. 什么是动态代理,有什么优势?
动态,指的是代理类实在程序运行时创建的,而不是在程序运行前手动编码来定义代理类的。这些动态代理类是在运行时候根据我们在JAVA代码中的“指示”动态生成的。相比于静态代理,动态代理的优势在于可以很方便的对代理类的函数进行统一处理,而不用修改每个代理类的函数。
2. 基于JDK实现动态代理
使用动态代理的初衷是简化代码, Javassist在进行动态代理的时候操作还是不够简便,这也违背了我们的初衷。
Jdk提供了InvocationHandler接口、Method和Proxy类来实现动态代理。
实现原理:
通过实现InvocationHandler接口创建自己的调用处理器;
通过为Proxy类指定ClassLoader对象和一组interface来创建动态代理;通过反射机制获取动态代理类的构造函数,其唯一参数类型就是调用处理器接口类型;通过构造函数创建动态代理类实例,构造时调用处理器对象作为参数参入。
跟静态代理不同的是,动态代理的过程主要分为三个步骤
• 将操作者对象注入 MyInvocationHandler 类中。
• 将 MyInvocationHandler对象注入 Proxy 类中并返回代理者对象,并在 invoke 方法中进行额外的操作
• 调用代理对象的操作方法。
其中,用 Proxy 类生成代理类的方法为 newProxyInstance(ClassLoader loader, Class<?>[] interfaces, InvocationHandler h) ,第二个参数是操作者的接口数组,意味着只能代理它实现的接口里的方法。
3. 实现案例
3.1 创建一个InfRunCtrl接口
public interface InfRunCtrl {
void execute();
}
3.2 创建一个JobInvocationHandler处理器
public class JobInvocationHandler implements InvocationHandler {
private InfRunCtrl infRunCtrl;
public JobInvocationHandler() {
super();
}
public JobInvocationHandler(InfRunCtrl infRunCtrl) {
super();
this.infRunCtrl = infRunCtrl;
}
/**
* 生成代理对象
**/
public static InfRunCtrl getProxyObject(InfRunCtrl ctrl) {
InvocationHandler handler = new JobInvocationHandler(ctrl);
// 生成代理对象
InfRunCtrl infRunCtrlProxy = (InfRunCtrl) Proxy.newProxyInstance(ctrl.getClass().getClassLoader(),
ctrl.getClass().getInterfaces(), handler);
return infRunCtrlProxy;
}
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
// 记录开始时间
// 执行具体的方法。
method.invoke(infRunCtrl, args);
// 记录结束时间
return null;
}
}
3.3 创建代理测试类DynamicProxyTest
public class DynamicProxyTest {
public static void main(String[] args) {
// 获取代理对象
InfRunCtrl infRunCtrlProxy = JobInvocationHandler.getProxyObject(ctrl, updateJobScheduler, hostName);
infRunCtrlProxy.execute();
}
}