Deploying Spring Boot app as WAR

Jul 20, 2019
Deploying Spring Boot app as WAR
How to change your JAR Spring Boot app to be packaged and deployed as WAR without sacrificing direct execution capabilities of embedded app server.

WAR vs JAR

By default, Spring Boot applications are packaged as executable JAR files with embedded Tomcat. You can run them directly by java -jar command. Traditional Java web applications need a servlet container (application server) to run. You need to have such container installed, configured, and then deploy your applications to it. And you need to have it prepared for each environment. With Spring Boot, this approach is inverted as the application server is directly in your JAR. This has many advantages, but sometimes you may need to have your Spring Boot app as a traditional WAR instead. For example, if you are tied by your company policies and need to deploy to a provided app server.

In this post, we'll examine how to package Spring Boot app as WAR, without sacrificing direct executability.

New applications

When you are creating a new app, the process is fortunately very easy. Instead of creating the application yourself, you can generate it with all the required settings and dependencies. There is an official tool called Spring Initializr.

By default, all the advanced options are hidden. You can set just the basics such as Spring version, language, or build tool. And of course all the dependencies.

You need to open the Options section to specify packaging.

Spring Boot initializr

In the advanced options section, there is Packaging selection. By default, there is Jar. This means you'll be able to run the JAR directly as it contains an embedded Tomcat application server.

You cannot deploy JARs to other applications servers (Tomcat, Jetty, JBoss, ...) to run them there. They only work with WARs. To be able to deploy your app to these, you need to change the packaging to WAR.

Spring Boot initializr packaging

What's great is such WAR is still executable on its own, which is useful. For example, it's great for local development, even if you use a regular app server in production.

After you're done with the setup, you can click Generate project and a zip file with your app will be downloaded.

IDEA integration

Generating apps with Spring Initializr is way more convenient and less error-prone than creating them manually. There is still a bit of inconvenience as you need to go to an external web page, download a zip file and unpack it.

Fortunately, you can use Spring Initializr directly from your IDE. In IntelliJ IDEA you can go to:

File → New Project → Spring Initializr

Here you can specify all the options as in the web version but with less hassle.

IDEA Spring Boot Initializr

Existing applications

When you already have existing Spring Boot application packaged as JAR, the process is slightly more complicated, but still straightforward. You need to make some changes manually.

Let's convert the app to WAR, which van be deployed to an application server such as Tomcat, while still keeping it executable.

Embedded Tomcat dependency

To make sure your embedded Tomcat dependencies are not clashing with what's already on your target Tomcat, you need to mark them as provided.

Maven

With Maven, simply add this dependency to your pom.xml file to the dependencies section.

<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-tomcat</artifactId>
    <scope>provided</scope>
</dependency>

Gradle

With Gradle, the process is similar, just add the dependency to your dependencies section with provided scope.

providedRuntime 'org.springframework.boot:spring-boot-starter-tomcat'

SpringBootServletInitializer

Now you need to make sure the app properly runs as WAR. It is as simple as adding the following class to your app.

import org.springframework.boot.builder.SpringApplicationBuilder;
import org.springframework.boot.web.servlet.support.SpringBootServletInitializer;

public class ServletInitializer extends SpringBootServletInitializer {

    @Override
    protected SpringApplicationBuilder configure(SpringApplicationBuilder application) {
        return application.sources(BootWarApplication.class);
    }

}

BootWarApplication.class is the class in your app annotated with @SpringBootApplication.

If you prefer, instead of a separate class, you can just make your @SpringBootApplication class extend SpringBootServletInitializer class and include the same configure method as above.

Change packaging

Now the last step is to make sure your app is properly packaged as WAR instead of JAR.

Maven

Simply update the packaging section in your pom.xml file from

<packaging>jar</packaging>

to WAR packaging

<packaging>war</packaging>

Gradle

In Gradle, add war plugin to your plugins section.

plugins {
    id 'org.springframework.boot' version '2.1.6.RELEASE'
    id 'java'
    id 'war'}

Building the WAR

The build process stays the same, no change here, simply run mvn package or gradle build and it will generate your WAR.

Now you can deploy to an application server of your choice.

Running the WAR

What's cool with this approach is that you can still run your WAR as an executable with embedded Tomcat. This way, you can have WAR deployment without sacrificing direct executability.

Simply run your archive as usual. Replace the last param with the real name of your WAR.

java -jar demo-1.0.0-SNAPSHOT.war



Let's connect