代理模式和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  }

 

待续...
 

转载于:https://www.cnblogs.com/mattmonkey/archive/2011/07/26/2301570.html