JAR to WAR: Deploy Spring Boot on App Servers like Tomcat
In this post, We will learn about converting Spring Boot JAR to WAR file. We know that Spring Boot
produces a fat JAR
That helps You to start the app by running java -jar <your jar file>
. We can deploy these JARs with ease. But in unavoidable situations, you may need a WAR
file.
- Each application runs on a separate port. That means maintaining a list of free ports for all the services to execute.
- It is annoying to stop the application.
- First, you need to run
ps -ef | grep java
- And then identify and execute
kill -9 <PID>
. - There are scripts to start and stop spring boot applications.
- First, you need to run
- Each application has a separate web container.
- They will run Class-loading, Garbage Collection and other JVM activities.
- That implies added CPU and memory overhead.
- Grouping of applications in a single container.
- That method is more comfortable for the operations team. After all, they just have to stop one server and call it a day.
Existing Setup
Let’s take our Hello World Spring Boot Example. We try to convert this project to create a WAR file from this JAR project.
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>com.springhow.example</groupId>
<artifactId>hello-world</artifactId>
<version>0.0.1-SNAPSHOT</version>
<packaging>jar</packaging>
<name>hello-world</name>
<description>Demo project for Spring Boot</description>
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.3.2.RELEASE</version>
<relativePath/> <!-- lookup parent from repository -->
</parent>
<properties>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
<java.version>1.8</java.version>
</properties>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
</plugin>
</plugins>
</build>
</project>
Code language: HTML, XML (xml)
And your main
Class for Spring boot resembles this.
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.boot.builder.SpringApplicationBuilder;
import org.springframework.boot.web.servlet.support.SpringBootServletInitializer;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
@RestController
@SpringBootApplication
public class HelloWorldApplication extends SpringBootServletInitializer {
@Override
protected SpringApplicationBuilder configure(SpringApplicationBuilder application) {
return application.sources(HelloWorldApplication.class);
}
public static void main(String[] args) {
SpringApplication.run(HelloWorldApplication.class);
}
@RequestMapping("/")
String helloWorld() {
return "Hello World!";
}
}
Code language: Java (java)
Step 1: Package type from JAR to WAR.
In pom.xml
file, Change the line <packaging>jar</packaging>
in to <packaging>war</packaging>
. So your pom.xml
can look like this.
<groupId>com.springhow.example</groupId>
<artifactId>hello-world</artifactId>
<version>0.0.1-SNAPSHOT</version>
<packaging>war</packaging>
Code language: HTML, XML (xml)
At this point, running mvn package
would result in a WAR
file in the target/
directory. But, we are not done yet.
Step 2 : Remove the extra dependencies
By default, Spring boot adds the spring-boot-starter-tomcat
dependency to your web application. This starter
brings in all jars for embedded tomcat
. Their dependencies may clash with the server’s runtime and cause unpredictable outcomes. So to convert spring boot from JAR to WAR, you should eliminate the server dependencies.
To avoid this, you need to mark the starter
in pom.xml
as provided
.
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-tomcat</artifactId>
<scope>provided</scope> <!-- This is important. -->
</dependency>
Code language: HTML, XML (xml)
By marking the dependencies as provided, maven will ignore these dependencies.
Initializing spring in the web application context
One key difference between JAR and WAR files are how they both initialize the application. For instance, the JAR starts by calling the Main-Class entry in MANIFEST.MF file. However, This won’t work in WAR files. The WAR files usually have a WEB.xml file that tells the application server which path matches to which servlet etc. With the new Servlet 3.0, you can use annotations to bring the same behaviour.
But we don’t have to do all of that, thanks to spring-web
. Spring Web module provides a SpringBootServletInitializer class for initializing the web context.
@RestController
@SpringBootApplication
public class HelloWorldApplication extends SpringBootServletInitializer {
@Override
protected SpringApplicationBuilder configure(SpringApplicationBuilder application) {
return application.sources(HelloWorldApplication.class);
}
public static void main(String[] args) {
SpringApplication.run(HelloWorldApplication.class);
}
@RequestMapping("/")
String helloWorld() {
return "Hello World!";
}
}
Code language: Java (java)
You are almost done at this point. Run the mvn package command and you have successfully converted your spring boot application from JAR into a WAR file. You can safely deploy these WAR files on application servers like Tomcat, GlassFish etc.