Comparison of running applications with maven and fat jar/war
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.
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:
- Manage the configuration of classpath so that we don't have to specify -cp manually when running java-jar.
- 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.
- Automatic lookup of main() through manifest eliminates the need to manually specify the main method in java-jar.
To run an application using the maven command, execute it under the root directory of the program:
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: 
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.
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.
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.
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