目录
动态代理定义:
所谓Dynamic Proxy是这样一种class:它是在运行时生成的class,在生成它时你必须提供一组interface给它,然后该class就宣称它实现了这些 interface。你当然可以把该class的实例当作这些interface中的任何一个来用。当然,这个Dynamic Proxy其实就是一个Proxy,它不会替你作实质性的工作,在生成它的实例时你必须提供一个handler,由它接管实际的工作。
而我们使用动态代理希望在调用被代理者的方法前后加上一些操作;
重点类和接口:
- java.lang.reflect.Proxy:这是 Java 动态代理机制的主类,它提供了一组静态方法来为一组接口动态地生成代理类及其对象。
Proxy 的静态方法:
// 方法 1: 该方法用于获取指定代理对象所关联的调用处理器
static InvocationHandler getInvocationHandler(Object proxy)
// 方法 2:该方法用于获取关联于指定类装载器和一组接口的动态代理类的类对象
static Class getProxyClass(ClassLoader loader, Class[] interfaces)
// 方法 3:该方法用于判断指定类对象是否是一个动态代理类
static boolean isProxyClass(Class cl)
// 方法 4:该方法用于为指定类装载器、一组接口及调用处理器生成动态代理类实例
static Object newProxyInstance(ClassLoader loader, Class[] interfaces,
InvocationHandler h)
- java.lang.reflect.InvocationHandler:这是调用处理器接口,它自定义了一个 invoke 方法,用于集中处理在动态代理类对象上的方法调用,通常在该方法中实现对委托类的代理访问。
InvocationHandler 的核心方法:
// 该方法负责集中处理动态代理类上的所有方法调用。第一个参数既是代理类实例,第二个参数是被调用的方法对象
// 第三个方法是调用参数。调用处理器根据这三个参数进行预处理或分派到委托类实例上发射执行
Object invoke(Object proxy, Method method, Object[] args)
- java.lang.ClassLoader:这是类装载器类,负责将类的字节码装载到 Java 虚拟机(JVM)中并为其定义类对象,然后该类才能被使用。Proxy 静态方法生成动态代理类同样需要通过类装载器来进行装载才能使用,它与普通类的唯一区别就是其字节码是由 JVM 在运行时动态生成的而非预存在于任何一个 .class 文件中。
每次生成动态代理类对象时都需要指定一个类装载器对象.
代码示例:
代码
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
interface AbstractSubject{
void methodA();
String methodB();
}
class RealSubject1 implements AbstractSubject{
@Override
public void methodA() {
System.out.println("RealSubject1.methodA()");
}
@Override
public String methodB() {
System.out.println("RealSubject1.methodB()");
return "ok";
}
}
class RealSubject2 implements AbstractSubject{
@Override
public void methodA() {
System.out.println("RealSubject2.methodA()");
}
@Override
public String methodB() {
System.out.println("RealSubject2.methodB()");
return "ok";
}
}
//调用处理类,有时候会有不同的调用处理,即在调用proxied的方法的前后会有不同的操作,这个时候也可以定义不同的Handler
class myInvocationHandler implements InvocationHandler{
//被代理的对象,在 method.invoke() 需要指出调用哪个对象的方法
AbstractSubject proxied ;
public myInvocationHandler(AbstractSubject proxied) {
this.proxied = proxied;
}
//在调用代理对象中的每一个方法时,在代码内部,都是直接调用了InvocationHandler 的invoke方法,而invoke方法根据代理类传递给自己的method参数来区分是什么方法。
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
System.out.println("调用方法("+proxied.toString()+"."+method.getName()+")之前的一些操作");
Object o= method.invoke(proxied, args);
System.out.println("调用方法("+proxied.toString()+"."+method.getName()+")之后的一些操作");
return o;
}
}
public class Test {
public static void main(String[] args) {
AbstractSubject realSubject1= new RealSubject1();
// Proxy.newProxyInstance()第二个参数是new class[]数组,里面可以有多个class对象,代表生成的代理类可以同时代理多个接口
// 调用处理类,有时候会有不同的调用处理,即在调用proxied的方法的前后会有不同的操作,这个时候也可以定义不同的Handler
AbstractSubject proxySubject = (AbstractSubject)Proxy.newProxyInstance(Test.class.getClassLoader(), new Class[]{AbstractSubject.class},new myInvocationHandler(realSubject1) );
proxySubject.methodA();
System.out.println("=========================================================");
proxySubject.methodB();
}
}
代码运行截图:
Java 动态代理具体有如下四步骤:
通过实现 InvocationHandler 接口创建自己的调用处理器;
通过为 Proxy 类指定 ClassLoader 对象和一组 interface 来创建动态代理类;
通过反射机制获得动态代理类的构造函数,其唯一参数类型是调用处理器接口类型;
通过构造函数创建动态代理类实例,构造时调用处理器对象作为参数被传入。
当然我们已经把2到4的步骤已经封装在Proxy.newInstanceProxy()中。
美中不足:
诚然,Proxy已经设计得非常优美,但是还是有一点点小小的遗憾之处,那就是它始终无法摆脱仅支持interface代理的桎梏,因为它的设计注定了这个遗憾。回想一下那些动态生成的代理类的继承关系图,它们已经注定有一个共同的父类叫Proxy。Java的继承机制注定了这些动态代理类们无法实现对class的动态代理,原因是多继承在Java中本质上就行不通。有很多条理由,人们可以否定对 class代理的必要性,但是同样有一些理由,相信支持class动态代理会更美好。接口和类的划分,本就不是很明显,只是到了Java中才变得如此的细化。如果只从方法的声明及是否被定义来考量,有一种两者的混合体,它的名字叫抽象类。实现对抽象类的动态代理,相信也有其内在的价值。此外,还有一些历史遗留的类,它们将因为没有实现任何接口而从此与动态代理永世无缘。如此种种,不得不说是一个小小的遗憾。但是,不完美并不等于不伟大,伟大是一种本质,Java动态代理就是佐例。
参考:
http://blog.youkuaiyun.com/diqi77/article/details/51673419
http://www.ibm.com/developerworks/cn/java/j-lo-proxy1/