背景
代理模式中,代理类与主体类实现同样的接口,代理类持有实体类的引用,并接受客户端对代理类中实体引用部分的外部注入,并代理实体类的功能。
按照代理类的产生方式,如果运行期之前就静态的存在那就是静态代理,如果是运行时产生的就是动态代理。
代理模式的类图如下
图1: 动态代理类图
静态代理
一个代码示例
// 1. 定义接口
interface Subject {
String action();
}
// 2. 定义主体类
public class RealSubject implements Subject {
@Override
public String action() {
System.out.println("action in RealSubject");
return "action done";
}
}
// 3. 定义静态代理类 它持有一个主体类的引用
public class ProxySubject implements Subject {
private RealSubject realSubject;
public ProxySubject(Subject realSubject) {
this.realSubject = realSubject;
}
@Override
public String action() {
System.out.println("do sth before RealSubject action");
String result = realSubject.action();
System.out.println("do sth after RealSubject action");
// 返回值仍要主体的返回值
return result;
}
}
// 4. 在客户端注入实体并使用
public class Client {
public static void main(String[] args) {
Subject realSubject = new RealSubject();
ProxySubject proxySubject = new ProxySubject(realSubject);
proxySubject.action();
}
}
// 5. 运行后输出结果
do sth before RealSubject action
action in RealSubject
do sth after RealSubject action
动态代理
动态代理也遵循上面的类图,和静态代理相比,有以下几点不同之处
- 代理类ProxySubject是在运行时动态生成的,而编译期是不存在的
- 代理类与主体类的代理关系是动态注入的(ProxySubject持有RealSubject的引用)
- 代理类对主体类的方法调用也是动态的
代理类的动态生成,代理类与主体类的关系建立以及对主体类的代理调用,都用到了两个关键类,即Proxy和InvocationHandler
Proxy类提供了动态生成代理类的方法并持有InvocationHandler接口的引用,所有生成的代理类都是Proxy的子类.
public static Object newProxyInstance(ClassLoader loader, Class<?>[] interfaces,
InvocationHandler h) throws IllegalArgumentException
InvocationHandler接口包含一个invoke方法,让实现InvocationHandler接口的类去具体实现,在实现中通过持有被代理类实体(RealSubject),并通过反射,去调用对应的实体方法。