动态代理是代理模式的补充,传统的代理模式要求我们为代理类创建class文件(.java文件编译后的字节流),相对麻烦,动态代理可以省去这个步骤,在运行时生成和class文件等价的字节流,然后加载到JVM中。本文参考了//www.greatytc.com/p/6f6bb2f0ece9# ,在他之上增加了类图和自己的理解。
老规矩,向上一张类图。
类图
实例
public class Main {
public static void main(String args[]) {
Subject realSubject = new RealSubject(); //创建委托对象
ProxyHandler proxyHandler = new ProxyHandler(realSubject); //创建InvocationHandler对象
Subject proxy = (Subject) Proxy.newProxyInstance(realSubject.getClass().getClassLoader()
, realSubject.getClass().getInterfaces()
, proxyHandler); //生成代理对象
proxy.request(); //使用代理对象
}
}
interface Subject {
public void request();
}
class RealSubject implements Subject {
@Override
public void request() {
System.out.println("real request");
}
}
class ProxyHandler implements InvocationHandler{
private Subject subject;
public ProxyHandler(Subject subject){
this.subject = subject;
}
@Override
public Object invoke(Object proxy, Method method, Object[] args) //proxy就是生成的代理对象
throws Throwable {
System.out.println("====before===="); //定义预处理的工作,当然你也可以根据 method的不同进行不同的预处理工作
Object result = method.invoke(subject, args);
System.out.println("====after====");
return result;
}
}
------------------------------输出---------------------------------------
====before====
real request
====after====
结合类图,我们首先创建一个RealSubject对象,一个ProxyHandler对象,这个对象的类继承自InvocationHandler,invoke(Object proxy, Method method, Object[] args)
第一个参数proxy就是由反射创建的代理对象,第二参数表明代理对象调用的方法,第三个参数表示调用的参数,在这个方法里我们调用了realSubject的对应的方法,在之前和之后我们都可以做相应的操作,这正是代理的含义。那个这个invoke(Object proxy, Method method, Object[] args)
是什么时候调用的?答案是proxy.request();
这个方法是自动生成的,内部实现类似
public final class $Proxy1 extends Proxy implements Subject{
private InvocationHandler h;
private $Proxy1(){}
public $Proxy1(InvocationHandler h){
this.h = h;
}
public int request(int i){
Method method = Subject.class.getMethod("request", new Class[]{int.class}); //创建method对象
return (Integer)h.invoke(this, method, new Object[]{new Integer(i)}); //调用了invoke方法
}
}
这个方法将代理对象作为参数传递给InvocationHandler.invoke方法。所以调用链如下:proxy.request()--->InvocationHandler.invoke()。再结合类图就不难理解。