java動態代理隨筆一

       先說一下java class的加載機制和與class文件的關係:Java 程序的工作機制: Java 對象都以單獨的 class 文件存在, java 虛擬機將其載入並執行其虛擬機指令。

 

  class 的加載與實例化

java 虛擬機根據 class path 來查找 java 對象,而虛擬機的 class path 又分爲三層:

bootstrap sun.boot.class.path

extension: java.ext.dirs

application: java.class.path

三個 class path 各有對應的 classloader 。由上而下形成父子關係

當程序中調用 new 指令,或者 ClassLoader.load 方法時。其順序如下:

1.       首先查看 application classloader 中是否已有對應的 class 緩存,如果有則返回,並根據 class 分配內存。如果沒有,接下一步。

2.       首先查看 extension classloader 中是否已有對應的 class 緩存,如果有則返回,並根據 class 分配內存。如果沒有,接下一步。

3.       首先查看 bootstrap classloader 中是否已有對應的 class 緩存,如果有則返回,並根據 class 分配內存。如果沒有,接下一步。

4.       bootstrap classloader 在其 class path 中試圖加載該 class ,如果有,則將該 class 放入 cache 中,並返回。如果沒有,接下一步。

5.       extension classloader 在其 class path 中試圖加載該 class ,如果有,則將該 class 放入 cache 中,並返回。如果沒有,接下一步。

6.       application classloader 在其 class path 中試圖加載該 class ,如果有,則將該 class 放入 cache 中,並返回。如果沒有,則拋出 ClassNotFound exception

 

每個 java 虛擬機都在其啓動時產生一個唯一的 class heap ,並把所有的 class instance 都分配在其中。其中每個類實例的信息又分兩部分, fields 域和 methods 域。每個類實例各自擁有 fields ,但同一個類的不同實例共享 methods

 


java 反射的處理

簡單例子代碼:

import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.InvocationTargetException;
import java.io.IOException;

 public class Main {
    public static void main(String[] args){
        TempImpl t1 = new TempImpl("temp1");
        try {
            Method t1Talk = t1.getClass().getMethod("Talk", new Class[0]) ;
            t1Talk.invoke(t1, null);
        } catch (NoSuchMethodException e) {
            e.printStackTrace();  //To change body of catch statement use File | Settings | File Templates.
        } catch (IllegalAccessException e) {
            e.printStackTrace();  //To change body of catch statement use File | Settings | File Templates.
        } catch (InvocationTargetException e) {
           e.printStackTrace();  //To change body of catch statement use File | Settings | File Templates.
        }

        try {
            System.in.read();
        } catch (IOException e) {
            e.printStackTrace();  //To change body of catch statement use File | Settings | File Templates.
        }
    }
} 
 

複雜例子代碼:

 import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.InvocationTargetException;
import java.io.IOException; 

public class Main {
    public static void main(String[] args){
        TempImpl t1 = new TempImpl("temp1");
        TempImpl t2 = new TempImpl("temp2");
        Temp2 temp2 = new Temp2();

        try {
            Method t1Talk = t1.getClass().getMethod("Talk", new Class[0]) ;
            Method t2Talk = t2.getClass().getMethod("Talk", new Class[0]) ;
            t1Talk.invoke(t2, null);
            t2Talk.invoke(t1, null);
            if(t1Talk.equals(t2Talk)){
                System.out.println("equals");
            }else{
                System.out.println("not equals");
             }

            if(t1Talk==t2Talk){
               System.out.println("ref equals");
            }else{
                System.out.println("ref not equals");
            }

            t2Talk.invoke(temp2, null);
        } catch (NoSuchMethodException e) {
            e.printStackTrace();  //To change body of catch statement use File | Settings | File Templates.
        } catch (IllegalAccessException e) {
            e.printStackTrace();  //To change body of catch statement use File | Settings | File Templates.
        } catch (InvocationTargetException e) {
            e.printStackTrace();  //To change body of catch statement use File | Settings | File Templates.
        }

        try {
            System.in.read();
        } catch (IOException e) {
            e.printStackTrace();  //To change body of catch statement use File | Settings | File Templates.
        }
    }
}

分析: java 虛擬機把每個 methods 當作一個執行單元。該執行單元帶有兩種簽名:類簽名和屬性簽名( public static 等)。 反射的第一步,驗證簽名的合法性。驗證通過後,順序執行該 method 中的指令,當需要訪問類實例的 fields 和傳入參數時,由虛擬機注入。

 

 

 

動態代理

一個簡單例子代碼:

研究 JDK 源代碼,發現在 Proxy sun 實現中調用了 sun.misc.ProxyGenerator 類的 generateProxyClass( proxyName, interfaces) 方法,其返回值爲 byte[] class 文件的內存類型一致。於是做如下試驗:

 public class  ProxyClassFile{

       public static void main(String[] args){

              String proxyName = "TempProxy";

        TempImpl t = new TempImpl("proxy");

              Class[] interfaces =t.getClass().getInterfaces();

             

              byte[] proxyClassFile = ProxyGenerator.generateProxyClass(

                  proxyName, interfaces);

        File f = new File("classes/TempProxy.class");

        try {

            FileOutputStream fos = new FileOutputStream(f);

            fos.write(proxyClassFile);

            fos.flush();

            fos.close();

        } catch (FileNotFoundException e) {

            e.printStackTrace();  //To change body of catch statement use File | Settings | File Templates.

        } catch (IOException e) {

            e.printStackTrace();  //To change body of catch statement use File | Settings | File Templates.

        }

       }

}
 

運行該類,到 class 文件夾下,利用反編譯技術,發現原來其採用了代碼生產技術:

 

  public interface Temp{

       public void Talk();

       public void Run();

} 
 
  import java.lang.reflect.*;

 

public final class TempProxy extends Proxy

    implements Temp{

 

    private static Method m4;

    private static Method m2;

    private static Method m0;

    private static Method m3;

    private static Method m1;

 

    public TempProxy(InvocationHandler invocationhandler)   {

        super(invocationhandler);

    }

 

    public final void Run()    {

        try {

            h.invoke(this, m4, null);

            return;

        }

            catch(Error _ex) { }

             catch(Throwable throwable)  {

            throw new UndeclaredThrowableException(throwable);

        }

    }

 

    public final String toString(){

        try{

            return (String)h.invoke(this, m2, null);

        }

            catch(Error _ex) { }

            catch(Throwable throwable)   {

            throw new UndeclaredThrowableException(throwable);

        }

        return "";

    }

 

    public final int hashCode() {

        try {

            return ((Integer)h.invoke(this, m0, null)).intValue();

        }

             catch(Error _ex) { }

            catch(Throwable throwable){

            throw new UndeclaredThrowableException(throwable);

        }

        return 123;

    }

 

    public final void Talk(){

        try{

            h.invoke(this, m3, null);

            return;

        }

            catch(Error _ex) { }

            catch(Throwable throwable) {

            throw new UndeclaredThrowableException(throwable);

        }

    }

 

    public final boolean equals(Object obj) {

        try  {

            return ((Boolean)h.invoke(this, m1, new object[{obj})).booleanValue();

        }

           catch(Error _ex) { }

           catch(Throwable throwable) {

            throw new UndeclaredThrowableException(throwable);

        }

        return false;

    }

 

    static{

        try{

     m4 = Class.forName("Temp").getMethod("Run", new Class[0]);

     m2 = Class.forName("java.lang.Object").getMethod("toString", new Class[0]);

      m0 = Class.forName("java.lang.Object").getMethod("hashCode", new Class[0]);

      m3 = Class.forName("Temp").getMethod("Talk", new Class[0]);

     m1 = Class.forName("java.lang.Object").getMethod("equals", new Class[] {

                Class.forName("java.lang.Object")

            });

        }

        catch(NoSuchMethodException nosuchmethodexception) {

             throw new NoSuchMethodError(nosuchmethodexception.getMessage());

        }

        catch(ClassNotFoundException classnotfoundexception) {

            throw new NoClassDefFoundError(classnotfoundexception.getMessage());

        }

    }

} 
 
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章