亚洲激情专区-91九色丨porny丨老师-久久久久久久女国产乱让韩-国产精品午夜小视频观看

溫馨提示×

溫馨提示×

您好,登錄后才能下訂單哦!

密碼登錄×
登錄注冊×
其他方式登錄
點擊 登錄注冊 即表示同意《億速云用戶服務條款》

SpringBoot的jar包怎么啟動

發布時間:2022-03-21 09:12:28 來源:億速云 閱讀:559 作者:小新 欄目:開發技術

這篇文章主要介紹了SpringBoot的jar包怎么啟動,具有一定借鑒價值,感興趣的朋友可以參考下,希望大家閱讀完這篇文章之后大有收獲,下面讓小編帶著大家一起了解一下。

    一、簡介

    使用過SprongBoot打過jar包的都應該知道,目標文件一般都會生成兩個文件,一個是以.jar的包,一個是.jar.original文件。那么使用SpringBoot會打出兩個包,而.jar.original的作用是什么呢?還有就是java -jar是如何將一個SpringBoot項目啟動,之間都進行了那些的操作?

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

    二、jar包的內部結構

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

    • BOOT-INF:這個文件夾下有兩個文件夾classes用來存放用戶類,也就是原始jar.original里的類;還有一個是lib,就是這個原始jar.original引用的依賴。

    • META-INF:這里是通過java -jar啟動的入口信息,記錄了入口類的位置等信息。

    • org:Springboot loader的代碼,通過它來啟動。

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

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

    Main-Class:記錄了java -jar的啟動入口,當使用該命令啟動時就會調用這個入口類的main方法,顯然可以看出,Springboot轉移了啟動的入口,不是用戶編寫的xxx.xxx.BootStrap的那個入口類。

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

    三、加載過程

    1.使用到的一些類

    3.1.1 Archive

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

    SpringBoot的jar包怎么啟動

    3.1.2 Launcher

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

    SpringBoot的jar包怎么啟動

    3.1.3 Spring.loader下的JarFile和JarEntry

    jarFile繼承于jar.util.jar.JarFileJarEntry繼承于java.util.jar.JarEntry,對原始的一些方法進行重寫覆蓋。每一個JarFileArchive都擁有一個JarFile方法,用于存儲這個jar包對應的文件,而每一個JarFile都有一個JarFileEntries,JarFileEntries是一個迭代器。總的來說,在解析jar包時,會將jar包內的文件封裝成JarEntry對象后由JarFile對象保存文件列表的迭代器。所以JarFileArchiveJarFileEntries之間是通過JarFile連接,二者都可以獲取到JarFile對象。

    2.過程分析

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

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

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

    JarLauncher的空構造方法時一個空實現,剛開始看的時候還懵了一下,以為是在后續的操作中去加載的文件,其實不然,在創建時由父類ExecutableArchiveLauncher的構造方法去加載的文件。

    加載為歸檔文件對象:

    this.archive = createArchive();

    具體的加載方法:判斷路徑是否是一個文件夾,是則返回ExplodedArchive對象,否則返回JarFileArchive 進入JarFileArchive類:通過這個new方法創建JarFile對象

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

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

    public class JarFile extends java.util.jar.JarFile {
    
      public JarFile(File file) throws IOException {
        this(new RandomAccessDataFile(file));
      }
    }

    進入jarLauncherlaunch方法:注冊URL協議的處理器,沒有指定時,默認指向org.springframework.boot.loader包路徑,獲取類路徑下的歸檔文件Archive并通過這些歸檔文件的URL,創建線程上下文類加載器,使用類加載器和用戶編寫的啟動入口類,通過反射調用它的main方法。

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

    JarLaunchergetClassPathArchives是在ExecutableArchiveLauncher中實現:獲取歸檔文件中滿足EntryFilterg過濾器的項,isNestedArchive方法由具體的之類實現。獲取到當前歸檔文件下的所有子歸檔文件之后的后置操作,是一個擴展點。在JarLauncher中是一個空實現。

    JarLauncher的具體實現,這里通過判斷是否在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方法:若匹配器匹配到則獲取內嵌歸檔文件。

    具體的獲取內嵌歸檔文件邏輯:根據具體的Entry對象,創建JarFile對象并封裝成歸檔文件對象后返回。

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

    獲取到參數entry對應的RandomAccessData對象,這里根據springboot擴展的url協議,在父路徑的基礎上添加!/來標記子包。

    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內部信息,加載為對應歸檔文件對象的大概過程已經講完了,接下來分析一下在獲取到了整個jar的歸檔文件對象后的處理。

    通過歸檔文件對象列表,獲取對應的url信息,并通過url信息創建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()]));
    }

    獲取到對應的LaunchedUrlClassLoader類加載器之后,設置線程的上下文類加載器為該加載器。根據MANIFI.MF文件中的start-classs信息創建項目啟動入口主類對象,并通過返回對象的run方法啟動

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

    進入MainMethodRunnerrun方法:先通過當前線程獲取到main入口類,然后通過反射調用啟動項目啟動類的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 });
    }

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

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

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

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

    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);
            }
          }
        }
      }

    感謝你能夠認真閱讀完這篇文章,希望小編分享的“SpringBoot的jar包怎么啟動”這篇文章對大家有幫助,同時也希望大家多多支持億速云,關注億速云行業資訊頻道,更多相關知識等著你來學習!

    向AI問一下細節

    免責聲明:本站發布的內容(圖片、視頻和文字)以原創、轉載和分享為主,文章觀點不代表本網站立場,如果涉及侵權請聯系站長郵箱:is@yisu.com進行舉報,并提供相關證據,一經查實,將立刻刪除涉嫌侵權內容。

    AI

    诸暨市| 仪征市| 建德市| 万载县| 阜新市| 鲜城| 吉水县| 彩票| 启东市| 昌乐县| 新蔡县| 浦北县| 理塘县| 东乡族自治县| 阿拉善盟| 左权县| 连江县| 荆州市| 胶州市| 宁海县| 和林格尔县| 磐安县| 阿拉善右旗| 正蓝旗| 海淀区| 墨脱县| 兴国县| 河曲县| 巫山县| 阜阳市| 图们市| 乐都县| 芜湖县| 扎囊县| 安徽省| 当雄县| 太仆寺旗| 苍溪县| 故城县| 西峡县| 东乡族自治县|