这周看RPC相关的代码时,里面用到了动态代理的相关知识,以前没怎么接触过,因此学习了下。
一、代理
代理是一种基本的设计模式,它是为了提供额外或者不同的操作,而插入的用来代替“实际”对象的对象。这些操作通常涉及与实际对象的通信,
因此代理通常充当着中间人的角色,下面我们来看一个展示代理结构的简单例子:
public interface Interface {
void doSomething();
void somethingElse(String arg);
}
public class RealObject implements Interface{
@Override
public void doSomething() {
System.out.println("doSomething");
}
@Override
public void somethingElse(String arg) {
System.out.println("somethingElse:"+arg);
}
}
public class SimpleProxy implements Interface {
private Interface proxied;
public SimpleProxy(Interface proxied) {
this.proxied = proxied;
}
@Override
public void doSomething() {
System.out.println("SimpleProxy doSomething");
proxied.doSomething();
}
@Override
public void somethingElse(String arg) {
System.out.println("SimpleProxy somethingElse:"+arg);
}
}
public class SimpleProxyDemo {
public static void consumer(Interface iface){
iface.doSomething();
iface.somethingElse("hello");
}
public static void main(String[] args){
consumer(new RealObject());
consumer(new SimpleProxy(new RealObject()));
}
}
运行结果如下:
doSomething
somethingElse:hello
SimpleProxy doSomething
doSomething
SimpleProxy somethingElse:hello
因为consumer()接受Interface,所以它无法知道真正获得的道理是RealObject还是SimpleProxy,因为这二者都实现了Interface。但是
SimpleProxy已经被插入到客户端和RealObject之间,因此他会执行操作,然后调用RealObject上相同的方法。
在任何时刻,只要你想要将额外的操作从“实际”对象中分离到不同的地方,特别是当你希望能够很容易的做出修改,从没有使用额外操作转为使用这些操作
,或者反过来,代理就显得有用了。例如,如果你希望跟踪RealObject中方法的调用,或者希望度量这些调用的开销,那么你应该怎么做呢?这些代码你肯定
不希望将其合并到应用中的代码,因此代理可以使你很容易的添加和移除他们。
二、Java动态代理
java的动态代理比代理的思想更向前迈进了一步,它可以动态的创建代理并动态的处理对所代理方法的调研。在动态代理上所做的所有调用都会被重定向到
单一的调用处理器上,它的工作是揭示调用的类型并确定相应的对策。下面是用Java动态代理重写的SimpleProxy:
public class DynamicProxyHandler implements InvocationHandler{
private Object proxied;
public DynamicProxyHandler(Object proxied) {
this.proxied = proxied;
}
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
System.out.println("----proxy: " + proxy.getClass()+
".method:" + method + ".args:" + args);
if (args != null){
for (Object arg:args){
System.out.println(" " + arg);
}
}
return method.invoke(proxied,args);
}
}
public class SimpleDynamicProxy {
public static void consumer(Interface iface){
iface.doSomething();
iface.somethingElse("hello");
}
public static void main(String[] args){
RealObject real = new RealObject();
consumer(real);
Interface proxy = (Interface) Proxy.newProxyInstance(
Interface.class.getClassLoader(),
new Class[]{Interface.class},
new DynamicProxyHandler(real)
);
consumer(proxy);
}
}
运行结果如下:
doSomething
somethingElse:hello
----proxy: class com.sun.proxy.$Proxy0.method:public abstract void com.ProxyDesign.proxy.Interface.doSomething().args:null
doSomething
----proxy: class com.sun.proxy.$Proxy0.method:public abstract void com.ProxyDesign.proxy.Interface.somethingElse(java.lang.String).args:[Ljava.lang.Object;@610455d6
hello
somethingElse:hello
在该示例中,通过静态方法Proxy.newProxyInstance可以创建动态代理,这个方法的三个参数分别为:
ClassLoader loader: 类加载器,你可以听过已经被夹在的对象获取其类加载器,然后传递给它。
Class<?>[] interfaces:该代理实现的接口列表。
InvocationHandler h:InvocationHandler接口的一个实现。
动态代理可以将所有调用重定向到调用处理器,因此通常会向调用处理器的构造函数传递一个“实际”对象的引用,从而使得调用处理器在执行其中介任务时,可以将请求转发。
而上述的invoke()方法中传递进来了代理的对象,以防你需要区分请求的来源,但是在许多情况下,你并不关心这一点。