首页 > 代码库 > 深入解析Java设计模式之动态代理

深入解析Java设计模式之动态代理

深入解析Java设计模式之动态代理

代理是基本的设计模式之一,它是你为了提供额外的或不同的操作,而插入的用来代替”实际“对象的对象。这些操作通常涉及与”实际“对象的通信,因此代理通常充当着中间人的角色,下面是一个用来展示动态代理结构的简单示例:

/**
	普通(非动态)代理示例:
*/

interface Interface {
  void doSomething();
  void somethingElse(String arg);
}

class RealObject implements Interface {
  public void doSomething() { print("doSomething"); }
  public void somethingElse(String arg) {
    print("somethingElse " + arg);
  }
}	

class SimpleProxy implements Interface {
  private Interface proxied;
  public SimpleProxy(Interface proxied) {
    this.proxied = proxied;
  }
  public void doSomething() {
  	//自定义执行逻辑部分
    print("SimpleProxy doSomething");
    //调用“被代理”对象的方法
    proxied.doSomething();
  }
  public void somethingElse(String arg) {
  	//自定义执行逻辑部分
    print("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
*///:~
因为cousumer()接受的Interface,所以他无法知道正在获得的到底是RealObject还是SimpleProxy,因为这二者都实现了Interface.但是SimpleProxy已经插入到了客户端和RealObject之间,因此他会执行操作,然后调用RealObject上相同的方法。

在任何时刻,只要你想要将额外的操作”实际“对象中分离到不同的地方,特别是当你希望能够很容易地做出修改,从没有使用额外操作转为使用这些操作或者反过来时,代理就显得很有用(设计模式的关键就是封装修改——因此你需要修改事物以证明这种模式的正确性)。列如,如果你希望跟踪RealObject中的方法的调用,或者希望度量这些调用的开销,那么你应该怎么做呢?这些代码肯定是你不希望将其合并到应用中的代码,因此代理使得你可以很容易地移除或移除它们。

Java的动态代理的思想向前更迈进了一步,因为它可以动态地创建代理并动态地处理对所代理方法的调用。在动态代理商所做的所有调用都会被重定向到单一的调用处理器上,它的工作是揭示调用额类型并确定相应的对策。下面是用动态代理重写的SimpleProxyDemo.java:

/**
	动态代理示例:
	*/
import java.lang.reflect.*;

class DynamicProxyHandler implements InvocationHandler {
  private Object proxied;
  public DynamicProxyHandler(Object proxied) {
    this.proxied = proxied;
  }
  public Objectinvoke(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);
  }
}	

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: (95% match)	
doSomething
somethingElse bonobo
**** 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: [Ljava.lang.Object;@42e816
  bonobo
somethingElse bonobo
*///:~

通过调用静态方法Proxy.newProxyInstance()可以创建动态代理,这个方法需要的到一个类加载器(你通常可以才从已经被加载额对象中获得其类加载器,然后传递它),一个你希望该代理实现的接口列表(不是类或抽象类),以及Invocationhandler接口的一个实现。动态代理可以将所有的调用重定向到调用处理器,因此通常会向调用处理器的构造器传递一个”实际“对象的引用,从而使得调用处理器在执行其中任务时,可以将请求转发。

invoke()方法中传递进来了代理对象,以防你需要区分请求的来源,但是在许多情况下,你并不关心这一点。然而,在invoke()内部,在代理上调用方法时需要格外当心,因为对接口的调用被重定向为对代理的调用

通常,你会执行被代理的操作,然而使用Method.invoke()将请求转发给被代理对象,并传入必须的参数。这初看起来可能有些受限,就像你只能执行泛化操作一样。但是,你可以通过传递其他的参数,来过滤某些方法调用:

动态代理和普通代理(非动态代理)一个最主要的区别就是代理类代码不需要你手动实现了,比如第一个示例中的"SimpleProxy"类就不需要手动实现。

     动态代理原理(序号表明了执行顺序):

   (1).通过Proxy类的newProxyInstance()方法动态地生成代理类——>

   (2).接口调用的重定向(对接口的调用将被重定向为对代理的调用)——>

   (3).在"invoke"方法中在method.invoke(....)之前或之后插入自定义逻辑代码——>

   (4).通过反射技术执行被代理的方法。


/**
	动态代理(执行指定方法)示例
*/
import java.lang.reflect.*;
import static net.mindview.util.Print.*;

class MethodSelector implements InvocationHandler {
  private Object proxied;
  public MethodSelector(Object proxied) {
    this.proxied = proxied;
  }
  public Object
  invoke(Object proxy, Method method, Object[] args)
  throws Throwable {
  	//此处过滤掉了不包含有关键字“interesting”的方法
    if(method.getName().equals("interesting"))
      print("Proxy detected the interesting method");
    return method.invoke(proxied, args);
  }
}	

interface SomeMethods {
  void boring1();
  void boring2();
  void interesting(String arg);
  void boring3();
}

class Implementation implements SomeMethods {
  public void boring1() { print("boring1"); }
  public void boring2() { print("boring2"); }
  public void interesting(String arg) {
    print("interesting " + arg);
  }
  public void boring3() { print("boring3"); }
}	

class SelectingMethods {
  public static void main(String[] args) {
    SomeMethods proxy= (SomeMethods)Proxy.newProxyInstance(
      SomeMethods.class.getClassLoader(),
      new Class[]{ SomeMethods.class },
      new MethodSelector(new Implementation()));
    proxy.boring1();
    proxy.boring2();
    proxy.interesting("bonobo");
    proxy.boring3();
  }
} /* Output:
boring1
boring2
Proxy detected the interesting method
interesting bonobo
boring3
*///:~