> SpringBoot在微服務上應用是越來越多,同樣教程也比較多,但是我相信會有人跟我一樣的迷惑,它的載入過程是什麼樣的,要經過哪些類,然後又為什麼會能直接把應用打包成jar/war,然後就可以直接運行。本次使用的SpringBoot版本1.5.2。 # 從快速啟動Demo中看載入過程 有很多人都下載了Springboot 版的eclipse,構建項目也比較方便,其實我感覺也挺好的,但是我習慣了用IDEA,所以這次就從官網上初始化一個新的項目 ## 準備快速啟動項目 ### 在官網初始化一個新的項目 ### 運行打包 為了給大家展示jar/war打包的內容,然後我打包了兩次,同時把相關的內容給大家貼出來。 war打完包的目錄結構 區別不大jar打包的時候是BOOT-INF放我們自己開發的代碼,war打包的時候是WEB-INF。 #### 我們先看打包的META-INF裡的MANIFEST.MF檔案。 > jar MANIFEST.MF ``` Manifest-Version: 1.0 Implementation-Title: demo Implementation-Version: 0.0.1-SNAPSHOT Archiver-Version: Plexus Archiver Built-By: angy Implementation-Vendor-Id: com.hiext Spring-Boot-Version: 1.5.2.RELEASE Implementation-Vendor: Pivotal Software, Inc. Main-Class: org.springframework.boot.loader.JarLauncher Start-Class: com.hiext.DemoApplication Spring-Boot-Classes: BOOT-INF/classes/ Spring-Boot-Lib: BOOT-INF/lib/ Created-By: Apache Maven 3.0.5 Build-Jdk: 1.8.0_111 Implementation-URL: http://projects.spring.io/spring-boot/authorizeServer/ `` ` > war MANIFEST.MF `` ` Manifest-Version: 1.0 Implementation-Title: demo Implementation-Version: 0.0.1-SNAPSHOT Archiver-Version: Plexus Archiver Built-By: angy Implementation-Vendor-Id: com.hiext Spring-Boot-Version: 1.5.2.RELEASE Implementation-Vendor: Pivotal Software, Inc. Main-Class: org.springframework.boot.loader.WarLauncher Start-Class: com.hiext.DemoApplication Spring-Boot-Classes: WEB-INF/classes/ Spring-Boot-Lib: WEB-INF/lib/ Created-By: Apache Maven 3.0.5 Build-Jdk: 1.8.0_111 Implementation-URL: http://projects.spring.io/spring-boot/authorizeServer/ ``` 從檔案的比較上來看載入的不同的類,然後SpringBoot的代碼也放在不同的位置。 #### 細說 MANIFEST.MF檔案 > 這個 manifest 檔案定義了與擴充和包相關的資料,是java打包必不可少的一個檔案。這個檔案也描述了jar包的一些很多資訊,主要分為一下幾類 * 1. 一般屬性 1. Manifest-Version
用來定義manifest檔案的版本,例如:Manifest-Version: 1.0
2. Created-By
聲明該檔案的產生者,一般該屬性是由jar命令列工具產生的,例如:Created-By: Apache Ant 1.5.1
3. Signature-Version
定義jar檔案的簽名版本
4. Class-Path
應用程式或者類裝載器使用該值來構建內部的類搜尋路徑 * 2. 應用程式相關屬性 * 3. 包擴充屬性 我們重點看應用程式相關的屬性,就是Main-class,這是jar的入口類,也就是要求這個類必須是可執行檔類。 一旦定義了該屬性即可通過 java -jar x.jar來運行該jar檔案。 Start-Class的配置就是我們自己寫的main函數了。 #### 其他檔案夾的介紹 BOOT-INF/WEB-INF 這裡放的是我們自己要寫開發的代碼然後編譯後的class與相關的jar等等。 org目錄裡放的是Springboot載入的class檔案。 送上連結 https://github.com/spring-projects/spring-boot/tree/master/spring-boot-tools/spring-boot-loader/src/main/java/org/springframework/boot/loader 對應的就是該目錄的源碼。 #####Archive的概念 * archive即歸檔檔案,這個概念在linux下比較常見 * 通常就是一個tar/zip格式的壓縮包 * jar是zip格式 在spring boot裡,抽象出了Archive的概念。 一個archive可以是一個jar(JarFileArchive),也可以是一個檔案目錄(ExplodedArchive)。可以理解為Spring boot抽象出來的統一訪問資源的層。 我們看下Archive這個介面的定義: ``` package org.springframework.boot.loader.archive; import java.io.IOException; import java.net.MalformedURLException; import java.net.URL; import java.util.List; import java.util.jar.Manifest; import org.springframework.boot.loader.Launcher; /** * An archive that can be launched by the {@link Launcher}. * * @author Phillip Webb * @see JarFileArchive */ public interface Archive extends Iterable<Archive.Entry> { /** * Returns a URL that can be used to load the archive. * @return the archive URL * @throws MalformedURLException if the URL is malformed */ URL getUrl() throws MalformedURLException; /** * Returns the manifest of the archive. * @return the manifest * @throws IOException if the manifest cannot be read */ Manifest getManifest() throws IOException; /** * Returns nested {@link Archive}s for entries that match the specified filter. * @param filter the filter used to limit entries * @return nested archives * @throws IOException if nested archives cannot be read */ List<Archive> getNestedArchives(EntryFilter filter) throws IOException; /** * Represents a single entry in the archive. */ interface Entry { /** * Returns {@code true} if the entry represents a directory. * @return if the entry is a directory */ boolean isDirectory(); /** * Returns the name of the entry. * @return the name of the entry */ String getName(); } /** * Strategy interface to filter {@link Entry Entries}. */ interface EntryFilter { /** * Apply the jar entry filter. * @param entry the entry to filter * @return {@code true} if the filter matches */ boolean matches(Entry entry); } } ``` > Archive的實現有兩個一個是 ExplodedArchive 一個是 JarFileArchive ,就是對應上面說的兩種訪問資源的形式 一種是檔案夾 一種是直接存取jar。從介面來看,每一個資源都有一個URL。 ```
jar:file:/C:/Users/angy/AppData/Local/Temp/junit7462285095317089505/archive.jar!/BOOT-INF/classes!/ jar: file:/C:/Users/angy/AppData/Local/Temp/junit7462285095317089505/archive.jar!/BOOT-INF/lib/foo.jar!/ ```