ClassLoader究竟為何物?

来源:http://www.cnblogs.com/bethunebtj/archive/2016/03/13/5274213.html
-Advertisement-
Play Games

要深入瞭解ClassLoader,首先就要知道ClassLoader是用來乾什麼的,顧名思義,它就是用來載入Class文件到JVM,以供程式使用 的。我們知道,java程式可以動態載入類定義,而這個動態載入的機制就是通過ClassLoader來實現的,所以可想而知ClassLoader的重 要性如何


要深入瞭解ClassLoader,首先就要知道ClassLoader是用來乾什麼的,顧名思義,它就是用來載入Class文件到JVM,以供程式使用 的。我們知道,java程式可以動態載入類定義,而這個動態載入的機制就是通過ClassLoader來實現的,所以可想而知ClassLoader的重 要性如何。

既然ClassLoader是用來載入類到JVM中的,那麼ClassLoader又是如何被載入呢?難道它不是java的類?

JDK 預設提供瞭如下幾種ClassLoader:

1.  Bootstrp loader
Bootstrp載入器是用C++語言寫的,它是在Java虛擬機啟動後初始化的,它主要負責載入%JAVA_HOME%/jre/lib,-Xbootclasspath參數指定的路徑以及%JAVA_HOME%/jre/classes中的類。

1.  ExtClassLoader  
Bootstrp loader載入ExtClassLoader,並且將ExtClassLoader的父載入器設置為Bootstrploader.ExtClassLoader是用Java寫的,具體來說就是 sun.misc.Launcher$ExtClassLoader,ExtClassLoader主要載入%JAVA_HOME%/jre/lib/ext,此路徑下的所有classes目錄以及java.ext.dirs系統變數指定的路徑中類庫。

2.  AppClassLoader 
Bootstrp loader載入完ExtClassLoader後,就會載入AppClassLoader,並且將AppClassLoader的父載入器指定為 ExtClassLoader。AppClassLoader也是用Java寫成的,它的實現類是sun.misc.Launcher$AppClassLoader,另外我們知道ClassLoader中有個getSystemClassLoader方法,此方法返回的正是AppclassLoader.AppClassLoader主要負責載入classpath所指定的位置的類或者是jar文檔,它也是Java程式預設的類載入器。

當運行一個程式的時候,JVM啟動,運行bootstrap classloader,該ClassLoader載入java核心API(ExtClassLoader和AppClassLoader也在此時被加 載),然後調用ExtClassLoader載入擴展API,最後AppClassLoader載入CLASSPATH目錄下定義的Class,這就是一 個程式最基本的載入流程。

上面大概講解了一下ClassLoader的作用以及一個最基本的載入流程,接下來將講解一下ClassLoader載入的方式,這裡就不得不講一下ClassLoader在這裡使用了雙親委托模式進行類載入。

每一個自定義ClassLoader都必須繼承ClassLoader這個抽象類,而每個ClassLoader都會有一個parent ClassLoader,我們可以看一下ClassLoader這個抽象類中有一個getParent()方法,這個方法用來返回當前 ClassLoader的parent,註意,這個parent不是指的被繼承的類,而是在實例化該ClassLoader時指定的一個 ClassLoader,如果這個parent為null,那麼就預設該ClassLoader的parent是bootstrap classloader,這個parent有什麼用呢?

我們可以考慮這樣一種情況,假設我們自定義了一個ClientDefClassLoader,我們使用這個自定義的ClassLoader載入 java.lang.String,那麼這裡String是否會被這個ClassLoader載入呢?事實上java.lang.String這個類並不 是被這個ClientDefClassLoader載入,而是由bootstrap classloader進行載入,為什麼會這樣?實際上這就是雙親委托模式的原因,因為在任何一個自定義ClassLoader載入一個類之前,它都會先 委托它的父親ClassLoader進行載入,只有當父親ClassLoader無法載入成功後,才會由自己載入,在上面這個例子里,因為 java.lang.String是屬於java核心API的一個類,所以當使用ClientDefClassLoader載入它的時候,該 ClassLoader會先委托它的父親ClassLoader進行載入,上面講過,當ClassLoader的parent為null 時,ClassLoader的parent就是bootstrap classloader,所以在ClassLoader的最頂層就是bootstrap classloader,因此最終委托到bootstrap classloader的時候,bootstrap classloader就會返回String的Class。

我們來看一下ClassLoader中的一段源代碼:

     protected synchronized Class loadClass(String name, boolean resolve) throws ClassNotFoundException{  
         // 首先檢查該name指定的class是否有被載入  
         Class c = findLoadedClass(name);  
         if (c == null) {  
             try {  
                 if (parent != null) {  
                     //如果parent不為null,則調用parent的loadClass進行載入  
                     c = parent.loadClass(name, false);  
                 }else{  
                     //parent為null,則調用BootstrapClassLoader進行載入  
                     c = findBootstrapClass0(name);  
                 }  
             }catch(ClassNotFoundException e) {  
                 //如果仍然無法載入成功,則調用自身的findClass進行載入              
                 c = findClass(name);  
             }  
         }  
         if (resolve) {  
             resolveClass(c);  
         }  
         return c;  
    } 

 

從上面一段代碼中,我們可以看出一個類載入的大概過程與之前我所舉的例子是一樣的,而我們要實現一個自定義類的時候,只需要實現findClass方法即可。

為什麼要使用這種雙親委托模式呢?

第一個原因就是因為這樣可以避免重覆載入,當父親已經載入了該類的時候,就沒有必要子ClassLoader再載入一次。

第二個原因就是考慮到安全因素,我們試想一下,如果不使用這種委托模式,那我們就可以隨時使用自定義的String來動態替代java核心api中定義類 型,這樣會存在非常大的安全隱患,而雙親委托的方式,就可以避免這種情況,因為String已經在啟動時被載入,所以用戶自定義類是無法載入一個自定義的 ClassLoader。

上面對ClassLoader的載入機制進行了大概的介紹,接下來不得不在此講解一下另外一個和ClassLoader相關的類,那就是Class類,每 個被ClassLoader載入的class文件,最終都會以Class類的實例被程式員引用,我們可以把Class類當作是普通類的一個模板,JVM根 據這個模板生成對應的實例,最終被程式員所使用。

我們看到在Class類中有個靜態方法forName,這個方法和ClassLoader中的loadClass方法的目的一樣,都是用來載入class的,但是兩者在作用上卻有所區別。


那為啥要自定義classloader呢?

 

我覺得,主要有以下原因: 1.類隔離。不想讓某些類被其他類看見。 2.安全因素。比如我有一個自定義的加密類的文件,只有用我自己的classloader才能解析成正常的類文件並運行。 3.功能因素。對類載入器有其他的需求之類。
您的分享是我們最大的動力!

-Advertisement-
Play Games
更多相關文章
  • 在C#中沒有獨立的函數存在,只有類的(動態或靜態)方法這一概念,它指的是類中用於執行計算或其它行為的成員。在Python中,你可以使用類似C#的方式定義類的動態或靜態成員方法,因為它與C#一樣支持完全的面向對象編程。你也可以用過程式編程的方式來編寫Python程式,這時Python中的函數與類可以沒
  • 鄭重聲明:本文是筆者網上翻譯原文,部分有做添加說明,所有權歸原文作者! 地址:http://www.cprogramming.com/c++11/rvalue-references-and-move-semantics-in-c++11.html C++一直致力於生成快速的程式。不幸的是,直到C++
  • 背景      在博客 噁心的0.5四捨五入問題 一文中看到一個關於 0.5 不能正確的四捨五入的問題。主要說的是 double 轉換到 BigDecimal 後,進行四捨五入得不到正確的結果: 輸出的結果為: 301353.0499999999883584678173065185546875301
  • 接上一篇隨筆,利用克拉莫法則求解n元線性方程組。 代碼:  
  • Atitit. Async await 優缺點 非同步編程的原理and實現 java c# php   1. async & await的來源1 2. 非同步編程history1 2.1. 線程池 2 2.2. 返回值2 2.3. Semaphore 信號量2 2.4. 線程的異常,主線程可以捕獲到麽2
  • C語言形式參數和實際參數的概念和在一個函數中交換外部變數的方法介紹
  • 關於Android Develop 文檔明明本地下載了,但在瀏覽器里打開還是很卡,原因是html文檔中有鏈接Google伺服器的Link和script。 網上有很多解決方案,其中一種是刪除裡面所有鏈接Google伺服器的Link和script。 我在網上下載的JAVA代碼這兩行修飾css代碼是怎麼也
  • atitit.RandomAccessFile rws rwd 的區別於聯繫   1. Rw rws  rwd1 2. "rws" 模式1 3. rwd"模式2       "r"    以只讀方式打開。調用結果對象的任何 write 方法都將導致拋出 IOException。  "rw" 
一周排行
    -Advertisement-
    Play Games
  • 移動開發(一):使用.NET MAUI開發第一個安卓APP 對於工作多年的C#程式員來說,近來想嘗試開發一款安卓APP,考慮了很久最終選擇使用.NET MAUI這個微軟官方的框架來嘗試體驗開發安卓APP,畢竟是使用Visual Studio開發工具,使用起來也比較的順手,結合微軟官方的教程進行了安卓 ...
  • 前言 QuestPDF 是一個開源 .NET 庫,用於生成 PDF 文檔。使用了C# Fluent API方式可簡化開發、減少錯誤並提高工作效率。利用它可以輕鬆生成 PDF 報告、發票、導出文件等。 項目介紹 QuestPDF 是一個革命性的開源 .NET 庫,它徹底改變了我們生成 PDF 文檔的方 ...
  • 項目地址 項目後端地址: https://github.com/ZyPLJ/ZYTteeHole 項目前端頁面地址: ZyPLJ/TreeHoleVue (github.com) https://github.com/ZyPLJ/TreeHoleVue 目前項目測試訪問地址: http://tree ...
  • 話不多說,直接開乾 一.下載 1.官方鏈接下載: https://www.microsoft.com/zh-cn/sql-server/sql-server-downloads 2.在下載目錄中找到下麵這個小的安裝包 SQL2022-SSEI-Dev.exe,運行開始下載SQL server; 二. ...
  • 前言 隨著物聯網(IoT)技術的迅猛發展,MQTT(消息隊列遙測傳輸)協議憑藉其輕量級和高效性,已成為眾多物聯網應用的首選通信標準。 MQTTnet 作為一個高性能的 .NET 開源庫,為 .NET 平臺上的 MQTT 客戶端與伺服器開發提供了強大的支持。 本文將全面介紹 MQTTnet 的核心功能 ...
  • Serilog支持多種接收器用於日誌存儲,增強器用於添加屬性,LogContext管理動態屬性,支持多種輸出格式包括純文本、JSON及ExpressionTemplate。還提供了自定義格式化選項,適用於不同需求。 ...
  • 目錄簡介獲取 HTML 文檔解析 HTML 文檔測試參考文章 簡介 動態內容網站使用 JavaScript 腳本動態檢索和渲染數據,爬取信息時需要模擬瀏覽器行為,否則獲取到的源碼基本是空的。 本文使用的爬取步驟如下: 使用 Selenium 獲取渲染後的 HTML 文檔 使用 HtmlAgility ...
  • 1.前言 什麼是熱更新 游戲或者軟體更新時,無需重新下載客戶端進行安裝,而是在應用程式啟動的情況下,在內部進行資源或者代碼更新 Unity目前常用熱更新解決方案 HybridCLR,Xlua,ILRuntime等 Unity目前常用資源管理解決方案 AssetBundles,Addressable, ...
  • 本文章主要是在C# ASP.NET Core Web API框架實現向手機發送驗證碼簡訊功能。這裡我選擇是一個互億無線簡訊驗證碼平臺,其實像阿裡雲,騰訊雲上面也可以。 首先我們先去 互億無線 https://www.ihuyi.com/api/sms.html 去註冊一個賬號 註冊完成賬號後,它會送 ...
  • 通過以下方式可以高效,並保證數據同步的可靠性 1.API設計 使用RESTful設計,確保API端點明確,並使用適當的HTTP方法(如POST用於創建,PUT用於更新)。 設計清晰的請求和響應模型,以確保客戶端能夠理解預期格式。 2.數據驗證 在伺服器端進行嚴格的數據驗證,確保接收到的數據符合預期格 ...