《深入理解JAVA虛擬機》9.類加載及執行子系統的案例與實踐

一、Tomcat:正統的類加載器架構

從圖中的委派關係中可以看出:
  • CommonClassLoader能加載的類都可以被Catalina ClassLoader和SharedClassLoader使用,從而實現了公有類庫的共用。
  • CatalinaClassLoader和Shared ClassLoader自己能加載的類則與對方相互隔離。
  • WebAppClassLoader可以使用SharedClassLoader加載到的類,但各個WebAppClassLoader實例之間相互隔離。
  • JasperLoader的加載範圍僅僅是這個JSP文件所編譯出來的那一個.Class文件,它出現的目的就是爲了被丟棄:當Web容器檢測到JSP文件被修改時,會替換掉目前的JasperLoader的實例,並通過再建立一個新的Jsp類加載器來實現JSP文件的HotSwap功能。
WebAppClassLoader
    1.檢查我們先前加載的本地類緩存,加載過就不加載了
    2.通過javase 的 ClassLoader檢查源碼是否有重複類,有的話就通過javaseLoader加載
    3.通過filter方法判斷一些特定的類,如果屬於特定的類,就通過父加載器加載
    4.剩餘的就自己加載,加載失敗的通過父類加載(破壞了雙親委派)
如果tomcat的CommonClassLoader想加載 WebAppClassLoader中的類,那麼可以使用線程上下文類加載器實現。
 

二、字節碼生成技術與動態代理的實現

 
使用Proxy.newProxyInstance(類加載器,類,被代理對象)生成代理對象,可使用參數sun.misc.ProxyGenerator.saveGeneratedFiles=true保存代理後的class文件。源碼jdk/src/share/classes/sun/misc下的sun.misc.ProxyGenerator。
 

三、自己動手實現遠程執行功能

ByteUtils:主要實現字節數組的操作,如字節數組的的替換。
ClassModifier:實現修改Class字節碼,修改常量池的符號引用。
ClassLoader:Java抽象的ClassLoader
HotSwapClassLoader:主要是暴露ClassLoader的defineClass()。
HackSystem:挾持System,其中out、err替換,其餘都轉發到System處理。
JavaClassExecuter:執行器,創建ClassModifer修改目標Class byte的System的符號引用爲HackSystem,然後使用HotSwapClassLoader加載修改後的類,再使用反射運行該類的main方法,異常信息也輸出到HackSystem,返回HackSystem中的緩存字符串。
 
代碼如下:
public class JavaClassExecuter {
    public static String execute(byte[] classByte){
        //清理HackSystem中緩存
        HackSystem.clearBuffer ();
        //創建Class修改器
        ClassModifier cm = new ClassModifier (classByte);
        //修改System符號引用爲HackSystem
        byte[] modifyBytes = cm.modifyUTF8Constant ("java/lang/System","javasource/jvm/hotswap/HackSystem");
        //創建類加載器
        HotSwapClassLoader loader = new HotSwapClassLoader ();
        //加載修改後的Class
        Class clazz = loader.loadByte (modifyBytes);
        try {
            //反射調用main方法
            Method method = clazz.getMethod ("main",new Class[]{String[].class});
            method.invoke (null,new String[]{});
        }catch (Exception e){
            //將異常也輸出到HackSystem中
            e.printStackTrace (HackSystem.out);
        }
        //返回HackSystem中的緩存內容
        return HackSystem.getBufferString ();
    }
}

 

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