Java动态代理

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

  接口:

/**
 * 接口
 * @author Arts&Crafts
 *
 */
public interface Interface {
    void doSomething();
    void somethingElse(String arg);
}

  实际类:

 1 /**
 2  * 实际类
 3  * @author Arts&Crafts
 4  *
 5  */
 6 public class RealObject implements Interface {
 7 
 8     @Override
 9     public void doSomething() {
10         System.out.println("RealObject.doSomething()");
11     }
12 
13     @Override
14     public void somethingElse(String arg) {
15         System.out.println("RealObject.somethingElse() " + arg);
16     }
17 
18 }

  代理类:

 1 /**
 2  * 代理类
 3  * 
 4  * @author Arts&Crafts
 5  * 
 6  */
 7 public class SimpleProxy implements Interface {
 8     private Interface proxied;
 9 
10     public SimpleProxy(Interface proxy) {
11         this.proxied = proxy;
12     }
13 
14     @Override
15     public void doSomething() {
16         System.out.println("SimpleProxy.doSomething()");
17         proxied.doSomething();
18     }
19 
20     @Override
21     public void somethingElse(String arg) {
22         System.out.println("SimpleProxy.somethingElse() " + arg);
23         proxied.doSomething();
24     }
25 
26 }

  测试:

 1 public class SimpleProxyDemo {
 2 public static void consumer(Interface iface){
 3     iface.doSomething();
 4     iface.somethingElse("Hello World");
 5 }
 6     
 7     /**
 8      * @param args
 9      */
10     public static void main(String[] args) {
11         consumer(new RealObject());
12         System.out.println();
13         consumer(new SimpleProxy(new RealObject()));
14     }
15 
16 }

  因为consumer()接受的Interface,所以它无法知道正在获取的到底是RealObject还是SimpleProxy,因为这二者都实现了Interface。但是SimpleProxy已经被插入到客户端和RealObkect之间,因此它会执行操作,然后调用RealObject上相同的方法。

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

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

  动态代理调用处理器类:

 1 import java.lang.reflect.InvocationHandler;
 2 import java.lang.reflect.Method;
 3 
 4 public class DynamicProxyHandler implements InvocationHandler {
 5     private Object proxied;
 6 
 7     public DynamicProxyHandler(Object proxied) {
 8         this.proxied = proxied;
 9     }
10 
11     @Override
12     public Object invoke(Object proxy, Method method, Object[] args)
13             throws Throwable {
14         System.out.println("*** proxy:" + proxy.getClass() + ". method: "
15                 + method + ". args:" + args);
16         if (args != null)
17             for (Object arg : args)
18                 System.out.println("  " + arg);
19         Object result = method.invoke(proxied, args);
20         return result;
21     }
22 
23 }

     测试类:

 1 import java.lang.reflect.Proxy;
 2 
 3 import org.jdk.staticproxy.Interface;
 4 import org.jdk.staticproxy.RealObject;
 5 
 6 public class SimpleDynamicProxyDemo {
 7     public static void consumer(Interface iface) {
 8         iface.doSomething();
 9         iface.somethingElse("Hello World");
10     }
11 
12     public static void main(String[] args) {
13         RealObject real = new RealObject();
14         consumer(real);
15         System.out.println();
16         Interface proxy = (Interface) Proxy.newProxyInstance(
17                 Interface.class.getClassLoader(),
18                 new Class[] { Interface.class }, new DynamicProxyHandler(real));
19         consumer(proxy);
20     }
21 }

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

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

  

    

 

 

 

 

 

 

 

 

 

 

posted on 2013-09-16 20:51  Arts&Crafts  阅读(251)  评论(0编辑  收藏  举报

导航