• JDK 动态代理 规格严格


    JAVA动态代理内部实现

    一 代理设计模式

    代理模式为目标对象提供一种代理以控制对实际对象的访问。在某些情况下,一个客户不想或者不能直接引用另一个对象,而代理对象可以在客户端和目标对象之间起到中介的作用。

    为了保持行为的一致性,代理类和实际委托类通常会实现相同的接口,所以在访问者看来两者没有丝毫的区别。

     代理模式类图  

    常见的代理有:
    1) 远程代理(Remote proxy):对一个位于不同的地址空间对象提供一个局域代表对象,如RMI中的stub。 
    2) 虚拟代理(Virtual proxy):根据需要将一个资源消耗很大或者比较复杂的对象,延迟加载,在真正需要的时候才创建。
    3) 保护代理(Protect or Access Proxy):控制对一个对象的访问权限。
    4) 智能引用(Smart Reference Proxy):提供比目标对象额外的服务和功能。

    通过代理类这一中间层,能够有效控制对实际委托类对象的直接访问,也可以很好地隐藏和保护实际对,实施不同的控制策略,从而在设计上获得了更大的灵活性。

    二 动态代理使用

    JAVA动态代理机制以巧妙的方式实现了代理模式的设计理念。

    动态代理类图


    动态代理在代理ProxySubject和RealSubject之间增加了InvocationHandler,这是一种通信间接化, 增加了灵 性性,例如可以把这个中间层实现为一个框架Framework,直接通过xml文件等方式来调用RealSubject。

    在普通的设计中,我们一般不会使用动态代理。但是在一些框架结构设计中,动态代理非常重要,如RMI,EJB中都使用动态代理。

    1. interface Subject  
    2. {  
    3.   public void doSomething();  
    4. }  
    5. class RealSubject implements Subject  
    6. {  
    7.   public void doSomething()  
    8.   {  
    9.     System.out.println( "call doSomething()" );  
    10.   }  
    11. }  
    12. class ProxyHandler implements InvocationHandler  
    13. {  
    14.   private Object proxied;  
    15.     
    16.   public ProxyHandler( Object proxied )  
    17.   {  
    18.     this.proxied = proxied;  
    19.   }  
    20.     
    21.   public Object invoke( Object proxy, Method method, Object[] args ) throws Throwable  
    22.   {  
    23.     return method.invoke( proxied, args);  
    24.   }   
    25. }  

    1. import java.lang.reflect.InvocationHandler;  
    2. import java.lang.reflect.Method;  
    3. import java.lang.reflect.Proxy;  
    4. import sun.misc.ProxyGenerator;  
    5. import java.io.*;  
    6. public class DynamicProxy  
    7. {  
    8.   public static void main( String args[] )  
    9.   {  
    10.     RealSubject real = new RealSubject();  
    11.     Subject proxySubject = ( Subject )     
    12.            Proxy.newProxyInstance(   
    13.            Subject.class.getClassLoader(),   
    14.                  new Class[] { Subject.class },   
    15.                    new ProxyHandler( real ) );  
    16.       
    17.     proxySubject.doSomething();  
    18.   //write proxySubject class binary data to file  
    19.     createProxyClassFile();  
    20.   }  
    21.     
    22.   public static void createProxyClassFile()  
    23.   {  
    24.     String name = "ProxySubject";  
    25.     byte[] data = ProxyGenerator.generateProxyClass( name, new Class[] { Subject.class } );  
    26.     try  
    27.     {  
    28.       FileOutputStream out = new FileOutputStream( name + ".class" );  
    29.       out.write( data );  
    30.       out.close();  
    31.     }  
    32.     catch( Exception e )  
    33.     {  
    34.       e.printStackTrace();  
    35.     }  
    36.   }  
    37. }  

    三 动态代理内部实现

    类Proxy的getProxyClass方法调用ProxyGenerator的 generateProxyClass方法产生ProxySubject.class的二进制数据:


    public static byte[] generateProxyClass(final String name, Class[] interfaces)

    我们可以import sun.misc.ProxyGenerator,调用 generateProxyClass方法产生binary data,然后写入文件,最后通过反编译工具来查看内部实现原理。

    反编译后的ProxySubject.java:

    1. import java.lang.reflect.*;  
    2. public final class ProxySubject extends Proxy  
    3.     implements Subject  
    4. {  
    5.     private static Method m1;  
    6.     private static Method m0;  
    7.     private static Method m3;  
    8.     private static Method m2;  
    9.     public ProxySubject(InvocationHandler invocationhandler)  
    10.     {  
    11.         super(invocationhandler);  
    12.     }  
    13.     public final boolean equals(Object obj)  
    14.     {  
    15.         try  
    16.         {  
    17.             return ((Boolean)super.h.invoke(this, m1, new Object[] {  
    18.                 obj  
    19.             })).booleanValue();  
    20.         }  
    21.         catch(Error _ex) { }  
    22.         catch(Throwable throwable)  
    23.         {  
    24.             throw new UndeclaredThrowableException(throwable);  
    25.         }  
    26.     }  
    27.     public final int hashCode()  
    28.     {  
    29.         try  
    30.         {  
    31.             return ((Integer)super.h.invoke(this, m0, null)).intValue();  
    32.         }  
    33.         catch(Error _ex) { }  
    34.         catch(Throwable throwable)  
    35.         {  
    36.             throw new UndeclaredThrowableException(throwable);  
    37.         }  
    38.     }  
    39.     public final void doSomething()  
    40.     {  
    41.         try  
    42.         {  
    43.             super.h.invoke(this, m3, null);  
    44.             return;  
    45.         }  
    46.         catch(Error _ex) { }  
    47.         catch(Throwable throwable)  
    48.         {  
    49.             throw new UndeclaredThrowableException(throwable);  
    50.         }  
    51.     }  
    52.     public final String toString()  
    53.     {  
    54.         try  
    55.         {  
    56.             return (String)super.h.invoke(this, m2, null);  
    57.         }  
    58.         catch(Error _ex) { }  
    59.         catch(Throwable throwable)  
    60.         {  
    61.             throw new UndeclaredThrowableException(throwable);  
    62.         }  
    63.     }  
    64.     static   
    65.     {  
    66.         try  
    67.         {  
    68.             m1 = Class.forName("java.lang.Object").getMethod("equals", new Class[] {  
    69.                 Class.forName("java.lang.Object")  
    70.             });  
    71.             m0 = Class.forName("java.lang.Object").getMethod("hashCode", new Class[0]);  
    72.             m3 = Class.forName("Subject").getMethod("doSomething", new Class[0]);  
    73.             m2 = Class.forName("java.lang.Object").getMethod("toString", new Class[0]);  
    74.         }  
    75.         catch(NoSuchMethodException nosuchmethodexception)  
    76.         {  
    77.             throw new NoSuchMethodError(nosuchmethodexception.getMessage());  
    78.         }  
    79.         catch(ClassNotFoundException classnotfoundexception)  
    80.         {  
    81.             throw new NoClassDefFoundError(classnotfoundexception.getMessage());  
    82.         }  
    83.     }  
    84. }  

    通过 ProxySubject.java,我们可以看到动态代理的内部是如何实现的,并且我们可以实现自己的一个动态代理生成器。

    ProxyGenerator内部是如何生成class二进制数据,可以参考源代码。

    1. private byte[] generateClassFile() {  
    2.   /* 
    3.    * Record that proxy methods are needed for the hashCode, equals, 
    4.    * and toString methods of java.lang.Object.  This is done before 
    5.    * the methods from the proxy interfaces so that the methods from 
    6.    * java.lang.Object take precedence over duplicate methods in the 
    7.    * proxy interfaces. 
    8.    */  
    9.   addProxyMethod(hashCodeMethod, Object.class);  
    10.   addProxyMethod(equalsMethod, Object.class);  
    11.   addProxyMethod(toStringMethod, Object.class);  
    12.   /* 
    13.    * Now record all of the methods from the proxy interfaces, giving 
    14.    * earlier interfaces precedence over later ones with duplicate 
    15.    * methods. 
    16.    */  
    17.   for (int i = 0; i < interfaces.length; i++) {  
    18.       Method[] methods = interfaces[i].getMethods();  
    19.       for (int j = 0; j < methods.length; j++) {  
    20.     addProxyMethod(methods[j], interfaces[i]);  
    21.       }  
    22.   }  
    23.   /* 
    24.    * For each set of proxy methods with the same signature, 
    25.    * verify that the methods' return types are compatible. 
    26.    */  
    27.   for (List<ProxyMethod> sigmethods : proxyMethods.values()) {  
    28.       checkReturnTypes(sigmethods);  
    29.   }  
    30.   /* ============================================================ 
    31.    * Step 2: Assemble FieldInfo and MethodInfo structs for all of 
    32.    * fields and methods in the class we are generating. 
    33.    */  
    34.   try {  
    35.       methods.add(generateConstructor());  
    36.       for (List<ProxyMethod> sigmethods : proxyMethods.values()) {  
    37.     for (ProxyMethod pm : sigmethods) {  
    38.         // add static field for method's Method object  
    39.         fields.add(new FieldInfo(pm.methodFieldName,  
    40.       "Ljava/lang/reflect/Method;",  
    41.        ACC_PRIVATE | ACC_STATIC));  
    42.         // generate code for proxy method and add it  
    43.         methods.add(pm.generateMethod());  
    44.     }  
    45.       }  
    46.       methods.add(generateStaticInitializer());  
    47.   } catch (IOException e) {  
    48.       throw new InternalError("unexpected I/O Exception");  
    49.   }  
    50.   /* ============================================================ 
    51.    * Step 3: Write the final class file. 
    52.    */  
    53.   /* 
    54.    * Make sure that constant pool indexes are reserved for the 
    55.    * following items before starting to write the final class file. 
    56.    */  
    57.   cp.getClass(dotToSlash(className));  
    58.   cp.getClass(superclassName);  
    59.   for (int i = 0; i < interfaces.length; i++) {  
    60.       cp.getClass(dotToSlash(interfaces[i].getName()));  
    61.   }  
    62.   /* 
    63.    * Disallow new constant pool additions beyond this point, since 
    64.    * we are about to write the final constant pool table. 
    65.    */  
    66.   cp.setReadOnly();  
    67.   ByteArrayOutputStream bout = new ByteArrayOutputStream();  
    68.   DataOutputStream dout = new DataOutputStream(bout);  
    69.   try {  
    70.       /* 
    71.        * Write all the items of the "ClassFile" structure. 
    72.        * See JVMS section 4.1. 
    73.        */  
    74.           // u4 magic;  
    75.       dout.writeInt(0xCAFEBABE);  
    76.           // u2 minor_version;  
    77.       dout.writeShort(CLASSFILE_MINOR_VERSION);  
    78.           // u2 major_version;  
    79.       dout.writeShort(CLASSFILE_MAJOR_VERSION);  
    80.       cp.write(dout);   // (write constant pool)  
    81.           // u2 access_flags;  
    82.       dout.writeShort(ACC_PUBLIC | ACC_FINAL | ACC_SUPER);  
    83.           // u2 this_class;  
    84.       dout.writeShort(cp.getClass(dotToSlash(className)));  
    85.           // u2 super_class;  
    86.       dout.writeShort(cp.getClass(superclassName));  
    87.           // u2 interfaces_count;  
    88.       dout.writeShort(interfaces.length);  
    89.           // u2 interfaces[interfaces_count];  
    90.       for (int i = 0; i < interfaces.length; i++) {  
    91.     dout.writeShort(cp.getClass(  
    92.         dotToSlash(interfaces[i].getName())));  
    93.       }  
    94.           // u2 fields_count;  
    95.       dout.writeShort(fields.size());  
    96.           // field_info fields[fields_count];  
    97.       for (FieldInfo f : fields) {  
    98.     f.write(dout);  
    99.       }  
    100.           // u2 methods_count;  
    101.       dout.writeShort(methods.size());  
    102.           // method_info methods[methods_count];  
    103.       for (MethodInfo m : methods) {  
    104.     m.write(dout);  
    105.       }  
    106.              // u2 attributes_count;  
    107.       dout.writeShort(0); // (no ClassFile attributes for proxy classes)  
    108.   } catch (IOException e) {  
    109.       throw new InternalError("unexpected I/O Exception");  
    110.   }  
    111.   return bout.toByteArray();  
    112.      
    http://blog.csdn.net/column/details/kernel.html#
    http://blog.csdn.net/lycb_gz/article/details/6975720
    http://blog.csdn.net/morewindows/article/details/6976468


    转载的文章。。。。。

  • 相关阅读:
    OpenGL---------BMP文件格式
    OpenGL———混合的基本知识
    OpenGL------显示列表
    OpenGL---------光照的基本知识
    OpenGL学习--------动画制作
    OpenGL------三维变换
    OpenGL学习--------颜色的选择
    OpenGL学习-------点、直线、多边形
    Windows X64汇编入门(1)
    x86 x64下调用约定浅析
  • 原文地址:https://www.cnblogs.com/diyunpeng/p/2255420.html
Copyright © 2020-2023  润新知