动态代理涉及到的类或接口
- java.lang.reflect.Proxy Java动态代理机制的主类,提供了一组静态方法来为一组接口动态地生成代理类及其对象。
- java.lang.reflect.InvocationHandler 调用处理器接口,它自定义了一个invoke方法,用于集中处理在动态代理对象上的方法调用,通常在该方法中实现对委托类的代理访问。
- java.lang.ClassLoader 类装载器类,负责将类的字节码装载到JVM并为其定义类对象,然后该类才能被使用。它与普通类的唯一区别就是期字节码是由JVM在运行时动态生成的而非预存在某一个class文件中。
一个典型的动态代理创建对象过程可以分为以下四个步骤:
- 通过实现InvocationHandler接口创建自己的调用处理器
InvocationHandler handler = new InvocationHandlerImpl(...);
- 通过为Proxy类置顶ClassLoader对象和一组interface创建动态代理类
Class clazz = Proxy.getProxyClass(classLoader, new Class[] {...});
- 通过反射机制获取动态代理类的构造函数,其参数类型是调用处理器接口类型
Constructor contructor = clazz.getConstructor(new Class[] { InvocationHandler.class });
- 通过构造函数创建代理类实例,此时需将调用处理器对象作为参数被传入
Interface Proxy = (Interface)constructor.newInstance(new Object[](handler));
为了简化对象创建过程,Proxy类中的newInstance方法封装了2~4,只需要两部即可完成代理对象的创建
// To create a proxy for somr interface Foo:
InvocationHandler handler = new MyInvocationHandler(...);
Class<?> proxyClass = Proxy.getProxyClass(Foo.class.getClassLoader(), Foo.class);
Foo f = (Foo) proxyClass.getConstructor(InvocationHandler.class)
.newInstance(handler);
// Or more simply:
Foo f = (Foo) Proxy.newProxyInstance(Foo.class.getClassLoader(),
new Class<?>[] { Foo.class },
handler);
静态代理实现真是对象的所有公开方法或者接口工作量太大,所以需要使用动态代理技术,代理类在定义时不需要知道具体要代理哪个对象,根据Java的反射机制,如果我们知道了一个对象的类型,就可以知道这个对象的classLoader,今儿构造出指责格对象,然后根据这个对象的接口列表,就可以调用这个对象的相应方法。
动态代理的一个重要使用场合是实现延迟加载,即所谓的“虚代理”:首先使用代理获得一个对象的“缩影”(即只保留被代理对象的部分属性),只有在必要时在根据这个缩影获取全部被代理对象的属性。这样做的目的往往是为了提高性能,比如Hibernate中的延迟加载就是很好的例子。
动态代理机制的特点
动态生成的代理类本身的特点:
- 包:如果所代理的接口都是 public 的,那么它将被定义带顶层包,如果所代理的接口中有非public的(即package访问级别),那么它将被定义在该接口所在的包,这样设计的目的是为了最大程度保证动态代理类不会因为包管理的问题儿无法被成功定义并访问
- 类修饰符:该代理类具有 final 和 public 修饰符,意味着它可以被所有类访问但是不能被再度继承
- 类名:格式是“$ProxyN”,其中N是一个递增的数字,代表Proxy类第 N 次生成的动态代理类
- 类继承关系:Proxy类是它的父类,这个规则适用于所有由Proxy创建的动态代理类,该类还实现了其所代理的一组接口