Java類加載體系

          早期的java程序員可能只要懂基本語法,還有少數的項目經驗就可以找到一份比較好的工作。Java和java社區的發展,更多的人了解它,深入它。現在java程序員了解一些語法我看還遠遠不夠了,對于jvm的了解和深入是非常重要的。網民的增多,網站的剛性需求,很多網站面臨高性能,高并發等等一系列的問題。沒有深入jvm的java程序員是很難寫出高質量高并發的代碼(也許一棒子打死所有人了,但我想絕大部分是肯定的)。

           

          Osgi也許你并不陌生,但是他底層的實現機制你可能沒去了解過。如果你是個打破砂鍋問到底的人,你肯定會想知道osgi是如何做到的。但是你沒有了解jvm的類加載體系,你肯定很難理解osgi是如果做到類隔離等一系列的問題。不過想完整理解osgi還需要其他很多方面的知識,但是它基本的機制還是的了解jvm的類加載機制。

           

          Java類庫有些包只是定義了一個標準,具體的實現都是由具體的供應商來提供。Java與數據庫連接就是一個很好的例子。Java.sql類庫只是定義了java與數據庫連接的標準,那么與mysql就需要msyql的驅動,oracle就需要oracle的驅動,而java.sql類庫是由bootstrap classloader加載,驅動包中的類是由system classloader來加載,不同類加載器加載的類是無法相互認識,所以自然也無法正常提供功能了。jvm又是提供了什么機制讓他們交互呢?如果你確實對這些問題毫無頭緒的話,那么我覺得你真的要好好理解下jvm類加載體系。

           

          這篇文章主要是介紹下jvm類加載的機制基礎知識。關于其他相關涉及,有時間的話,我會單獨寫文章來介紹。

           

          1 java類加載器

          http://www.aygfsteel.com/images/blogjava_net/yangpingyu/classloader-1.jpg

          1.1 Bootstrap classloader:sun jdk是用c++實現,所以在代碼中你是無法獲取此加載器的實例。此加載器主要負責加載$JAVA_HOME/jre/lib/rt.jar。java類中獲取結果為null,這里可以用一個例子跑下證明:

          public class Test {

                   public static void main(String[] arg) throws Exception{

                             ClassLoader classloader = Test.class.getClassLoader();

                             System.out.println(classloader);

                             System.out.println(classloader.getParent());

                             System.out.println(classloader.getParent().getParent());

                   }

          }

          輸出結果:

          sun.misc.Launcher$AppClassLoader@19821f

          sun.misc.Launcher$ExtClassLoader@addbf1

          null

          最后輸出的null就是代表bootstrap classloader。

           

          1.2 Extension classloader:主要加載擴展功能的jar,$JAVA_HOME/jre/lib/ext/*.jar。

          1.3 System classloader:加載claspath中的jar包。

          1.4自定義 classloader:主要加載你指定的目錄中的包和類。

           

          2 雙親委派模型

          系統運行時,我們請求加載String類,此時System Classloader自己不找classpath中的包,把請求轉發給Extension Classloader,但它也不做查找,又轉發給Bootstrap Classloader,但是它發現自己沒有parent了。于是他在rt.jar包中找到String類并加載到jvm中提供使用。Jvm為什么要這么實現呢?其實和java安全體系有關。假設jvm不是這么實現,我們自定義一個String類,做一些破壞,那么運行jvm的機器肯定要受到損壞。具體例子:

          public class String {

                   public static void main(String[] args) {

                             System.out.println("hello world");

                   }

          }

          我們運行自定義String類的時候報錯了,說沒有main方法,可我們定義的明明有的,嘿嘿,委派機制的緣故最后加載到的是由bootstrap classloader在rt.jar包中的String,那個類是沒有main方法,因此報錯了。

          http://www.aygfsteel.com/images/blogjava_net/yangpingyu/classloader-2.jpg

          3 類隔離

          jvm中的類是:類加載器+包名+類名。比如:URLClassLoader1,URLClassLoader2分別加載com.test.Test的時候會加載兩次,因為每個classloader中的類對于其他classloader來說是隔離的,不認識的。例子:

          import java.net.URL;
          import java.net.URLClassLoader;

          public class CustomClassloaderTest {
              
          public static void main(String[] args) throws Exception {
                  URL url = 
          new URL("file:/g:/");
                  URLClassLoader ucl = 
          new URLClassLoader(new URL[]{url});
                  Class c = ucl.loadClass("Yang");
                  c.newInstance();
                  System.out.println(c.getClassLoader());

                  URLClassLoader ucl2 = 
          new URLClassLoader(new URL[]{url});
                  Class c2 = ucl2.loadClass("Yang");
                  c2.newInstance();
                  System.out.println(c2.getClassLoader());
              }
          }

          大家把Yang類存在g盤下。

          public class Yang {
              
          static {
                  System.out.println("Yang");
              }
          }

          運行結果:

          Yang

          java.net.URLClassLoader@c17164

          Yang

          java.net.URLClassLoader@61de33

          看到每次加載Yang類的時候都輸出Yang,說明Yang類被加載了兩次。

          如果你不確信,可以修改下代碼,讓同一classloader加載Yang類兩次

           

          import java.net.URL;
          import java.net.URLClassLoader;

          public class CustomClassloaderTest {
              
          public static void main(String[] args) throws Exception {
                  URL url = 
          new URL("file:/g:/");
                  URLClassLoader ucl = 
          new URLClassLoader(new URL[]{url});
                  Class c = ucl.loadClass("Yang");
                  c.newInstance();
                  System.out.println(c.getClassLoader());

                  Class c2 = ucl.loadClass("Yang");
                  c2.newInstance();
                  System.out.println(c2.getClassLoader());
              }
          }

          看看輸出結果:

          Yang

          java.net.URLClassLoader@c17164

          java.net.URLClassLoader@c17164

          結果中只輸出了一次Yang。因此可以證明我們最開始說的類隔離。

           

          4 線程上下文類加載器

          我們理解了雙親委派模型,那么目前只有由下向上單向尋找類(system->extension->bootstrap)

          。我們在最開始的時候說過,java.sql包中的類由bootstrap或extension classloader加載,而mysql驅動包是在classpath中由system來加載,但bootstrap中的類是無法找到system classloader中的類,此時靠線程上下文類加載器來解決。線程上下文類加載器主要就是能讓jvm類加載模型具有了向下尋找的可能,bootstrap->extension->system,如果不做任何設置,線程上下文類加載器默認是system classloader。本來這里想寫一個例子的,可是有點麻煩,所以下次單獨寫一篇關于這方面的知識。

           

          posted on 2011-05-14 21:41 yangpingyu 閱讀(1026) 評論(2)  編輯  收藏 所屬分類: java基礎

          評論

          # re: Java類加載體系[未登錄] 2011-11-19 21:35 Alex

          請問你用的是哪個jdk,我嘗試的情況是,兩個classloader 加載同一個class,static仍然只是被執行一次的。  回復  更多評論   

          # re: Java類加載體系 2011-11-30 15:11 yangpingyu

          @Alex
          我在家里用的好像是jdk1.6版本。  回復  更多評論   

          <2011年5月>
          24252627282930
          1234567
          891011121314
          15161718192021
          22232425262728
          2930311234

          導航

          統計

          常用鏈接

          留言簿

          隨筆分類

          隨筆檔案

          收藏夾

          linux

          產品交互

          分析,設計,架構

          安全

          技術牛人

          數據庫

          搜索

          最新評論

          閱讀排行榜

          評論排行榜

          主站蜘蛛池模板: 高碑店市| 南丹县| 新昌县| 衡山县| 周宁县| 六盘水市| 龙江县| 工布江达县| 台安县| 宁河县| 金门县| 东平县| 徐闻县| 略阳县| 荔波县| 白玉县| 蓝山县| 泗洪县| 长治县| 昔阳县| 阜城县| 巴马| 普安县| 修水县| 海兴县| 石棉县| 锡林浩特市| 谢通门县| 泌阳县| 冀州市| 荥经县| 香河县| 马尔康县| 宣武区| 蒙阴县| 汉源县| 蒙自县| 英超| 育儿| 鸡泽县| 右玉县|