Java動態代理

來源:互聯網
上載者:User

標籤:==   實現   查看   java   version   ant   needed   stream   tostring   

代理模式為其他對象提供一種代理以控制對這個對象的訪問,中介,可去掉功能服務或增加額外的服務1. 常見代理


遠程代理: 為不同地理的對象提供區域網路代表對象

虛擬代理: 根據需要將資源消耗很大的對象進行延遲 真正需要的時候進行建立

保護代理: 許可權控制

智能引用代理: 提供額外服務

靜態代理:代理和被代理對象在代理之前是確定的。他們都實現相同的介面或者相同的抽象類別

2. 動態代理實現原理

實現功能: 通過Proxy的newProxyInstance返回代理對象

<1>聲明一段源碼

<2>編譯源碼(JDK Complier API),產生新的類(代理類)

<3>將這類load到記憶體中,產生一個新的對象(代理對象)

<4>return代理對象

<5>調用順序

根據Proxy.newInstance()傳入的參數動態產生.class -->

返回代理類 --> 然後用介面接收返回引用 --> 方法調用

3. 源碼分析

Proxy靜態方法newProxyInstance

public static Object newProxyInstance(ClassLoader loader, Class<?>[]interfaces,InvocationHandler h) throws IllegalArgumentException { // 檢查 h 不為空白,否則拋異常if (h == null) { throw new NullPointerException(); } // 獲得與指定類裝載器和一組介面相關的代理類類型對象Class cl = getProxyClass(loader, interfaces); // 通過反射擷取建構函式對象並組建代理程式類執行個體try { Constructor cons = cl.getConstructor(constructorParams); return (Object) cons.newInstance(new Object[] { h }); } catch (NoSuchMethodException e) { throw new InternalError(e.toString()); } catch (IllegalAccessException e) { throw new InternalError(e.toString()); } catch (InstantiationException e) { throw new InternalError(e.toString()); } catch (InvocationTargetException e) { throw new InternalError(e.toString()); } }

類Proxy的getProxyClass方法調用ProxyGenerator的 generateProxyClass方法產生ProxySubject.class的位元據:

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

我們可以import sun.misc.ProxyGenerator,調用 generateProxyClass方法產生binary data,然後寫入檔案,最後通過反編譯工具來查看內部實現原理。 反編譯後的ProxySubject.java Proxy靜態方法newProxyInstance

import java.lang.reflect.*;   public final class ProxySubject extends Proxy   implements Subject   {   private static Method m1;   private static Method m0;   private static Method m3;   private static Method m2;   public ProxySubject(InvocationHandler invocationhandler)   {   super(invocationhandler);   }   public final boolean equals(Object obj)   {   try  {   return ((Boolean)super.h.invoke(this, m1, new Object[] {   obj   })).booleanValue();   }   catch(Error _ex) { }   catch(Throwable throwable)   {   throw new UndeclaredThrowableException(throwable);   }   }   public final int hashCode()   {   try  {   return ((Integer)super.h.invoke(this, m0, null)).intValue();   }   catch(Error _ex) { }   catch(Throwable throwable)   {   throw new UndeclaredThrowableException(throwable);   }   }   public final void doSomething()   {   try  {   super.h.invoke(this, m3, null);   return;   }   catch(Error _ex) { }   catch(Throwable throwable)   {   throw new UndeclaredThrowableException(throwable);   }   }   public final String toString()   {   try  {   return (String)super.h.invoke(this, m2, null);   }   catch(Error _ex) { }   catch(Throwable throwable)   {   throw new UndeclaredThrowableException(throwable);   }   }   static{   try  {   m1 = Class.forName("java.lang.Object").getMethod("equals", new Class[] {   Class.forName("java.lang.Object")   });   m0 = Class.forName("java.lang.Object").getMethod("hashCode", new Class[0]);   m3 = Class.forName("Subject").getMethod("doSomething", new Class[0]);   m2 = Class.forName("java.lang.Object").getMethod("toString", new Class[0]);   }   catch(NoSuchMethodException nosuchmethodexception)   {   throw new NoSuchMethodError(nosuchmethodexception.getMessage());   }   catch(ClassNotFoundException classnotfoundexception)   {   throw new NoClassDefFoundError(classnotfoundexception.getMessage());   }   }   }

ProxyGenerator內部是如何產生class位元據,可以參考原始碼。

private byte[] generateClassFile() {     /*     * Record that proxy methods are needed for the hashCode, equals,     * and toString methods of java.lang.Object.  This is done before     * the methods from the proxy interfaces so that the methods from     * java.lang.Object take precedence over duplicate methods in the     * proxy interfaces.     */    addProxyMethod(hashCodeMethod, Object.class);     addProxyMethod(equalsMethod, Object.class);     addProxyMethod(toStringMethod, Object.class);     /*     * Now record all of the methods from the proxy interfaces, giving     * earlier interfaces precedence over later ones with duplicate     * methods.     */    for (int i = 0; i < interfaces.length; i++) {     Method[] methods = interfaces[i].getMethods();     for (int j = 0; j < methods.length; j++) {   addProxyMethod(methods[j], interfaces[i]);     }     }     /*     * For each set of proxy methods with the same signature,     * verify that the methods‘ return types are compatible.     */    for (List<ProxyMethod> sigmethods : proxyMethods.values()) {     checkReturnTypes(sigmethods);     }     /* ============================================================     * Step 2: Assemble FieldInfo and MethodInfo structs for all of     * fields and methods in the class we are generating.     */    try {     methods.add(generateConstructor());     for (List<ProxyMethod> sigmethods : proxyMethods.values()) {   for (ProxyMethod pm : sigmethods) {   // add static field for method‘s Method object   fields.add(new FieldInfo(pm.methodFieldName,     "Ljava/lang/reflect/Method;",      ACC_PRIVATE | ACC_STATIC));   // generate code for proxy method and add it   methods.add(pm.generateMethod());   }     }     methods.add(generateStaticInitializer());     } catch (IOException e) {     throw new InternalError("unexpected I/O Exception");     }     /* ============================================================     * Step 3: Write the final class file.     */    /*     * Make sure that constant pool indexes are reserved for the     * following items before starting to write the final class file.     */    cp.getClass(dotToSlash(className));     cp.getClass(superclassName);     for (int i = 0; i < interfaces.length; i++) {     cp.getClass(dotToSlash(interfaces[i].getName()));     }     /*     * Disallow new constant pool additions beyond this point, since     * we are about to write the final constant pool table.     */    cp.setReadOnly();     ByteArrayOutputStream bout = new ByteArrayOutputStream();     DataOutputStream dout = new DataOutputStream(bout);     try {     /*     * Write all the items of the "ClassFile" structure.     * See JVMS section 4.1.     */    // u4 magic;     dout.writeInt(0xCAFEBABE);     // u2 minor_version;     dout.writeShort(CLASSFILE_MINOR_VERSION);     // u2 major_version;     dout.writeShort(CLASSFILE_MAJOR_VERSION);     cp.write(dout);   // (write constant pool)     // u2 access_flags;     dout.writeShort(ACC_PUBLIC | ACC_FINAL | ACC_SUPER);     // u2 this_class;     dout.writeShort(cp.getClass(dotToSlash(className)));     // u2 super_class;     dout.writeShort(cp.getClass(superclassName));     // u2 interfaces_count;     dout.writeShort(interfaces.length);     // u2 interfaces[interfaces_count];     for (int i = 0; i < interfaces.length; i++) {   dout.writeShort(cp.getClass(   dotToSlash(interfaces[i].getName())));     }     // u2 fields_count;     dout.writeShort(fields.size());     // field_info fields[fields_count];     for (FieldInfo f : fields) {   f.write(dout);     }     // u2 methods_count;     dout.writeShort(methods.size());     // method_info methods[methods_count];     for (MethodInfo m : methods) {   m.write(dout);     }    // u2 attributes_count;     dout.writeShort(0); // (no ClassFile attributes for proxy classes)     } catch (IOException e) {     throw new InternalError("unexpected I/O Exception");     }     return bout.toByteArray();

Java動態代理

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.