-
Notifications
You must be signed in to change notification settings - Fork 0
Description
SpringBoot在命令行是如何启动?
假设这是一个简单的SpringBoot应用程序
我们要是想启动它,一般需要两个步骤:
- 打包成jar文件
- 运行jar文件
具体来说就是这样的
# 打包成单独的jar文件
$ mvn package# 运行jar文件
$ java -jar target/standalone-0.0.1-SNAPSHOT.jar
. ____ _ __ _ _
/\\ / ___'_ __ _ _(_)_ __ __ _ \ \ \ \
( ( )\___ | '_ | '_| | '_ \/ _` | \ \ \ \
\\/ ___)| |_)| | | | | || (_| | ) ) ) )
' |____| .__|_| |_|_| |_\__, | / / / /
=========|_|==============|___/=/_/_/_/
:: Spring Boot :: (v2.1.6.RELEASE)
2019-06-27 23:15:12.965 INFO 93939 --- [ main] c.g.c.standalone.StandaloneApplication : Starting StandaloneApplication v0.0.1-SNAPSHOT on appledeiMac.local with PID 93939 (/Users/apple/Downloads/x1hnd1rk/hello-springboot/target/standalone-0.0.1-SNAPSHOT.jar started by apple in /Users/apple/Downloads/x1hnd1rk/hello-springboot)
...
...那么问题来了,java -jar xx.jar的时候,到底发生了什么?为什么
我们的程序就启动了呢?
jar文件内容
首先我们来解压一下打包后的文件,来看看到底是什么东西。
jar文件都是通过zip格式来压缩的,所以解压jar包等于解压zip文件。
凡是可以解压zip文件的工具,都可以解压jar文件。
$ unzip target/standalone-0.0.1-SNAPSHOT.jar -d temp
$ tree ./temp -L 2
./temp
├── BOOT-INF
│ ├── classes
│ └── lib
├── META-INF
│ ├── MANIFEST.MF
│ └── maven
└── org
└── springframework
$ tree ./temp
./temp
├── BOOT-INF
│ ├── classes
│ │ ├── application.properties
│ │ └── com
│ │ └── github
│ │ └── codeman
│ │ └── standalone
│ │ └── StandaloneApplication.class
│ └── lib
│ ├── classmate-1.4.0.jar
│ ├── hibernate-validator-6.0.17.Final.jar
....
├── META-INF
│ ├── MANIFEST.MF
│ └── maven
│ └── com.github.codeman
│ └── standalone
│ ├── pom.properties
│ └── pom.xml
└── org
└── springframework
└── boot
└── loader
├── ExecutableArchiveLauncher.class
├── JarLauncher.class
...
到了这一步骤,请读者在自己的计算机上尝试一下。
我们可以看到有三个文件夹。
首先来看看BOOT-INF这个文件夹。这里文件夹里面又有两个文件夹classes和lib。可以看到,class文件夹就是存放我们的源代码编译后的class文件,
而lib文件夹存放的是我们依赖的jar包,包括我们的tomcat
也被打包到这个文件夹了。
那么METE-INFO这个文件夹是做什么的呢?
这里就需要补充一个额外的知识了:
根据java规范和jar规范,当我们执行jar -jar xx.jar的时候,
它会寻找jar包里面的META-INFO/MANIFEST.MF文件,并读取Main-Class这个字段。
org.springframework.boot.loader.JarLauncher
也就是说,java -jar target/standalone-0.0.1-SNAPSHOT.jar
等同java org.springframework.boot.loader.JarLauncher
口说无凭,我们来试一下:
$ cd temp
$ java org.springframework.boot.loader.JarLauncher
. ____ _ __ _ _
/\\ / ___'_ __ _ _(_)_ __ __ _ \ \ \ \
( ( )\___ | '_ | '_| | '_ \/ _` | \ \ \ \
\\/ ___)| |_)| | | | | || (_| | ) ) ) )
' |____| .__|_| |_|_| |_\__, | / / / /
=========|_|==============|___/=/_/_/_/
:: Spring Boot :: (v2.1.6.RELEASE)
2019-06-28 08:14:01.518 INFO 95178 --- [ main] c.g.c.standalone.StandaloneApplication : Starting StandaloneApplication on appledeiMac.local with PID 95178 (/Users/apple/Downloads/x1hnd1rk/hello-springboot/temp/BOOT-INF/classes started by apple in /Users/apple/Downloads/x1hnd1rk/hello-springboot/temp)
2019-06-28 08:14:01.521 INFO 95178 --- [ main] c.g.c.standalone.StandaloneApplication : No active profile set, falling back to default profiles: default
...
...可以看到,程序确实也可以通过这个方式来启动。
JarLauncher
可以现在新的问题又来了,java org.springframework.boot.loader.JarLauncher的时候
发生了什么?
这里我们查看一下官方文档
请读者自行点击查看。
org.springframework.boot.loader.JarLauncher
会作为一个引导类了,它会启动META-INF/MANIFEST.MF中
Start-Class中定义的类。
在我们这个项目中,它的值就是com.github.codeman.standalone.StandaloneApplication
可以看到这就是我们自己编写的项目的入口文件。
那么我们来手动的启动下
$ java -classpath "temp/BOOT-INF/classes:temp/BOOT-INF/lib/*" com.github.codeman.standalone.StandaloneApplication
. ____ _ __ _ _
/\\ / ___'_ __ _ _(_)_ __ __ _ \ \ \ \
( ( )\___ | '_ | '_| | '_ \/ _` | \ \ \ \
\\/ ___)| |_)| | | | | || (_| | ) ) ) )
' |____| .__|_| |_|_| |_\__, | / / / /
=========|_|==============|___/=/_/_/_/
:: Spring Boot :: (v2.1.6.RELEASE)
2019-06-27 23:43:25.117 INFO 94198 --- [ main] c.g.c.standalone.StandaloneApplication : Starting StandaloneApplication on appledeiMac.local with PID 94198 (/Users/apple/Downloads/x1hnd1rk/hello-springboot/temp/BOOT-INF/classes started by apple in /Users/apple/Downloads/x1hnd1rk/hello-springboot)
...
...可以看到,我们的程序也可以运行。
所以有下面的推论
jar -jar xx.jar 等于 java org.springframework.boot.loader.JarLauncher 等于 java -classpath "BOOT-INF/classes:BOOT-INF/lib/*" com.github.codeman.standalone.StandaloneApplication
至于我们的
@Controller
@SpringBootApplication
public class StandaloneApplication {
public static void main(String[] args) {
SpringApplication.run(StandaloneApplication.class, args);
}
}发生了什么?这是一个非常大的主题,我会在以后和大家讨论。这里就忽略了。
我们可以,SpringBoot把项目和依赖都打包从一个单独的
jar,可以让我们非常方便的部署,不需要再手动的管理源代码和依赖的文件,大大方便了我们的开发。


