首先看一下 java 中的动态代理类:
1. Java 动态代理类位于 java.lang.reflect 包下,一般主要涉及到以下两个类:
a. Interface InvocationHandler:该接口中仅定义了一个方法(该方法在代理类中动态实现):
/*
* 第一个参数 proxy 是代理类;第二个参数 method 是被代理的方法; 第三个是该代理方法的参数数组。
*/
public Object invoke(Object proxy, Method method, Object[] args)
throws Throwable;
b. Proxy:动态代理类。作用类似于前面说的静态代理模式中的 ProxySubject 类。
/*
* 构造方法,用于给内部的 h 赋值
*/
protected Proxy(InvocationHandler h) {
Objects.requireNonNull(h);
this.h = h;
}
/*
* 获得一个代理类。其中 loader 是类加载器,interfaces 是真实类所拥有的全部接口的数组
*/
public static Class<?> getProxyClass(ClassLoader loader, Class<?>... interfaces){
...
}
/*
* 返回代理类的一个实例。返回后的代理类可以当作真实类使用(可使用真实类在 Subject 接口中声明过的方法)
* 注意,第二个参数 Interfaces 是真实对象中实现的接口 Class 对象数组
*/
public static Object newProxyInstance(ClassLoader loader, Class<?>[] interfaces, InvocationHandler h) {
...
}
2. 所谓的 Dynamic Proxy 是这样一种 class: 它是在运行时生成的类,在生成它时你必须提供一组 Interface 给它,然后该类就宣称它实现了这些 Interface。你当然可以把该类的实例当作这些 Interface 中的任何一个来使用(多态)。当然,这个 Dynamic Proxy 其实就是一个 Proxy,它不会替你做实质性的工作,在生成它的实例时你必须提供一个 Handler(也就是 invocationHandler 实例对象),由它来接管实际的工作。
3. 在使用动态代理类时,我们必须实现 InvocationHandler 接口。
eg:
// 抽象角色
public interface Subject {
void request();
}
// 真实角色
public class RealSubject implements Subject {
@Override
public void request() {
System.out.println("From real subject!");
}
}
/**
* 该代理类的内部属性是 Object 类型,实际使用的时候通过该类的构造方法传递进来一个对象。此外,该类还实现了
* InvocationHandler 接口中的 invoke() 方法,该方法中的 method.invoke() 其实就是调用被代理对象要执行的方法,
* 方法参数是 sub,表示该方法从属于 sub 对象,通过动态代理类,我们可以在执行真实对象的方法前后加入自己的一
* 些额外方法。这样我们就可以通过这一个代理类代理任何一个真实角色对象。
*/
public class DynamicSubject implements InvocationHandler {
// 这个类可以代理任何一个真实类
private Object sub;
public DynamicSubject(Object obj){
this.sub = obj;
}
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
System.out.println("before calling: " + method);
// 通过反射来完成真实对象中的方法调用(这里就是调用 sub 对象中(也就是真实角色对象)中的相应方法),后面 args 是这个方法需要的参数数组
method.invoke(sub, args);
System.out.println("after calling: " + method);
return null;
}
}
// 客户端
public static void main(String[] args) {
// 创建一个真实角色对象
RealSubject realSubject = new RealSubject();
// 创建一个 InvocationHandler 接口,最后 subject.request() 方法实现实际就是调用这个对象的 invoke() 方法。
InvocationHandler handler = new DynamicSubject(realSubject);
// 创建 Class 对象
Class<?> classType = handler.getClass();
// 创建代理类对象,然后通过代理类对象调用真实角色对象的方法。
// realSubject.getClass().getInterfaces() 就是 RealSubject 类实现的 Subject 接口的 Class 对象
Subject subject = (Subject) Proxy.newProxyInstance(classType.getClassLoader(), realSubject.getClass().getInterfaces(), handler);
// 这个 request() 方法就是上面第二个参数 realSubject.getClass().getInterfaces() 接口中的方法。
subject.request();
}
// output
before calling: public abstract void com.cfm.dynamicproxy.Subject.request()
From real subject!
after calling: public abstract void com.cfm.dynamicproxy.Subject.request()
通过这种方式,被代理的对象(RealSubject)可以在运行时动态改变,需要控制的接口(Subject接口)可以在运行时改变,控制的方式(DynamicSubject类)也可以动态改变,从而实现了非常灵活的动态代理关系。
总结:
1. 动态代理是指客户通过代理类来调用其它对象的方法。它使用的场合:调试、远程方法调用(RMI)等等。
2. 动态代理创建步骤:
a. 创建一个实现接口 InvocationHandler 的类并实现它里面的 invoke() 方法。
b. 创建被代理的类以及接口(也就是真实角色和抽象角色)。
c. 通过 Proxy 的静态方法(如下所示),创建一个代理类。
newProxyInstance(ClassLoader loader, Class[] interfaces, InvocationHandler h)
d. 通过 c 创建的代理实例调用相应的被代理方法。