Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

SpringBoot在命令行是如何启动的? #11

Open
bitfishxyz opened this issue Aug 8, 2019 · 0 comments
Open

SpringBoot在命令行是如何启动的? #11

bitfishxyz opened this issue Aug 8, 2019 · 0 comments
Labels
SpringBoot SpringBoot

Comments

@bitfishxyz
Copy link
Member

SpringBoot在命令行是如何启动?

假设这是一个简单的SpringBoot应用程序

我们要是想启动它,一般需要两个步骤:

  • 打包成jar文件
  • 运行jar文件

具体来说就是这样的

# 打包成单独的jar文件
$ mvn package

20190627231420

# 运行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这个文件夹。这里文件夹里面又有两个文件夹classeslib。可以看到,class文件夹就是存放我们的源代码编译后的class文件,
lib文件夹存放的是我们依赖的jar包,包括我们的tomcat
也被打包到这个文件夹了。

那么METE-INFO这个文件夹是做什么的呢?

这里就需要补充一个额外的知识了:

根据java规范和jar规范,当我们执行jar -jar xx.jar的时候,
它会寻找jar包里面的META-INFO/MANIFEST.MF文件,并读取Main-Class这个字段。

在我们的项目中,它就是
20190628080913

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的时候
发生了什么?

这里我们查看一下官方文档

https://docs.spring.io/spring-boot/docs/current/reference/htmlsingle/#executable-jar-launcher-manifest

请读者自行点击查看。

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,可以让我们非常方便的部署,不需要再手动的管理源代码和依赖的文件,大大方便了我们的开发。

@bitfishxyz bitfishxyz added the SpringBoot SpringBoot label Aug 8, 2019
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
SpringBoot SpringBoot
Projects
None yet
Development

No branches or pull requests

1 participant