代理 是常用的基本设计模式之一,在某些情况下,一个客户不想或者不能直接引用一个对 象,此时可以通过一个称之为“代理”的第三者来实现 间接引用。代理对象可以在客户端和目标对象之间起到 中介的作用,并且可以通过代理对象去掉客户不能看到 的内容和服务或者添加客户需要的额外服务。
通过引入一个新的对象(如小图片和远程代理 对象)来实现对真实对象的操作或者将新的对象作为真 实对象的一个替身,这种实现机制即为 代理模式。
简单代理
**具体实现:**给某一个对象提供一个代 理,并由代理对象控制对原对象的引用。
下面来看一个代理结构的简单示例:
import java.io.Serializable;
interface Interface {
void doSomething();
void somethingElse(String arg);
}
//被代理类
class RealObject implements Interface, Serializable {
public void doSomething() { System.out.println("doSomething"); }
public void somethingElse(String arg) {
System.out.println("somethingElse " + arg);
}
}
//代理类
class SimpleProxy implements Interface {
private Interface proxied;
public SimpleProxy(Interface proxied) {
this.proxied = proxied;
}
public void doSomething() {
System.out.println("SimpleProxy doSomething");
proxied.doSomething();
}
public void somethingElse(String arg) {
System.out.println("SimpleProxy somethingElse " + arg);
proxied.somethingElse(arg);
}
}
class SimpleProxyDemo {
public static void consumer(Interface iface) {
iface.doSomething();
iface.somethingElse("bonobo");
}
public static void main(String[] args) {
consumer(new RealObject());
consumer(new SimpleProxy(new RealObject()));
}
}
Output:
doSomething
somethingElse bonobo
SimpleProxy doSomething
doSomething
SimpleProxy somethingElse bonobo
somethingElse bonobo
因为consumer()
接受的是Interface,所以它无法知道正在获得的到底是RealObject
还是SimpleProxy
,因为这两者都实现了Interface
。但是SimpleProxy
已经被插入到了客户端和RealObject
之间,因此它会执行操作,然后调用RealObject
上相同的方法。
在任何时刻,只要你想要将额外的操作从"实际"对象中分离到不同的地方,特别是当你希望能够很容易的做出修改,从没有使用额外操作转为使用这些操作时,代理就会显得非常有用。例如,如果你希望跟踪对RealObject
中的方法的调用,或者希望度量这些调用的开销,那么你应该怎么做呢?这时,使用代理就可以很容易地添加或移除它们。
动态代理
Java 的 动态代理 比代理的思想更向前迈进的一步,因为它可以动态的创建代理并动态的处理对所代理方法的调用。下面是从修改后的SimpleProxyDemo.java
:
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
interface Interface {
void doSomething();
void somethingElse(String arg);
}
class RealObject implements Interface {
public void doSomething() { System.out.println("doSomething"); }
public void somethingElse(String arg) {
System.out.println("somethingElse " + arg);
}
}
class DynamicProxyHandler implements InvocationHandler {
private Object proxied;
public DynamicProxyHandler(Object proxied) {
this.proxied = proxied;
}
public Object invoke(Object proxy, Method method, Object[] args)
throws Throwable {
System.out.print("**** proxy: " + proxy.getClass() + ", method: "
+ method + ", args: " );
if (args != null)
for (Object arg : args)
System.out.print(" " + arg);
else
System.out.print("null");
System.out.println();
return method.invoke(proxied, args);
}
}
class SimpleDynamicProxy {
public static void consumer(Interface iface) {
iface.doSomething();
iface.somethingElse("bonobo");
}
public static void main(String[] args) {
RealObject real = new RealObject();
// consumer(real);
// Insert a proxy and call again:
Interface proxy = (Interface) Proxy.newProxyInstance(
Interface.class.getClassLoader(),
new Class[] { Interface.class }, new DynamicProxyHandler(real));
consumer(proxy);
}
}
Output:
**** proxy: class $Proxy0, method: public abstract void Interface.doSomething(), args: null
doSomething
**** proxy: class Proxy0, method: public abstract void Interface.somethingElse(java.lang.String), args: bonobo
somethingElse bonobo
通过调用静态方法Proxy.newProxyInstance()
可以创建动态的创建代理类对象,这个方法需要得到一个类加载器(你通常可以从已经被加载的对象中获取其类加载器,然后传递给它),一个你希望实现的接口列表(不是类或抽象类),以及**InvocationHandler
接口的一个实现。
动态代理可以将所有的调用重定向到调用处理器**上,因此会向调用处理器的构造器传递一个“实际”对象的引用,从而使得调用处理器在执行其中介任务时,可以请求转发。
动态代理示意图
从上图我们可以看到,代理类Proxy
调用的所有方法都会转发到实现了InvocationHandler
接口的invoke
方法。Proxy
不管客户端的业务方法是怎么实现的。当客户端调用Proxy
时,它只会调用InvocationHandler
的invoke
接口,所以我们的真正实现的方法就必须在invoke
方法中去调用。
调用处理器中实现的invoke()
方法中传递进来了代理对象proxy
,可以通过此参数来区分请求的来源。method
既是实际要调用的被代理类的方法,args
为被调用方法所需要的参数。
动态代理之代理对象
那么proxy
到底是一个什么样的对象呢,这个类到底是长什么样子呢?好的。我们再写二个方法去把这个类打印出来看个究竟,是什么三头六臂呢?我们在main
下面写如下两个静态方法。
public static void printClassDefinition(Class clz) {
StringBuilder clzModifier = new StringBuilder();
int mod = clz.getModifiers() & Modifier.methodModifiers();
if (mod != 0) {
clzModifier.append(Modifier.toString(mod)).append(' ');
}
String superClz = clz.getSuperclass().getName();
if (superClz != null && !superClz.equals("")) {
superClz = "extends " + superClz;
}
Class[] interfaces = clz.getInterfaces();
String inters = "";
for (int i = 0; i < interfaces.length; i++) {
if (i == 0) {
inters += "implements ";
}
inters += interfaces[i].getName();
}
System.out.println(clzModifier + clz.getName() + " " + superClz + " "
+ inters);
System.out.println("{");
Field[] fields = clz.getDeclaredFields();
for (int i = 0; i < fields.length; i++) {
System.out.println("\t" + fields[i].toString() + ';');
}
System.out.println();
Constructor[] constructors = clz.getDeclaredConstructors();
for (int i = 0; i < constructors.length; i++) {
System.out.println("\t" + constructors[i].toString() + ';');
}
System.out.println();
Method[] methods = clz.getDeclaredMethods();
for (int i = 0; i < methods.length; i++) {
System.out.println("\t" + methods[i].toString() + ';');
}
System.out.println("}");
}
再改写main方法:
public static void main(String[] args) {
RealObject real = new RealObject();
// consumer(real);
// Insert a proxy and call again:
Interface proxy = (Interface) Proxy.newProxyInstance(
Interface.class.getClassLoader(),
new Class[] { Interface.class }, new DynamicProxyHandler(real));
System.out.println(proxy.getClass().getName());
//打印出proxy类的结构
printClassDefinition(proxy.getClass());
}
现在重新执行main
方法,我们再看看输出结果:
Output:
$Proxy0
public final $Proxy0 extends java.lang.reflect.Proxy implements Interface
{
private static java.lang.reflect.Method $Proxy0.m1;
private static java.lang.reflect.Method $Proxy0.m0;
private static java.lang.reflect.Method $Proxy0.m3;
private static java.lang.reflect.Method $Proxy0.m4;
private static java.lang.reflect.Method $Proxy0.m2;
public $Proxy0(java.lang.reflect.InvocationHandler);
public final boolean $Proxy0.equals(java.lang.Object);
public final java.lang.String $Proxy0.toString();
public final int $Proxy0.hashCode();
public final void $Proxy0.doSomething();
public final void $Proxy0.somethingElse(java.lang.String);
}
此时,我们就可以看到Proxy
对象的类结构,那么很明显,Proxy.newProxyInstance(Interface.class.getClassLoader(),new Class[] { Interface.class }, new DynamicProxyHandler(real))
方法会做如下几件事:
- 根据传入的第二个参数
interfaces
动态生成一个类,实现interfaces
中的接口,该例中即Interface
接口的somethingElse
和doSomething
方法。并且继承了Proxy
类,重写了hashcode
,toString
,equals
等三个方法。具体实现可参看ProxyGenerator.generateProxyClass(...)
; 该例中生成了$Proxy0
类。 - 通过传入的第一个参数classloder将刚生成的类加载到jvm中。即将
$Proxy0
类load。 - 利用第三个参数,调用
$Proxy0
的$Proxy0(InvocationHandler)
构造函数 创建$Proxy0
的对象,并且用interfaces
参数遍历其所有接口的方法,并生成Method
对象初始化对象的几个Method
成员变量 - 将
$Proxy0
的实例返回给客户端。
现在好了。我们再看客户端怎么调就清楚了。
- 客户端拿到的是
$Proxy0
的实例对象,由于$Proxy0
实现了Interface,因此转化为Interface没任何问题。
Interface proxy = (Interface) Proxy.newProxyInstance(Interface.class.getClassLoader(), new Class[] { Interface.class }, new DynamicProxyHandler(real));
proxy.doSomething()
实际上调用的是$Proxy0.doSomething()
, 那么$Proxy0.doSomething()
的实现就是通过InvocationHandler
去调用invoke
方法啦!
参考文章:
深入理解Java Proxy机制