Skip to content

Instantly share code, notes, and snippets.

@codeman688
Created June 28, 2019 01:24
Show Gist options
  • Save codeman688/852e6ea229f22eeabb9019c2dbfaf03e to your computer and use it in GitHub Desktop.
Save codeman688/852e6ea229f22eeabb9019c2dbfaf03e to your computer and use it in GitHub Desktop.

How does SpringBoot start on the command line?

Suppose this is a simple SpringBoot application

20190627231420

If we want to start it, we usually need two steps:

  • Package it into a jar file
  • Run this jar file

Specifically, it is like this

# Packaged into a separate jar file
$ mvn package

20190627231420

# Run this jar file
$ 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)
...
...

Then the question comes, what happened in the java -jar xx.jar? Why is our program started?

The contents of the jar file

First, let's unpack the packaged file to see what it is.

The jar files are compressed by the zip format, so extracting the jar package is equivalent to extracting the zip file. Any tool that can extract the zip file can extract the jar file.

$ unzip target/standalone-0.0.1-SNAPSHOT.jar -d temp

$ 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
                ...

At this point, readers are encouraged to try it on their own computers.

We can see that there are three folders.

First take a look at the BOOT-INF folder. There are two more folders classes and lib in the folder. It can be seen that the classes folder stores our compiled source code , and the lib folder stores the jar packages we depend on, including our tomcat, which is also packaged into this folder.

So what does the METE-INFO folder do?

Here you need to add an extra piece of knowledge:

According to the java specification and the jar specification, when we execute jar -jar xx.jar, it looks for the META-INFO/MANIFEST.MF file in the jar package and reads the Main-Class field.

In our project, it is org.springframework.boot.loader.JarLauncher. 20190628080913

In other words, java -jar target/standalone-0.0.1-SNAPSHOT.jar is equivalent to java org.springframework.boot.loader.JarLauncher.

Let’s try it:

$ 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
...
...

As you can see, the program can indeed be started in this way.

JarLauncher

Now that the new problem is coming again, what happened when java org.springframework.boot.loader.JarLauncher?

Here we look at the official documentation:

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

Readers are asked to click on their own.

org.springframework.boot.loader.JarLauncher will be used as a bootstrap class that will start the class defined in Start-Class in META-INF/MANIFEST.MF.

In our project, its value is com.github.codeman.standalone.StandaloneApplication.

You can see that this is the entry file for our own project.

Then let's start it manually:

$ 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)
...
...

As you can see, our program can also run.

So there is the following inference:

jar -jar xx.jar is equal to java org.springframework.boot.loader.JarLauncher equal to java -classpath "BOOT-INF/classes:BOOT-INF/lib/*" com.github.codeman.standalone.StandaloneApplication.

As for what happened to our SpringApplication.run(StandaloneApplication.class, args)?

@Controller
@SpringBootApplication
public class StandaloneApplication {

    public static void main(String[] args) {
        SpringApplication.run(StandaloneApplication.class, args);
    }
}

This is a very big topic, I will discuss it with you later, I will ignore it here.

The benefits of SpringBoot doing this are: packaging the project and dependencies from a single jar allows us to deploy it very easily, without having to manually manage the source code and dependent files.

The article here is permanently saved on github.

https://github.com/codeman-cs/SpringBoot/wiki/How-does-SpringBoot-start-on-the-command-line%3F

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment