代理模式和java动态代理的机制(一)InvocationHandler

首先回顾下Proxy模式

 

 Provide a surrogate or palceholder for another object to control access to it.

其实就是把要控制的类包上一层。接口是一致的,所以从外面看不出区别,里面却大有乾坤。

客户类:

 1 public class ProxyTest2 {
 2     public static void main(String[] args) {
 3         Subject subject = ProxyTest2.getASubject();
 4         subject.doOperationOne();
 5     }
 6 
 7     public static  Subject getASubject(){
 8         RealSubject realSubject = new RealSubject();
 9         return new Proxy(realSubject);
10     }
11 }

 
抽象主题角色

1 public interface Subject{
2     public void doOperationOne();
3 }

 

实际主题角色

1 public class RealSubject implements Subject{
2 
3     @Override
4     public void doOperationOne() {
5         System.out.println("One~~~~~~~~~~~~~~~~~~~~~~");
6         
7     }
8 }

 

 代理角色

 1 public class Proxy implements Subject {
 2     Subject target;
 3     public Proxy(Subject target){
 4         this.target = target;
 5     }
 6     
 7     @Override
 8     public void doOperationOne() {
 9         System.out.println("befer.....");
10         target.doOperationOne();
11         System.out.println("after.....");
12     }
13 }

 

动态代理

 

java提供一个机制,可以给任意接口的实例加上一个代理。叫做动态代理。

上面这个例子的抽象主题角色和 真实主题角色保留。看看动态代理是怎么做的。

新的客户端:

 1 public class ProxyTest {
 2     
 3     public static void main(String[] args) {
 4         Subject subject = ProxyTest.getASubject();
 5         subject.doOperationOne();
 6     }
 7 
 8     public static  Subject getASubject(){
 9         RealSubject realSubject = new RealSubject();
10         InvocationHandler proxyImpl = new Handler(realSubject);
11         Subject proxy = (Subject) Proxy.newProxyInstance(
12                 realSubject.getClass().getClassLoader(), 
13                 realSubject.getClass().getInterfaces(),
14                 proxyImpl  );    
15         return proxy;    
16     }    
17     
18 }

 

 原本代理角色的工作被移动到java.lang.reflect.InvocationHandler接口的实现里完成

 1 public class Handler implements InvocationHandler {
 2     Subject realSubject;
 3 
 4     public Handler(Subject realSubject) {
 5         this.realSubject = realSubject;
 6     }
 7 
 8     //
 9 
10     //
11     public Object invoke(Object proxy, Method method, Object[] args)
12             throws Throwable {
13         System.out.println(method.getName() + " before...");
14         method.invoke(realSubject, args);
15         System.out.println(method.getName() + " after...");
16         return null;
17     }
18 }

 

 

 研究下reflect.Proxy的源码看看是怎么和InvocationHandler配合实现动态代理的效果

 1 public static Object newProxyInstance(ClassLoader loader,
 2                       Class<?>[] interfaces,
 3                       InvocationHandler h)
 4     throws IllegalArgumentException
 5     {
 6     if (h == null) {
 7         throw new NullPointerException();
 8     }
 9 
10     /*
11      * Look up or generate the designated proxy class.
12      */
13     Class cl = getProxyClass(loader, interfaces);
14 
15     /*
16      * Invoke its constructor with the designated invocation handler.
17      */
18     try {
19         Constructor cons = cl.getConstructor(constructorParams);
20         return (Object) cons.newInstance(new Object[] { h });
21     } catch (NoSuchMethodException e) {
22         throw new InternalError(e.toString());
23     } catch (IllegalAccessException e) {
24         throw new InternalError(e.toString());
25     } catch (InstantiationException e) {
26         throw new InternalError(e.toString());
27     } catch (InvocationTargetException e) {
28         throw new InternalError(e.toString());
29     }
30     }

 

第十九行:根据接口产生一个类(代理?)。
第二十行:获取代理类的构造器。constructorParams是个final的Class数组 { InvocationHandler.class })
第二十一行:以传入的InvocationHandler实例为参数,实例化代理。返回。

 
下面看下用于生成代理类的getProxyCalss方法里核心的代码。

 1 byte[] proxyClassFile =    ProxyGenerator.generateProxyClass(
 2             proxyName, interfaces);
 3         try {
 4             proxyClass = defineClass0(loader, proxyName,
 5             proxyClassFile, 0, proxyClassFile.length);
 6         } catch (ClassFormatError e) {
 7             /*
 8              * A ClassFormatError here means that (barring bugs in the
 9              * proxy class generation code) there was some other
10              * invalid aspect of the arguments supplied to the proxy
11              * class creation (such as virtual machine limitations
12              * exceeded).
13              */
14             throw new IllegalArgumentException(e.toString());
15         }
16         }

红色标记出来的方法,无法看到源码。不过根据语义大致应该是自动产生一个class。


我们知道代理类实现的接口,知道代理类有一个InvocationHandler类型的成员。要生成这么一个代理类似乎也不太难。

 1 import java.lang.reflect.InvocationHandler;
 2 import java.lang.reflect.Method;
 3 
 4 public class Imagined implements Subject {
 5     private InvocationHandler handler;
 6     
 7     public Imagined(InvocationHandler handler){
 8         this.handler = handler;
 9     } 
10     
11     @Override
12     public void doOperationOne() {
13         try {
14             Method method = Subject.class.getDeclaredMethod("doOperationOne");
15             System.out.println(method.getName());
16             handler.invoke(this, method,null);
17         } catch (Throwable e) {
18             e.printStackTrace();
19         }
20     }
21 }

 

 新的客户端,验证下。

 1 import java.lang.reflect.InvocationHandler;
 2 
 3 public class ProxyTest3 {
 4     
 5     public static void main(String[] args) {
 6         Subject subject = ProxyTest3.getASubject();
 7         subject.doOperationOne();
 8     }
 9 
10     public static  Subject getASubject(){
11         RealSubject realSubject = new RealSubject();
12         InvocationHandler handler=  new Handler(realSubject);
13         Subject subject = new Imagined(handler);
14         return subject;    
15     }    
16     
17 }

 

待续...
 

posted @ 2011-07-26 15:51  倚楼无语F5  阅读(408)  评论(0编辑  收藏  举报