JAVA中的Launcher類解析
一、ClassLoader
sun.misc.Launcher類是java的入口,在啟動java應用的時候會首先創(chuàng)建Launcher類,創(chuàng)建Launcher類的時候回準備應用程序運行中需要的類加載器。
Launcher作為JAVA應用的入口,根據(jù)雙親委派模型,Laucher是由JVM創(chuàng)建的,它類加載器應該是BootStrapClassLoader, 這是一個C++編寫的類加載器,是java應用體系中最頂層的類加載器,負責加載JVM需要的一些類庫(<JAVA_HOME>/lib)??梢酝ㄟ^一個簡單的代碼驗證一下我們的想法。
public class App { public static void main(String[] args) { ClassLoader classLoader = Launcher.class.getClassLoader(); } }
這里的classLoader是null,說明Launcher確實是BootstrapClassLoader加載的,那么我們就會非常好奇,ExtClassLoader是什么時候創(chuàng)建的呢?翻看一下Launcher的構(gòu)造器的代碼。
public Launcher() { sun.misc.Launcher.ExtClassLoader extClassLoader; try { extClassLoader = sun.misc.Launcher.ExtClassLoader.getExtClassLoader(); } catch (IOException var10) { throw new InternalError("Could not create extension class loader", var10); } try { this.loader = sun.misc.Launcher.AppClassLoader.getAppClassLoader(extClassLoader); } catch (IOException var9) { throw new InternalError("Could not create application class loader", var9); } Thread.currentThread().setContextClassLoader(this.loader); }
Launcher在創(chuàng)建的時候,第一件事情就是獲取ExtClassLoader, ExtClassLoader在JVM中是一個單例, 創(chuàng)建過程也是通過獲取環(huán)境變量來獲取ext加載的目錄,生成一個ExtClassLoader,ExtClassLoader是URLClassLoader的子類。
public static Launcher.ExtClassLoader getExtClassLoader() throws IOException { if (instance == null) { Class clazz = Launcher.ExtClassLoader.class; synchronized(Launcher.ExtClassLoader.class) { if (instance == null) { instance = createExtClassLoader(); } } } return instance; }
在獲取ExtClassLoader之后,以此作為父類加載器創(chuàng)建一個 sun.misc.Launcher.AppClassLoader, AppClassLoader的加載路徑是java.class.path標記的路徑,相同的,AppClassLoader也是URLClassLoader的子類。最終會將當前線程的上下文類加載器設置為AppClassLoader。 通過上述分析,當我們需要獲取當前應用程序的AppClassLoader或者ExtClassLoader的時候,可以直接使用Launcher來訪問。
public class App { public static void main(String[] args) { ClassLoader appClassLoader = Launcher.getLauncher().getClassLoader(); ClassLoader extClassLoader = appClassLoader.getParent(); } }
二、Thread上下文ClassLoader的思考
java程序并不是一個單獨的可執(zhí)行文件,而是由一組.class文件組成。在應用程序啟動的時候,并不是所有的類都會被加載,一個類被加載的時候會使用引用這個類的那個類的加載器來加載,也就是xxx.class.getClassLoader()。但是在日常使用的時候,還有一種是通過Thread的上限文獲取類加載器。
在java中為什么需要上下文類加載器呢,這個就是一個非常有意思的問題。 我們都知道java類加載的雙親委派模型,在加載一個類的時候,會優(yōu)先委派給父類加載器,這樣保證不會出現(xiàn)類被重復加載,也保證了java一些基礎類可以穩(wěn)定的存在,不會被用戶自定義類頂替掉。
雙親委派模型并不是完美的,在一些場景下會出現(xiàn)一些比較難解決的問題,舉個例子,在使用SPI的時候,ServiceLoader是通過BootStrap類加載器加載的,在執(zhí)行到加載用戶編寫的擴展類的時候,如果使用當前類的類加載器,是肯定無法加載到用戶編寫的類的,這個時候就無法繼續(xù)執(zhí)行了,所以這個時候就需要使用Thread的上下文類加載器,查看源碼的時候我們就發(fā)現(xiàn),在用戶不主動傳遞ClassLoader的時候,會獲取當前上下文類加載器,這樣應用程序才能正常的執(zhí)行。
public static <S> ServiceLoader<S> load(Class<S> service) { ClassLoader cl = Thread.currentThread().getContextClassLoader(); return ServiceLoader.load(service, cl); }
到此這篇關于JAVA中的Launcher類解析的文章就介紹到這了,更多相關JAVA的Launcher內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關文章希望大家以后多多支持腳本之家!
相關文章
springboot接口多實現(xiàn)類選擇性注入解決方案
這篇文章主要為大家介紹了springboot接口多實現(xiàn)類選擇性注入解決方案的四種方式,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進步2022-03-03spring聲明式事務@Transactional開發(fā)常犯的幾個錯誤及最新解決方案
使用聲明式事務@Transactional進行事務一致性的管理,在開發(fā)過程中,發(fā)現(xiàn)很多開發(fā)同學都用錯了spring聲明式事務@Transactional或使用不規(guī)范,導致出現(xiàn)各種事務問題,這篇文章主要介紹了spring聲明式事務@Transactional開發(fā)常犯的幾個錯誤及解決辦法,需要的朋友可以參考下2024-02-02Java創(chuàng)建對象之顯示創(chuàng)建與隱式創(chuàng)建
在本篇文章中,小編會帶大家學習面向?qū)ο笾嘘P于對象的創(chuàng)建之顯示創(chuàng)建和隱式創(chuàng)建,其實類和對象作為面向?qū)ο笾凶罨镜?,也是最重要?需要的朋友可以參考下2023-05-05MyBatis實現(xiàn)簡單的數(shù)據(jù)表分月存儲
本文主要介紹了MyBatis實現(xiàn)簡單的數(shù)據(jù)表分月存儲,文中通過示例代碼介紹的非常詳細,對大家的學習或者工作具有一定的參考學習價值,需要的朋友們下面隨著小編來一起學習學習吧2023-03-03