亚洲乱码中文字幕综合,中国熟女仑乱hd,亚洲精品乱拍国产一区二区三区,一本大道卡一卡二卡三乱码全集资源,又粗又黄又硬又爽的免费视频

SpringBoot的jar包如何啟動(dòng)的實(shí)現(xiàn)

 更新時(shí)間:2022年03月20日 11:05:09   作者:不懂技術(shù)的小菜鳥  
本文主要介紹了SpringBoot的jar包如何啟動(dòng)的實(shí)現(xiàn),文中根據(jù)實(shí)例編碼詳細(xì)介紹的十分詳盡,具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下

一、簡介

? 使用過SprongBoot打過jar包的都應(yīng)該知道,目標(biāo)文件一般都會生成兩個(gè)文件,一個(gè)是以.jar的包,一個(gè)是.jar.original文件。那么使用SpringBoot會打出兩個(gè)包,而.jar.original的作用是什么呢?還有就是java -jar是如何將一個(gè)SpringBoot項(xiàng)目啟動(dòng),之間都進(jìn)行了那些的操作?

? 其實(shí).jar.originalmavenSpringBoot重新打包之前的原始jar包,內(nèi)部只包含了項(xiàng)目的用戶類,不包含其他的依賴jar包,生成之后,SpringBoot重新打包之后,最后生成.jar包,內(nèi)部包含了原始jar包以及其他的引用依賴。以下提及的jar包都是SpringBoot二次加工打的包。

二、jar包的內(nèi)部結(jié)構(gòu)

SpringBoot打出的jar包,可以直接通過解壓的方式查看內(nèi)部的構(gòu)造。一般情況下有三個(gè)目錄。

  • BOOT-INF:這個(gè)文件夾下有兩個(gè)文件夾classes用來存放用戶類,也就是原始jar.original里的類;還有一個(gè)是lib,就是這個(gè)原始jar.original引用的依賴。
  • META-INF:這里是通過java -jar啟動(dòng)的入口信息,記錄了入口類的位置等信息。
  • org:Springboot loader的代碼,通過它來啟動(dòng)。

這里主要介紹一下/BOOT-INF/MANIFEST.MF文件

Main-Class: org.springframework.boot.loader.JarLauncher
Start-Class: cn.com.springboot.center.AuthEenterBootstrap

Main-Class:記錄了java -jar的啟動(dòng)入口,當(dāng)使用該命令啟動(dòng)時(shí)就會調(diào)用這個(gè)入口類的main方法,顯然可以看出,Springboot轉(zhuǎn)移了啟動(dòng)的入口,不是用戶編寫的xxx.xxx.BootStrap的那個(gè)入口類。

Start-Class:記錄了用戶編寫的xxx.xxx.BootStrap的那個(gè)入口類,當(dāng)內(nèi)嵌的jar包加載完成之后,會使用LaunchedURLClassLoader線程加載類來加載這個(gè)用戶編寫的入口類。

三、加載過程

1.使用到的一些類

3.1.1 Archive

? 歸檔文件接口,實(shí)現(xiàn)迭代器接口,它有兩個(gè)子類,一個(gè)是JarFileArchivejar包文件使用,提供了返回這個(gè)jar文件對應(yīng)的url、或者這個(gè)jar文件的MANIFEST文件數(shù)據(jù)信息等操作。是ExplodedArchive是文件目錄的使用也有獲取這個(gè)目錄url的方法,以及獲取這個(gè)目錄下的所有Archive文件方法。

3.1.2 Launcher

? 啟動(dòng)程序的基類,這邊最后是通過JarLauncher#main()來啟動(dòng)。ExecutableArchiveLauncher是抽象類,提供了獲取Start-Class類路徑的方法,以及是否還有內(nèi)嵌對應(yīng)文件的判斷方法和獲取到內(nèi)嵌對應(yīng)文件集合的后置處理方法的抽象,由子類JarLauncherWarLauncher自行實(shí)現(xiàn)。

3.1.3 Spring.loader下的JarFile和JarEntry

? jarFile繼承于jar.util.jar.JarFile,JarEntry繼承于java.util.jar.JarEntry,對原始的一些方法進(jìn)行重寫覆蓋。每一個(gè)JarFileArchive都擁有一個(gè)JarFile方法,用于存儲這個(gè)jar包對應(yīng)的文件,而每一個(gè)JarFile都有一個(gè)JarFileEntries,JarFileEntries是一個(gè)迭代器??偟膩碚f,在解析jar包時(shí),會將jar包內(nèi)的文件封裝成JarEntry對象后由JarFile對象保存文件列表的迭代器。所以JarFileArchiveJarFileEntries之間是通過JarFile連接,二者都可以獲取到JarFile對象。

2.過程分析

MANIFEST.MF文件中的Main-class指向入口開始。

創(chuàng)建JarLauncher并且通過它的launch()方法開始加載jar包內(nèi)部信息。

public static void main(String[] args) throws Exception {
  new JarLauncher().launch(args);
}

JarLauncher的空構(gòu)造方法時(shí)一個(gè)空實(shí)現(xiàn),剛開始看的時(shí)候還懵了一下,以為是在后續(xù)的操作中去加載的文件,其實(shí)不然,在創(chuàng)建時(shí)由父類ExecutableArchiveLauncher的構(gòu)造方法去加載的文件。

加載為歸檔文件對象:

this.archive = createArchive();

具體的加載方法:判斷路徑是否是一個(gè)文件夾,是則返回ExplodedArchive對象,否則返回JarFileArchive 進(jìn)入JarFileArchive類:通過這個(gè)new方法創(chuàng)建JarFile對象

public class JarFileArchive implements Archive {

  public JarFileArchive(File file, URL url) throws IOException {
    this(new JarFile(file));
    this.url = url;
  }
}

進(jìn)入到JarFile方法:通過RandomAccessDataFile讀取文件的內(nèi)容,并傳遞給本類中的方法進(jìn)行具體的解析。

public class JarFile extends java.util.jar.JarFile {

  public JarFile(File file) throws IOException {
    this(new RandomAccessDataFile(file));
  }
}

進(jìn)入jarLauncherlaunch方法:注冊URL協(xié)議的處理器,沒有指定時(shí),默認(rèn)指向org.springframework.boot.loader包路徑,獲取類路徑下的歸檔文件Archive并通過這些歸檔文件的URL,創(chuàng)建線程上下文類加載器,使用類加載器和用戶編寫的啟動(dòng)入口類,通過反射調(diào)用它的main方法。

protected void launch(String[] args) throws Exception {
  JarFile.registerUrlProtocolHandler();
  ClassLoader classLoader = createClassLoader(getClassPathArchives());
  launch(args, getMainClass(), classLoader);
}

JarLaunchergetClassPathArchives是在ExecutableArchiveLauncher中實(shí)現(xiàn):獲取歸檔文件中滿足EntryFilterg過濾器的項(xiàng),isNestedArchive方法由具體的之類實(shí)現(xiàn)。獲取到當(dāng)前歸檔文件下的所有子歸檔文件之后的后置操作,是一個(gè)擴(kuò)展點(diǎn)。在JarLauncher中是一個(gè)空實(shí)現(xiàn)。

JarLauncher的具體實(shí)現(xiàn),這里通過判斷是否在BOOT-INF/lib/包下返回true 也就是說只會把jar包下的BOOT-INF/lib/下的文件加載為Archive對象

protected boolean isNestedArchive(Archive.Entry entry) {
  if (entry.isDirectory()) {
    return entry.getName().equals(BOOT_INF_CLASSES);
  }
  return entry.getName().startsWith(BOOT_INF_LIB);
}

JarFileArchivegetNestedArchives方法:若匹配器匹配到則獲取內(nèi)嵌歸檔文件。

具體的獲取內(nèi)嵌歸檔文件邏輯:根據(jù)具體的Entry對象,創(chuàng)建JarFile對象并封裝成歸檔文件對象后返回。

protected Archive getNestedArchive(Entry entry) throws IOException {
    try {
        JarFile jarFile = this.jarFile.getNestedJarFile(jarEntry);
        return new JarFileArchive(jarFile);
    }
}

獲取到參數(shù)entry對應(yīng)的RandomAccessData對象,這里根據(jù)springboot擴(kuò)展的url協(xié)議,在父路徑的基礎(chǔ)上添加!/來標(biāo)記子包。

private JarFile createJarFileFromFileEntry(JarEntry entry) throws IOException {
    RandomAccessData entryData = this.entries.getEntryData(entry.getName());
    return new JarFile(this.rootFile, this.pathFromRoot + "!/" + entry.getName(),
                       entryData, JarFileType.NESTED_JAR);
}

到這基本上讀取jar內(nèi)部信息,加載為對應(yīng)歸檔文件對象的大概過程已經(jīng)講完了,接下來分析一下在獲取到了整個(gè)jar的歸檔文件對象后的處理。

通過歸檔文件對象列表,獲取對應(yīng)的url信息,并通過url信息創(chuàng)建LaunchedURLClassLoader

protected ClassLoader createClassLoader(List<Archive> archives) {
    List<URL> urls = new ArrayList<URL>(archives.size());
    for (Archive archive : archives) {
        urls.add(archive.getUrl());
    }
    return createClassLoader(urls.toArray(new URL[urls.size()]));
}

獲取到對應(yīng)的LaunchedUrlClassLoader類加載器之后,設(shè)置線程的上下文類加載器為該加載器。根據(jù)MANIFI.MF文件中的start-classs信息創(chuàng)建項(xiàng)目啟動(dòng)入口主類對象,并通過返回對象的run方法啟動(dòng)

protected void launch(String[] args, String mainClass, ClassLoader classLoader) {
    Thread.currentThread().setContextClassLoader(classLoader);
    createMainMethodRunner(mainClass, args, classLoader).run();
}

進(jìn)入MainMethodRunnerrun方法:先通過當(dāng)前線程獲取到main入口類,然后通過反射調(diào)用啟動(dòng)項(xiàng)目啟動(dòng)類的main方法

public void run() throws Exception {
    Class<?> mainClass = Thread.currentThread().getContextClassLoader()
                    .loadClass(this.mainClassName);
    Method mainMethod = mainClass.getDeclaredMethod("main", String[].class);
    mainMethod.invoke(null, new Object[] { this.args });
}

最后來說一下這個(gè)LaunchedURLClassLoader,它繼承于URLClassLoader,并重寫了loadClass方法

LaunchedClassLoaderloadClass方法:調(diào)用父類loadClass方法,走正常委派流程,最終會被LaunchURLClassLoader加載。

@Override
protected Class<?> loadClass(String name, boolean resolve){
   try {
      try {
         definePackageIfNecessary(name);
      }
      return super.loadClass(name, resolve);
   }
}

進(jìn)入URLClassLoader中根據(jù)springboot解析進(jìn)行解析。根據(jù)名稱將路徑轉(zhuǎn)化為以.class結(jié)尾的/分隔的格式。通過UrlClassPath對象根據(jù)路徑獲取資源類文件

new PrivilegedExceptionAction<Class<?>>() {
    public Class<?> run() throws ClassNotFoundException {
      String path = name.replace('.', '/').concat(".class");
      Resource res = ucp.getResource(path, false);
      if (res != null) {
        try {
          return defineClass(name, res);
        }
      }
    }
  }

四、總結(jié)

? Springboot主要實(shí)現(xiàn)了對URL加載方式進(jìn)行了擴(kuò)展,并且對一些對象ArchiveJarFile、Entry等進(jìn)行了抽象和擴(kuò)展,最后使用LaunchedUrlClassLoader來進(jìn)行處理。

到此這篇關(guān)于SpringBoot的jar包如何啟動(dòng)的實(shí)現(xiàn)的文章就介紹到這了,更多相關(guān)SpringBoot jar包啟動(dòng)內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!

相關(guān)文章

  • Spring自定義注解配置簡單日志示例

    Spring自定義注解配置簡單日志示例

    這篇文章主要介紹了Spring自定義注解配置簡單日志示例,注解可以增強(qiáng)我們的java代碼,同時(shí)利用反射技術(shù)可以擴(kuò)充實(shí)現(xiàn)很多功能,它們被廣泛應(yīng)用于三大框架底層,需要的朋友可以參考下
    2023-05-05
  • 淺析java實(shí)現(xiàn)數(shù)據(jù)加密問題

    淺析java實(shí)現(xiàn)數(shù)據(jù)加密問題

    本文通過實(shí)例代碼給大家介紹了java實(shí)現(xiàn)數(shù)據(jù)加密問題,非常不錯(cuò),具有一定的參考借鑒價(jià)值,需要的朋友參考下吧
    2019-11-11
  • Spring Boot web項(xiàng)目的TDD流程

    Spring Boot web項(xiàng)目的TDD流程

    TDD(Test-driven development) 測試驅(qū)動(dòng)開發(fā),簡單點(diǎn)說就是編寫測試,再編寫代碼。這是首要一條,不可動(dòng)搖的一條,先寫代碼后寫測試的都是假TDD。
    2021-05-05
  • resty client使用Java客戶端來訪問Api

    resty client使用Java客戶端來訪問Api

    這篇文章主要介紹了resty-client使用Java客戶端來訪問Api的驗(yàn)證權(quán)限,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步
    2022-03-03
  • SpringCloud Stream消息驅(qū)動(dòng)實(shí)例詳解

    SpringCloud Stream消息驅(qū)動(dòng)實(shí)例詳解

    這篇文章主要介紹了SpringCloud Stream消息驅(qū)動(dòng)的相關(guān)知識,本文給大家介紹的非常詳細(xì),對大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下
    2021-03-03
  • Java多線程中不同條件下編寫生產(chǎn)消費(fèi)者模型方法介紹

    Java多線程中不同條件下編寫生產(chǎn)消費(fèi)者模型方法介紹

    這篇文章主要介紹了Java多線程中不同條件下編寫生產(chǎn)消費(fèi)者模型方法介紹,介紹了生產(chǎn)消費(fèi)者模型,然后分享了相關(guān)代碼示例,具有一定參考價(jià)值,需要的朋友可以了解下。
    2017-11-11
  • 深入探究一下Java中不同的線程間數(shù)據(jù)通信方式

    深入探究一下Java中不同的線程間數(shù)據(jù)通信方式

    這篇文章主要來和大家一起深入探究一下Java中不同的線程間數(shù)據(jù)通信方式,文中的示例代碼講解詳細(xì),具有一定的借鑒價(jià)值,需要的可以參考一下
    2023-04-04
  • java實(shí)現(xiàn)AES可逆加密算法

    java實(shí)現(xiàn)AES可逆加密算法

    這篇文章主要為大家詳細(xì)介紹了java實(shí)現(xiàn)AES可逆加密算法,具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下
    2019-03-03
  • Java數(shù)據(jù)結(jié)構(gòu)篇之實(shí)現(xiàn)二叉搜索樹的核心方法

    Java數(shù)據(jù)結(jié)構(gòu)篇之實(shí)現(xiàn)二叉搜索樹的核心方法

    二叉搜索樹是一種常用的數(shù)據(jù)結(jié)構(gòu),它是一棵二叉樹,且每個(gè)節(jié)點(diǎn)的值都大于其左子樹中任何節(jié)點(diǎn)的值,而小于其右子樹中任何節(jié)點(diǎn)的值,這篇文章主要給大家介紹了關(guān)于Java數(shù)據(jù)結(jié)構(gòu)篇之實(shí)現(xiàn)二叉搜索樹的核心方法,需要的朋友可以參考下
    2023-12-12
  • 70行Java代碼實(shí)現(xiàn)深度神經(jīng)網(wǎng)絡(luò)算法分享

    70行Java代碼實(shí)現(xiàn)深度神經(jīng)網(wǎng)絡(luò)算法分享

    這篇文章主要介紹了70行Java代碼實(shí)現(xiàn)深度神經(jīng)網(wǎng)絡(luò)算法分享,涉及神經(jīng)網(wǎng)絡(luò)的計(jì)算過程,神經(jīng)網(wǎng)絡(luò)的算法程序?qū)崿F(xiàn),多層神經(jīng)網(wǎng)絡(luò)完整程序?qū)崿F(xiàn)等相關(guān)內(nèi)容,具有一定參考價(jià)值,需要的朋友可以參考下。
    2017-11-11

最新評論