3 min read

How to convert Spring Boot JAR to WAR?

January 16, 2018

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 at 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 is an easier way though.
  • 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.

Steps to Adjust a spring boot JAR into WAR.

Let’s say your pom.xml looks like this.

<?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>

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!";
    }

}

Step 1: Change the packaging type in maven.

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>

At this point, running mvn package would result in a WARfile in the target/ directory. But, we are not done yet.

Step 2 : Remove the extra dependencies.

By default, Spring boot adds spring-boot-starter-tomcat dependency to your web application. This starter brings in all jars for embedded tomcat. Their jars may clash with the server’s runtime and cause unpredictable outcomes.

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>

Maven will ignore dependencies with scope as provided. Application server Runtime will supply these dependencies.

Initializing spring in the web application context

Every executable JAR files will have a Main-Class entry in META-INF\MANIFEST.MF file. Spring-boot takes advantage of this behaviour for JAR files. But for WAR files, the Main-Class entry won’t cut it. Here, you would need web.xml or servlet-3.0 annotations.

Thanks to spring-web, we can configure SpringBootServletInitializer to initialize our servlet context. That is exactly what we have done below.

@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!";
    }

}

Now you can run mvn package and see the war file under target/ directory. You can deploy this file on any application server like tomcat, WildFly,GlassFish etc.

For Spring Boot 1.x, the SpringBootServletInitializer is under org.springframework.boot.web.support.

Raja Anbazhagan

About the author

Raja is a Software Engineer with over 7 years of experience in working with Enterprise Java applications. Lately, He is focused in cloud-based Java applications and serverless technologies. He spends his spare time in stackoverflow.

Browse Categories