首頁>技術>

1 靜態 main 方法與 JVM 程序的關係

在講解 SpringBoot 專案的啟動和執行之前,首先分析一下基於靜態 main 方法啟動執行 Java 類的相關知識,以便讀者能夠更好理解基於 SpringBoot 框架搭建的專案的啟動和執行方式。

1.1 基於靜態 main 方法執行 Java 類

​ Java 類的靜態 main 方法是每一個 Java 開發人員都再熟悉不過的一個方法,在進行 Java 應用程式開發,特別是 Java SE 應用程式開發時,一般都會在 Java 類定義一個靜態 main 方法來作為該類的執行入口。

​ 具體為在執行該 Java 類時,main 方法會被 JVM 呼叫,然後執行 main 方法內部的每一行程式碼,執行完畢之後,程式退出。如下為靜態 main 方法的定義:

public class MainDemo {    // 類執行入口    public static void main(String[] args) {        // 自定義需要執行的程式碼    }}

拓展知識:

Java 語言由於底層是基於 c 語言實現的,故在類的執行方面也仿照了 c 語言的習慣,使用一個名為 main 的方法來作為類的執行入口。

不過 Java 語言在具體設計方面結合了 Java 語言的相關特性,即 main 方法需要使用 static 關鍵字修飾來成為 Java 的類方法,從而實現了無需建立類的物件例項即可呼叫該 main 方法。

1.2 靜態 main 方法的定義

​ 該靜態 main 方法的返回型別為 void,引數為 String 字串陣列 args,該陣列代表該類的多個執行時引數,具體可以透過以下方式來傳遞:

java DemoMain 1 2 3

其中 java 為 Java 語言提供的執行類的命令,DemoMain 是以上類的類名,注意該類對應的 class 檔案需要在類路徑下,1,2,3 就是以上的 args 字串陣列的內容,即 args[0] = 1,args[1] = 2,args[2] = 3。

拓展知識:

注意 main 方法作為類的執行入口的以上兩個條件,即方法返回型別為 void,方法引數為 String 字串陣列是必須的,否則 Java 類在執行時無法將該方法作為執行入口。例如,如果返回型別為 int,或者方法引數為空,則該 main 方法只是一個普通的靜態方法,而不是該類的執行入口。

以上兩個條件都是 Java 語言自身的規範,只有符合規範才能被 JVM 識別和執行。

​ 除此之外, main 方法需要使用 static 關鍵字修飾來成為靜態方法的原因是:靜態方法也稱為類方法,即 main 方法是類物件的方法,而不是透過 new 關鍵字建立的類的物件例項的成員方法。

​ 由 JVM 類載入的相關知識可知,JVM 在執行過程中,當需要使用某個類的時候,如訪問該類的靜態屬性時(或者類的靜態方法,或者建立該類的物件例項),需要將該類的 class 檔案的二進位制資料載入到 JVM 的執行時資料區的方法區中,並且會建立對應的型別為 java.lang.Class 的類物件。之後就可以使用該類物件來訪問該類的相關資訊,如類的靜態屬性等。

​ 所以當透過 java 命令來執行某個類時,首先會建立一個 JVM 程序,然後載入該類的二進位制資料到 JVM 的方法區並建立型別為 java.lang.Class 的類物件。接著在該 JVM 程序的主執行緒中會透過該類物件來呼叫該類的 main 方法,從而完成類的執行。當 執行完 main 方法的所有程式碼,則方法呼叫結束,JVM 程序退出。

tips:不過如果在 main 方法內,存在讓主執行緒阻塞等待的方法呼叫的話,則 JVM 程序會繼續保持執行狀態而不會退出,這也是 SpringBoot 框架基於 main 方法來啟動 JVM 程序並保持該程序執行而不退出的實現原理。

2 SpringBoot專案的啟動與執行

​ SpringBoot 框架的一個核心設計就是基於 main 方法來獨立啟動一個 JVM 程序來執行應用,而不需要將應用打 包為 war 包並部署到 Tomcat 去執行。這種設計簡化了基於 SpringBoot 搭建的專案的部署和執行流程,使得 Java 企業級應用迴歸了最原始、最簡單、但又是最高效的執行模式。

​ 所以基於 SpringBoot 框架搭建專案時,會在應用程式碼目錄 java 的頂層包路徑下包含一個名稱類似於 XXXApplication 的專案啟動類,其中 XXX 是專案名稱。如下是在上一小節介紹的 demo 專案中,由 SpringBoot 框架自動建立的的專案啟動類 DemoApplication 的原始碼:

package com.yzxie.study.demo;import org.springframework.boot.SpringApplication;import org.springframework.boot.autoconfigure.SpringBootApplication;@SpringBootApplicationpublic class DemoApplication {   public static void main(String[] args) {      SpringApplication.run(DemoApplication.class, args);   }}

​ 由以上原始碼實現可知,在 DemoApplication 類的執行入口方法 main 中只包含了一行程式碼,即呼叫由 SpringBoot 框架提供的 SpringApplication 類的靜態方法 run 來完成 SpringBoot 框架的啟動與執行。

拓展知識:

SpringApplication 的靜態 run 方法的核心工作包括:在內部完成 Spring IOC 容器的載入和相關 bean 物件的建立,完成 Servlet 引擎的載入與在指定埠監聽客戶端的連線請求,使得該 JVM 程序的主執行緒阻塞不退出,保持執行狀態,從而實現與傳統的、將專案打 war 包部署到 Tomcat 去執行一樣的效果。關於 SpringApplication 類的相關用法與設計原理的更多知識在後續章節詳細分析。

​ 由以上 1.1 部分的分析可知,當需要啟動和執行專案時,可以使用 java 命令來啟動和執行專案啟動類,如 demo 專案的 DemoApplicatiion 。

​ 不過與執行單個 Java 類不一樣,在命令列使用 java 命令啟動專案時,首先需要將整個專案打成一個 jar 包,然後將該 jar 包新增到系統的類路徑,或者在 java 命令中指定該 jar 包所在的類路徑,最後在 java 命令中指定需要執行的 Java 類名,如 DemoApplication,完成啟動和執行該類。

tips:Java 命令執行 Java 類的工作原理為首先建立一個 JVM 程序,然後在主執行緒中呼叫 main 方法來完成類的執行。其中將專案打成 jar 包並使用 java 命令來在命令列啟動和執行專案是 Java 企業級專案在 Linux 伺服器部署的常用方式。

3 總結

​ 在本小節我們首先介紹了 Java 語言最原始的基於靜態 main 方法來執行 Java 類的相關用法和工作原理,以及分析了 main 方法定義的相關規範。具體為 main 方法要符合是靜態方法,方法返回值為 void,方法引數為 String 陣列這三個條件,只有這樣才能被 JVM 程序識別為執行入口方法並進行呼叫。

​ 其次我們分析了 SpringBoot 應用的啟動執行方式,即基於 SpringBoot 搭建的專案迴歸了基於 main 方法啟動執行的方式,從而實現了以獨立 JVM 程序來啟動和執行專案,而不需要依賴額外部署的 Tomcat,這極大簡化了 Spring 應用的部署和執行流程。

4
  • BSA-TRITC(10mg/ml) TRITC-BSA 牛血清白蛋白改性標記羅丹明
  • const關鍵字:終於擁有真正的常量宣告語句