Comparison of running applications with maven and fat jar/war in spring boot

Posted by kye on Tue, 28 Jan 2020 05:24:43 +0100

Article Directory


Comparison of running applications with maven and fat jar/war

brief introduction

In the previous article, we introduced the fat jar/war package for Spring boot. Both jar/war packages can be run using java-jar commands, while maven also provides mvn spring-boot:run commands to run applications. Let's see how they differ.

Spring Boot Maven Plugin

In the previous article, we mentioned Spring Boot Maven Plugin, which can be used to effectively increase deployment efficiency and packaged as a fat jar/war package.

When packaging into a fat jar/war package, you actually do the following behind it:

  1. Manage the configuration of classpath so that we don't have to specify -cp manually when running java-jar.
  2. Custom lassLoaders are used to load and locate all external jar package dependencies.And all dependent jar packages are already included in this fat package.
  3. Automatic lookup of main() through manifest eliminates the need to manually specify the main method in java-jar.

Run the application using the Maven command

To run an application using the maven command, execute it under the root directory of the program:

mvn spring-boot:run

It automatically downloads the required dependencies and runs them with the following running logs:

mvn spring-boot:run
[INFO] Scanning for projects...
[INFO] 
[INFO] -------------------< com.flydean:springboot-fatjar >--------------------
[INFO] Building springboot-fatjar 0.0.1-SNAPSHOT
[INFO] --------------------------------[ jar ]---------------------------------
[INFO] 
[INFO] >>> spring-boot-maven-plugin:2.2.2.RELEASE:run (default-cli) > test-compile @ springboot-fatjar >>>
[INFO] 
[INFO] --- maven-resources-plugin:3.1.0:resources (default-resources) @ springboot-fatjar ---
[INFO] Using 'UTF-8' encoding to copy filtered resources.
[INFO] Copying 0 resource
[INFO] Copying 0 resource
[INFO] 
[INFO] --- maven-compiler-plugin:3.8.1:compile (default-compile) @ springboot-fatjar ---
[INFO] Nothing to compile - all classes are up to date
[INFO] 
[INFO] --- maven-resources-plugin:3.1.0:testResources (default-testResources) @ springboot-fatjar ---
[INFO] Using 'UTF-8' encoding to copy filtered resources.

[INFO] 
[INFO] --- maven-compiler-plugin:3.8.1:testCompile (default-testCompile) @ springboot-fatjar ---
[INFO] Nothing to compile - all classes are up to date
[INFO] 
[INFO] <<< spring-boot-maven-plugin:2.2.2.RELEASE:run (default-cli) < test-compile @ springboot-fatjar <<<
[INFO] 
[INFO] 
[INFO] --- spring-boot-maven-plugin:2.2.2.RELEASE:run (default-cli) @ springboot-fatjar ---
[INFO] Attaching agents: []

Run the application as a fat jar/war package

If you want to package into fat jar/war, you need to use the Maven Spring Boot plugin, as shown below, otherwise the packaged jar package does not contain external dependencies:

<build>
    <plugins>
        ...
        <plugin>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-maven-plugin</artifactId>
        </plugin>
        ...
    </plugins>
</build>

If our code contains more than one main class, you need to specify manually which one to use, in two ways:

<plugin>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-maven-plugin</artifactId>
    <executions>
        <execution>
            <configuration>
                <mainClass>com.flydean.FatJarApp</mainClass>
            </configuration>
        </execution>
    </executions>
</plugin>

Or set the star-class property:

<properties>
    <start-class>com.flydean.FatJarApp</start-class>
</properties>

Use mvn clean package to package the program, then use java-jar target/springboot-fatwar-0.0.1-SNAPSHOT.war
You are ready to run.

Detailed War File

Unzip the packed war file and let's look at the structure of the war file:

There are three parts:

  • META-INF containing the automatically generated MANIFEST.MF
  • WEB-INF/classes, containing the compiled class file
  • WEB-INF/lib, which contains war s dependent jar packages and embedded Tomcat jar packages.
  • WEB-INF/lib-provided contains additional dependency packages that are required to run in embedded mode but not in deployment mode.
  • org/springframework/boot/loader, which contains Spring boot custom class loaders responsible for loading external dependencies and making them available at runtime.

Let's look at the contents of the MANIFEST.MF file again:

Manifest-Version: 1.0
Implementation-Title: springboot-fatwar
Implementation-Version: 0.0.1-SNAPSHOT
Start-Class: com.flydean.FatWarApp
Spring-Boot-Classes: WEB-INF/classes/
Spring-Boot-Lib: WEB-INF/lib/
Build-Jdk-Spec: 1.8
Spring-Boot-Version: 2.2.2.RELEASE
Created-By: Maven Archiver 3.4.0
Main-Class: org.springframework.boot.loader.WarLauncher

Focus primarily on two lines:

Start-Class: com.flydean.FatWarApp
Main-Class: org.springframework.boot.loader.WarLauncher

One is the startup class we wrote, the other is the main class, which comes with Spring boot.

Detail jar file

Let's look at the jar file again:

The jar file is slightly different from the war file. Instead of a WEB-INF, it changes to a BOOT-INF.

  • All our own classes are under BOOT-INF/classes.
  • External dependency is under BOOT-INF/lib.

Let's see how the MANIFEST.MF file differs:

Manifest-Version: 1.0
Implementation-Title: springboot-fatjar
Implementation-Version: 0.0.1-SNAPSHOT
Start-Class: com.flydean.FatJarApp
Spring-Boot-Classes: BOOT-INF/classes/
Spring-Boot-Lib: BOOT-INF/lib/
Build-Jdk-Spec: 1.8
Spring-Boot-Version: 2.2.2.RELEASE
Created-By: Maven Archiver 3.4.0
Main-Class: org.springframework.boot.loader.PropertiesLauncher

We can see that the Start-Class is the same, but the Main-Class is different.

How to choose

Now that there are two ways to run the application, one using the mvn command and the other using the fat jar/war file, how do we choose?

Usually, if we are in an offline development environment, we can use the mvn command directly. The mvn command needs to depend on the source code. We can constantly modify the source code to facilitate development.

If it's an online environment, then we need to use fat jar/war, which has less external dependency. We don't need to deploy maven or source code in an online environment, just a java runtime environment.

Refer to the code for this article https://github.com/ddean2009/learn-springboot2/tree/master/springboot-fatwar

Refer to more tutorials Fldean's Blog

88 original articles published. 90% praised. 270,000 visits+
Private letter follow

Topics: Spring Maven SpringBoot Java