SpringBoot Jar包啟動原理

前言

通過java -jar xxx.jar這個啟動java程序的套路是Jar包本來就有的特性,sb只是利用了這個強(qiáng)大的功能簡化了應(yīng)用的啟動。

MANIFEST.MF

MANIFEST.MF在jar包的META-INF文件夾下,通過jar包啟動應(yīng)用的配置就在這個文件里面。下面看下我的一個sb應(yīng)用的該文件內(nèi)容

Manifest-Version: 1.0
Implementation-Title: demo
Implementation-Version: 0.0.1-SNAPSHOT
Start-Class: com.example.demo.DemoApplication
Spring-Boot-Classes: BOOT-INF/classes/
Spring-Boot-Lib: BOOT-INF/lib/
Build-Jdk-Spec: 1.8
Spring-Boot-Version: 2.1.5.RELEASE
Created-By: Maven Archiver 3.4.0
Main-Class: org.springframework.boot.loader.JarLauncher

MANIFEST.MF中配置分成兩部分,自定義屬性和非自定義屬性。

非自定義屬性就是MANIFEST.MF這個文件中規(guī)定的一些特定屬性束倍,上面的Manifest-Version,Implementation-Title,Implementation-Version绪妹,Created-By甥桂,Main-Class都是

而自定義屬性,就是自己隨便取名的屬性邮旷,比如Start-Class黄选,Spring-Boot-Classes,Spring-Boot-Lib

其中非自定義屬性Main-Class十分重要婶肩,java -jar xxx.jar就是從這個屬性對應(yīng)class的main作為入口啟動應(yīng)用的办陷。

但是我們使用maven插件打包的時候配置的main-class其實(shí)對應(yīng)的Start-Class這個配置,為什么要這樣呢律歼?因?yàn)橐粋€應(yīng)用啟動還需要用類加載器加載一些其他資源比如jar包以及應(yīng)用自己的class類民镜,所以Main-Class就做了這些事情。

sb jar包內(nèi)容一覽

--META-INF
----MANIFEST.MF
----maven
------com.example
--------demo
----------pom.xml
----------pom.properties
--listfile.py
--test.jar
--BOOT-INF
----classes
------com
--------example
----------demo
------------DemoApplication.class
------application.properties
----lib
------tomcat-embed-websocket-9.0.19.jar
------jackson-databind-2.9.8.jar
------jackson-core-2.9.8.jar
...
--org
----springframework
------boot
--------loader
----------archive
----------JarLauncher.class
...

通過java -cvf xx.jar解壓jar包后會得到以上格式的文件目錄险毁,分為三個文件夾

文件夾 作用
META-INF 一些配置文件制圈,MANIFEST.MF就在這里
BOOT-INF 子文件class存儲應(yīng)用類,lib存儲第三方j(luò)ar包
org main-class對應(yīng)的JarLauncher在這里畔况,這邊的類用于sb應(yīng)用啟動

一些源碼

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() {
    }

    protected JarLauncher(Archive archive) {
        super(archive);
    }

    protected boolean isNestedArchive(Entry entry) {
        return entry.isDirectory() ? entry.getName().equals("BOOT-INF/classes/") : entry.getName().startsWith("BOOT-INF/lib/");
    }

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

jar包通過JarLauncher的main方法啟動鲸鹦,我們看到這里就一行代碼

(new JarLauncher()).launch(args);

這行代碼對應(yīng)2個邏輯

  1. 初始化包換三方j(luò)ar包和當(dāng)前應(yīng)用的class文件的類加載器
  2. 啟動我們配置的SpringApplication

new JarLauncher()負(fù)責(zé)加載我們當(dāng)前這個jar包,launch負(fù)責(zé)執(zhí)行以上兩個邏輯跷跪。
JarLauncher默認(rèn)構(gòu)造函數(shù)實(shí)現(xiàn)為空亥鬓,它父類ExecutableArchiveLauncher會調(diào)用再上一級父類Launcher的createArchive方法加載jar包

public JarLauncher() {
    }
public ExecutableArchiveLauncher() {
        try {
            this.archive = this.createArchive();
        } catch (Exception var2) {
            throw new IllegalStateException(var2);
        }
    }
protected final Archive createArchive() throws Exception {
        ProtectionDomain protectionDomain = this.getClass().getProtectionDomain();
        CodeSource codeSource = protectionDomain.getCodeSource();
        URI location = codeSource != null ? codeSource.getLocation().toURI() : null;
        String path = location != null ? location.getSchemeSpecificPart() : null;
        if (path == null) {
            throw new IllegalStateException("Unable to determine code source archive");
        } else {
            File root = new File(path);
            if (!root.exists()) {
                throw new IllegalStateException("Unable to determine code source archive from " + root);
            } else {
                return (Archive)(root.isDirectory() ? new ExplodedArchive(root) : new JarFileArchive(root));
            }
        }
    }

加載了jar包之后,我們就能獲得它里面所有的資源域庇,也就是上一節(jié)列出的那些文件。

launch的實(shí)現(xiàn)在父類Launcher中

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

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

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

不多做解釋覆积,上面的代碼很清晰的展示了launch方法的邏輯听皿,通過createClassLoader構(gòu)造類加載器,通過this.createMainMethodRunner(mainClass, args, classLoader).run()啟動我們的sb應(yīng)用宽档。

參考

MANIFEST.MF詳解及配置的注意事項(xiàng)
python格式化輸出文件夾下所有文件

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末尉姨,一起剝皮案震驚了整個濱河市,隨后出現(xiàn)的幾起案子吗冤,更是在濱河造成了極大的恐慌又厉,老刑警劉巖,帶你破解...
    沈念sama閱讀 206,311評論 6 481
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件椎瘟,死亡現(xiàn)場離奇詭異覆致,居然都是意外死亡,警方通過查閱死者的電腦和手機(jī)肺蔚,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 88,339評論 2 382
  • 文/潘曉璐 我一進(jìn)店門煌妈,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人,你說我怎么就攤上這事璧诵√” “怎么了?”我有些...
    開封第一講書人閱讀 152,671評論 0 342
  • 文/不壞的土叔 我叫張陵之宿,是天一觀的道長族操。 經(jīng)常有香客問我,道長比被,這世上最難降的妖魔是什么色难? 我笑而不...
    開封第一講書人閱讀 55,252評論 1 279
  • 正文 為了忘掉前任,我火速辦了婚禮姐赡,結(jié)果婚禮上莱预,老公的妹妹穿的比我還像新娘。我一直安慰自己项滑,他們只是感情好依沮,可當(dāng)我...
    茶點(diǎn)故事閱讀 64,253評論 5 371
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著枪狂,像睡著了一般危喉。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上州疾,一...
    開封第一講書人閱讀 49,031評論 1 285
  • 那天辜限,我揣著相機(jī)與錄音,去河邊找鬼严蓖。 笑死薄嫡,一個胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的颗胡。 我是一名探鬼主播毫深,決...
    沈念sama閱讀 38,340評論 3 399
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼毒姨!你這毒婦竟也來了哑蔫?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 36,973評論 0 259
  • 序言:老撾萬榮一對情侶失蹤弧呐,失蹤者是張志新(化名)和其女友劉穎闸迷,沒想到半個月后,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體俘枫,經(jīng)...
    沈念sama閱讀 43,466評論 1 300
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡腥沽,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 35,937評論 2 323
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發(fā)現(xiàn)自己被綠了崩哩。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片巡球。...
    茶點(diǎn)故事閱讀 38,039評論 1 333
  • 序言:一個原本活蹦亂跳的男人離奇死亡言沐,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出酣栈,到底是詐尸還是另有隱情险胰,我是刑警寧澤,帶...
    沈念sama閱讀 33,701評論 4 323
  • 正文 年R本政府宣布矿筝,位于F島的核電站起便,受9級特大地震影響,放射性物質(zhì)發(fā)生泄漏窖维。R本人自食惡果不足惜榆综,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 39,254評論 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望铸史。 院中可真熱鬧鼻疮,春花似錦、人聲如沸琳轿。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,259評論 0 19
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽崭篡。三九已至挪哄,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間琉闪,已是汗流浹背迹炼。 一陣腳步聲響...
    開封第一講書人閱讀 31,485評論 1 262
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留颠毙,地道東北人斯入。 一個月前我還...
    沈念sama閱讀 45,497評論 2 354
  • 正文 我出身青樓,卻偏偏與公主長得像蛀蜜,于是被迫代替她去往敵國和親咱扣。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 42,786評論 2 345

推薦閱讀更多精彩內(nèi)容