Springboot可以說是Java程式設計師必備技能了,大家都知道Springboot最後可以透過maven打成jar包,然後直接使用java -jar
指令運行一個Web工程(或其它)。這樣就避免了原先基於tomcat的web工程的複雜操作。 Springboot能夠讓Web服務的部署變得簡單到如此程度是因為其內建了Jetty(或Tomcat)伺服器,並且在容器啟動過程中start該伺服器,成功運行Web服務。
相信各位Springbooter一定不會陌生下面的程式碼,無論是初學Springboot的新同學,或是開始研究Springboot原始碼的新司機,這段程式碼幾乎是我們的落腳點。我們如此熟悉它,以至於認為它就是Springboot這個魔法樂園的起點。但真的是這樣嗎?
@SpringBootApplication public class Springboot01helloworldApplication { public static void main(String[] args) { SpringApplication.run(Springboot01helloworldApplication.class, args); } }
我們都知道,一個Java工程打包過後,這個jar包的入口描述被寫在了/META-INF/MANIFEST.MF
文件下,下面讓我們來看看這個檔案內容:
Manifest-Version: 1.0 Archiver-Version: Plexus Archiver Built-By: MrXu Start-Class: com.vivo.internet.nex.repeater.console.RepeaterConsoleApplication Spring-Boot-Classes: BOOT-INF/classes/ Spring-Boot-Lib: BOOT-INF/lib/ Spring-Boot-Version: 1.5.19.RELEASE Created-By: Apache Maven 3.8.1 Build-Jdk: 1.8.0_281 Main-Class: org.springframework.boot.loader.JarLauncher
檔案入口的描述為Main-Class對應的value,即org.springframework.boot.loader.JarLauncher
。那麼,接下來我們需要看看這個類別究竟做了什麼?
// JarLauncher.java public class JarLauncher extends ExecutableArchiveLauncher { static final String BOOT_INF_CLASSES = "BOOT-INF/classes/"; static final String BOOT_INF_LIB = "BOOT-INF/lib/"; public JarLauncher() { } // ...省略无关代码 public static void main(String[] args) throws Exception { (new JarLauncher()).launch(args); } }
明顯的main函數吸引了我們的注意,沒錯了,這就是入口,看看JarLauncher的空構造並沒有任何程式碼,我們先往它的父類找找:
// ExecutableArchiveLauncher.java public abstract class ExecutableArchiveLauncher extends Launcher { public ExecutableArchiveLauncher() { try { this.archive = this.createArchive(); } catch (Exception var2) { throw new IllegalStateException(var2); } } // ...省略 } // Launcher.java public abstract class Launcher { public Launcher() {} // ...省略无关代码 }
從程式碼中可以看出,真正做了事情的父類別是ExecutableArchiveLauncher
,它在初始化時建構了archive實例,該實例封裝了/META-INF/MANIFEST.MF
文件的資訊。後面我們也會用到它。
這裡先呼叫子類別ExecutableArchiveLauncher的getMainClass方法,主要邏輯就是從
/META-INF/MANIFEST. MF檔案中取得Start-Class訊息,對應上文就是com.vivo.internet.nex.repeater.console.RepeaterConsoleApplication
字串,這樣就和我們寫的啟動類別關聯上了。 接著是launch方法的具體執行,launch()先建立一個MainMethodRunner,將上述所取得的Start-Class和透傳的參數傳遞進去,然後呼叫MainMethodRunner的run方法。 run方法的執行也非常簡單,就是載入Start-Class對應的啟動類,然後反射呼叫啟動類別的main方法。之後就是容器的初始化過程了。
// Launcher.java protected void launch(String[] args) throws Exception { JarFile.registerUrlProtocolHandler(); ClassLoader classLoader = this.createClassLoader(this.getClassPathArchives()); this.launch(args, this.getMainClass(), classLoader); } // ExecutableArchiveLauncher.java protected String getMainClass() throws Exception { Manifest manifest = this.archive.getManifest(); String mainClass = null; if (manifest != null) { mainClass = manifest.getMainAttributes().getValue("Start-Class"); } if (mainClass == null) { throw new IllegalStateException("No 'Start-Class' manifest entry specified in " + this); } else { return mainClass; } }
以上是SpringBoot應用的啟動入口怎麼封裝的詳細內容。更多資訊請關注PHP中文網其他相關文章!