相對於傳統的JAVA可執行包(jar檔案),SpringBoot的包結構有比較大的不一樣。標準的JDK定義的jar檔案裡面是不能夠有內嵌jar檔案的,所以通常我們在執行一個jar檔案裡面的應用程式時,還需要通過-classpath來告訴JDK這個jar所依賴的所有的jar檔案資訊。而SpringBoot的build出來的包則允許將所有依賴的包打包到同一個jar裡面,就是jar裡面有jar,原因是spring-boot-loader重寫了ClassLoader。
下面的SpringBoot官方文檔對此行為的描述。
https://docs.spring.io/spring-boot/docs/current/reference/html/executable-jar.html
簡單來說
JAR檔案的結構
example.jar | +-META-INF | +-MANIFEST.MF +-org | +-springframework | +-boot | +-loader | +-<spring boot loader classes> +-BOOT-INF +-classes | +-mycompany | +-project | +-YourClasses.class +-lib +-dependency1.jar +-dependency2.jar
其中SpringBoot提供的bootstrap的類是放到包的最外面,比如上面的org.springframework.boot.loader。 應用程式自己的代碼則是需要放到BOOT-INF/classes目錄下面;然後應用程式自己依賴的其它的jar檔案則需要放到BOOT-INF/lib目錄下。
當這個jar作為standardalone的程式運行時(沒有放到container),SpringBoot會在產生的META-INF/MANIFEST.MF裡面將Main-Class設定成org.springframework.boot.loader.JarLauncher,JarLauncher類會建立一個spring自己的ClassLoader: LaunchedURLClassLoader, 這個classloader 會就能通過URL來載入上面BOOT-INF/lib裡面所依賴的包,並且通過反射Manifest裡面的Start-Class裡面定義的類,然後invoke這個類裡面的main方法。
Manifest-Version: 1.0
Spring-Boot-Classes: BOOT-INF/classes/
Implementation-Title: gs-rest-service
Implementation-Version: 0.1.0
Built-By: elichon
Start-Class: hello.Application
Created-By: Apache Maven 3.3.9
Implementation-URL: http://projects.spring.io/spring-boot/gs-rest-serv
ice/
Implementation-Vendor: Pivotal Software, Inc.
Implementation-Vendor-Id: org.springframework
Build-Jdk: 1.7.0_79
Spring-Boot-Lib: BOOT-INF/lib/
Spring-Boot-Version: 1.5.3.RELEASE
Main-Class: org.springframework.boot.loader.JarLauncher
Archiver-Version: Plexus Archiver
WAR檔案的結構
example.war | +-META-INF | +-MANIFEST.MF +-org | +-springframework | +-boot | +-loader | +-<spring boot loader classes> +-WEB-INF +-classes | +-com | +-mycompany | +-project | +-YourClasses.class +-lib | +-dependency1.jar | +-dependency2.jar +-lib-provided +-servlet-api.jar +-dependency3.jar
同樣的,當用spring-boot來運行一個war包時,應當把依賴包放到WEB-INF/lib目錄。然後對於應用程式依賴的jar,但傳統的web container會提供的JAR,但需要把它們放到WEB-INF/lib-provided。這樣就可以以下面的方式來啟動這個war了: jar -jar example.war。