Spring Boot Executable jar/war 原理
spring boot executable jar/war
spring boot裡其實不僅可以直接以 java -jar demo.jar
的方式啟動,還可以把jar/war變為一個可以執行的指令碼來啟動,比如./demo.jar
。
把這個executable jar/war 連結到/etc/init.d
下面,還可以變為linux下的一個service。
只要在spring boot maven plugin
裡配置:
<plugin> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-maven-plugin</artifactId> <configuration> <executable>true</executable> </configuration> </plugin>
這樣子打包出來的jar/war就是可執行的。更多詳細的內容可以參考官方的文件。
http://docs.spring.io/spring-boot/docs/current/reference/htmlsingle/#deployment-install
zip格式裡的magic number
生成的jar/war實際上是一個zip格式的檔案,這個zip格式檔案為什麼可以在shell下面直接執行?
研究了下zip檔案的格式。zip檔案是由entry組成的,而每一個entry開頭都有一個4個位元組的magic number:
Local file header signature = 0x04034b50 (read as a little-endian number) 即 PK\003\004
參考:https://en.wikipedia.org/wiki/Zip_(file_format)
zip處理軟體是讀取到magic number才開始處理。所以在linux/unix下面,可以把一個bash檔案直接寫在一個zip檔案的開頭,這樣子會被認為是一個bash script。 而zip處理軟體在讀取這個檔案時,仍然可以正確地處理。
比如spring boot生成的executable jar/war,的開頭是:
#!/bin/bash # # . ____ _ __ _ _ # /\\ / ___'_ __ _ _(_)_ __ __ _ \ \ \ \ # ( ( )\___ | '_ | '_| | '_ \/ _` | \ \ \ \ # \\/ ___)| |_)| | | | | || (_| | ) ) ) ) # ' |____| .__|_| |_|_| |_\__, | / / / / # =========|_|==============|___/=/_/_/_/ # :: Spring Boot Startup Script :: #
在script內容結尾,可以看到zip entry的magic number:
exit 0
PK^C^D
spring boot的launch.script
實際上spring boot maven plugin是把下面這個script打包到fat jar的最前面部分。
這個launch.script 支援很多變數設定。還可以自動識別是處於auto
還是service
不同mode中。
所謂的auto mode
就是指直接執行jar/war:
./demo.jar
而service mode
則是由作業系統在啟動service的情況:
service demo start/stop/restart/status
所以fat jar可以直接在普通的命令列裡執行,./xxx.jar
或者link到/etc/init.d/
下,變為一個service。
總結
- jar/war實際就是zip格式
- spring-boot-maven-plugin把啟動指令碼打到executable jar/war的最前面
- 指令碼的最後一行是
exit 0
,指令碼只執行自己的內容,不會執行到jar/war裡的內容 - zip檔案由多個entry組成,entry的開頭有magic number,所以zip處理軟體可以跳過前面的指令碼,準確找到zip entry