Main Tutorials

Spring Boot – Deploy WAR file to Tomcat

In this article, we will show you how to create a Spring Boot traditional WAR file and deploy to a Tomcat servlet container.

In Spring Boot, to create a WAR for deployment, we need 3 steps:

  1. Extends SpringBootServletInitializer
  2. Marked the embedded servlet container as provided.
  3. Update packaging to war

Tested with

  • Spring Boot 2.1.2.RELEASE
  • Tomcat 8 and 9
  • Maven 3
Note
In Spring Boot, the new final executable JAR file with embedded server solution may not suitable in all production environments, especially the deployment team (a team with good knowledge of server optimization and monitoring skills, but lack of, the development experience), they want full control of the server, and they don’t touch code, so, we need a traditional WAR file.

1. Extends SpringBootServletInitializer

Update the @SpringBootApplication class to extend SpringBootServletInitializer, and override the configure method.

1.1 Classic Spring Boot JAR deployment.

StartWebApplication.java

import org.springframework.boot.autoconfigure.SpringBootApplication;

@SpringBootApplication
public class StartWebApplication {

    public static void main(String[] args) throws Exception {
        SpringApplication.run(StartWebApplication.class, args);
    }

}

1.2 For WAR deployment.

StartWebApplication.java

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;

@SpringBootApplication
public class StartWebApplication extends SpringBootServletInitializer {

    public static void main(String[] args) {
        SpringApplication.run(StartWebApplication.class, args);
    }

    @Override
    protected SpringApplicationBuilder configure(SpringApplicationBuilder builder) {
        return builder.sources(StartWebApplication.class);
    }
}


/*@SpringBootApplication
public class StartWebApplication {

    public static void main(String[] args) throws Exception {
        SpringApplication.run(StartWebApplication.class, args);
    }

}*/

For multiple main classes, make sure tell Spring Boot which main class to start :

pom.xml

  <properties>
      <!-- The main class to start by executing java -jar -->
      <start-class>com.mkyong.SpringBootWebApplication</start-class>
  </properties>
  

Read this – Spring Boot – Which main class to start

2. Marked the embedded servlet container as provided

pom.xml

<dependencies>

	<dependency>
		<groupId>org.springframework.boot</groupId>
		<artifactId>spring-boot-starter-thymeleaf</artifactId>
	</dependency>

	<!-- marked the embedded servlet container as provided -->
	<dependency>
		<groupId>org.springframework.boot</groupId>
		<artifactId>spring-boot-starter-tomcat</artifactId>
		<scope>provided</scope>
	</dependency>

</dependencies>

3. Update packaging to war

pom.xml

  <packaging>war</packaging>

Done, build the project and copy the WAR file for deployment.

Download Source Code

$ git clone https://github.com/mkyong/spring-boot.git
$ cd web-thymeleaf-war
$ mvn package
$ copy web-thymeleaf-war/target/mkyong.war $TOMCAT/webapps/
$ start Tomcat
$ localhost:8080/mkyong

References

About Author

author image
Founder of Mkyong.com, love Java and open source stuff. Follow him on Twitter. If you like my tutorials, consider make a donation to these charities.

Comments

Subscribe
Notify of
33 Comments
Most Voted
Newest Oldest
Inline Feedbacks
View all comments
Mohammed Qurashi
6 years ago

Awesome tutorial, I had it working for my spring-boot app on tomcat 8

vRadhe
5 years ago

It is not running from main class or not execute which contains main method

Wang
5 years ago

Hi Mkyong,

I followed your example and got the following error from Tomcat log.

01-Oct-2018 14:29:57.442 INFO [http-nio-8080-exec-43] org.apache.jasper.servlet.TldScanner.scanJars At least one JAR was scanned for TLDs yet contained no TLDs. Enable debug logging for this logger for a complete list of JARs that were scanned but no TLDs were found in them. Skipping unneeded JARs during scanning can improve startup time and JSP compilation time.
01-Oct-2018 14:30:11.851 SEVERE [http-nio-8080-exec-43] org.apache.catalina.core.StandardContext.startInternal One or more listeners failed to start. Full details will be found in the appropriate container log file
01-Oct-2018 14:30:11.852 SEVERE [http-nio-8080-exec-43] org.apache.catalina.core.StandardContext.startInternal Context [/nuhs] startup failed due to previous errors
01-Oct-2018 14:30:11.889 WARNING [http-nio-8080-exec-43] org.apache.catalina.loader.WebappClassLoaderBase.clearReferencesJdbc The web application [nuhs] registered the JDBC driver [com.mysql.jdbc.Driver] but failed to unregister it when the web application was stopped. To prevent a memory leak, the JDBC Driver has been forcibly unregistered.
01-Oct-2018 14:30:11.889 WARNING [http-nio-8080-exec-43] org.apache.catalina.loader.WebappClassLoaderBase.clearReferencesThreads The web application [nuhs] appears to have started a thread named [Abandoned connection cleanup thread] but has failed to stop it. This is very likely to create a memory leak. Stack trace of thread:
[email protected]/java.lang.Object.wait(Native Method)
[email protected]/java.lang.ref.ReferenceQueue.remove(Unknown Source)
com.mysql.jdbc.AbandonedConnectionCleanupThread.run(AbandonedConnectionCleanupThread.java:64)
[email protected]/java.util.concurrent.ThreadPoolExecutor.runWorker(Unknown Source)
[email protected]/java.util.concurrent.ThreadPoolExecutor$Worker.run(Unknown Source)
[email protected]/java.lang.Thread.run(Unknown Source)
01-Oct-2018 14:30:12.932 INFO [Abandoned connection cleanup thread] org.apache.catalina.loader.WebappClassLoaderBase.checkStateForResourceLoading Illegal access: this web application instance has been stopped already. Could not load []. The following stack trace is thrown for debugging purposes as well as to attempt to terminate the thread which caused the illegal access.
java.lang.IllegalStateException: Illegal access: this web application instance has been stopped already. Could not load []. The following stack trace is thrown for debugging purposes as well as to attempt to terminate the thread which caused the illegal access.
at org.apache.catalina.loader.WebappClassLoaderBase.checkStateForResourceLoading(WebappClassLoaderBase.java:1329)
at org.apache.catalina.loader.WebappClassLoaderBase.getResource(WebappClassLoaderBase.java:1006)
at com.mysql.jdbc.AbandonedConnectionCleanupThread.checkContextClassLoaders(AbandonedConnectionCleanupThread.java:90)
at com.mysql.jdbc.AbandonedConnectionCleanupThread.run(AbandonedConnectionCleanupThread.java:63)
at java.base/java.util.concurrent.ThreadPoolExecutor.runWorker(Unknown Source)
at java.base/java.util.concurrent.ThreadPoolExecutor$Worker.run(Unknown Source)
at java.base/java.lang.Thread.run(Unknown Source)

Adolf Mrls
6 years ago

Hi Mkyong, great tutorial
in the case to need a “upload-dir” where?
(i put it in the root and dont work x( ) Help pls!

Vibhor gaur
3 years ago

Hi sir, I followed exact same steps as mentioned here
$ git clone https://github.com/mkyong/spring-boot.git
$ cd web-thymeleaf-war
$ mvn package
$ copy web-thymeleaf-war/target/mkyong.war $TOMCAT/webapps/
$ start Tomcat
$ localhost:8080/mkyong

but I get HTTP status 404 error

However, if I don’t deploy through tomcat but simply do mvn spring-boot:run, it works fine, please help sir I am stuck very bad, can you please help

Aayush
4 years ago

Run into error

org.apache.catalina.core.StandardContext.listenerStart Exception sending context initialized event to listener instance of class [org.springframework.web.context.ContextLoaderListener]
java.lang.IllegalStateException: Cannot initialize context because there is already a root application context present – check whether you have multiple ContextLoader* definitions in your web.xml!

asd
4 years ago
Reply to  Aayush

plugin
groupId>org.apache.maven.plugins/groupId
artifactId>maven-war-plugin/artifactId
configuration
failOnMissingWebXml false /failOnMissingWebXml
/configuration
/plugin

Gabriel Andrade
6 years ago

Im using spring boot with JSF and i am able to start the server just fine, but after a while(around 1 or 2 days), the server stops and cant startup again, giving me the error:
2018-02-18 10:30:08.018 INFO 7052 — [localhost-startStop-2] ationConfigEmbeddedWebApplicationContext : Closing org.springframework.boot.context.embedded.AnnotationConfigEmbeddedWebApplicationContext@2e601386: startup date [Thu Feb 15 13:20:57 UTC 2018]; root of context hierarchy
2018-02-18 10:30:08.033 INFO 7052 — [localhost-startStop-2] o.s.j.e.a.AnnotationMBeanExporter : Unregistering JMX-exposed beans on shutdown

Sergey Chernov
3 years ago

Thanks for advice regarding war-file: extends SpringBootServletInitializer
It solved my problem!

Emilbek Sulaimanov
4 years ago

Thank you Mkyong

Udaib khan
4 years ago

Hi ,Currently i have migrated my application from spring mvc to spring boot and now when i export war file using eclipse and deploy it tomcat 8.5 then it gives me this error “Caused by: java.lang.UnsupportedClassVersionError: JVMCFRE003 bad major version; class=org/springframework/web/SpringServletContainerInitializer, offset=6 (unable to load class org.springframework.web.SpringServletContainerInitializer)”

Althought i am using same jdk locally and and same jre on production but again i’m unable to deploy this war file

asb
4 years ago

Thank you very much
you are best

Ted
5 years ago

To get it working with Java 9+ you need to add this to your pom file (xml bind removed in Java 9+):

javax.xml.bind
jaxb-api
2.3.0

Dido
5 years ago

Every request I make returns 401. I use JWT authentication. Anyone with the same problem?

Khamphai
5 years ago

how to deploy spring boot war file to glassfish4.1 server ?

Carol
6 years ago

Thank you!

nonsaprei
6 years ago

I just wanted to add that specifying a server.contextPath in the application.properties is pointless, because Tomcat won’t let you use that.

ronald haring
6 years ago

only works on servlet3+ containers i think, tomcat 7 does nothing

Chhorn Elit
6 years ago

I build your war to deploy, but cannot. Then I realize the pom.xml specify java 8.0. However, tomcat server were running on java 7.0. Thanks though.

Anthony
6 years ago

Thanks for the tutorial!
Is there a more seamless way to continue deployment to the application. (In case I made a small change to a template for example). I would have to re-upload the whole war file to tomcat.

Rohit Basu
6 years ago

I tried my own and i post the issue in
https://stackoverflow.com/questions/47294386/issues-in-spring-boot-war-file-deployment-in-tomcat-server
I am getting error:
“Whitelabel Error Page

This application has no explicit mapping for /error, so you are seeing this as a fallback.

Thu Nov 16 18:03:35 IST 2017
There was an unexpected error (type=Not Found, status=404).
No message available”

Please check if you can help.

Shahid Akhtar
6 years ago

Hi Mkyong,
Would you please let me know how to set contextPath for spring boot application if deployed as a war on
standalone tomcat?

Regards,
Shahid Akhtar.

Pavithra
6 years ago

This tutor is very simple!! Thanks

phuctran
6 years ago

to run your example, need to add “server.error.whitelabel.enabled=false” to application.properity

webdev
6 years ago
Reply to  phuctran

how to run this application

Amit
6 years ago

hi Mkyong,
I installed your example.
It seems server.contextPath is not recognized by external tomcat8.

Do you have any suggestions on how to set context path of a spring boot(1.5) application in external tomcat8?

Regards
Amit

Salil Kumar
6 years ago
Reply to  Amit

Hi Amit ,

To run this application , you need to add the below in application.properties.
server.port=8080
server.error.whitelabel.enabled=false.

Then run the below command :

C:……….> mvn spring-boot:run

Then open any browser and run :

http://localhost:8080/mkyong/

Hetarth Shah
6 years ago
Reply to  Amit
Shahid Akhtar
6 years ago
Reply to  Hetarth Shah

it does not work for standalone container

Shahid Akhtar
6 years ago
Reply to  Hetarth Shah

Hi Shah,
Given link states about contextPath change will work for embedded tomcat. It does not work for
standalone containers. Would you please let me know how contextPath can be set for standalone
containers?

Thanks
Shahid Akhtar

Mohammed Amen
6 years ago
Reply to  Shahid Akhtar

By the way why do you need to deploy anything in stand alone container? You dont you use the embedded one …it is quite easy to use with very less work to do. If you are using eclipse as ide you can add tomcat maven compiler plugin in pom.xml along with the spring-boot-starter-tomcat. It is a perfect combination u only need to run the SpringBootWebApplication java class and then maven clean and install which will automatically add the war to the tomcat without unnecessary overhead and u can then load the page.

Joel Rives
5 years ago

I find the tutorial very simple and straight forward. I downloaded the code, built it and deployed to Tomcat. It works. I am now trying to apply this to my project with no luck yet. Here is the pertinent part of my project hierarchy:

config
SpringBootWebApplication
controller
HelloController

The SpringBootWebApplication is exactly as in your tutorial
The HelloController is my version of your WelcomeController. I looks like this:

@Controller
public class HelloController {

@RequestMapping(“/”)
public String index() {
return “Greetings from Spring Boot!”;
}

}

This does not work. The war deploys just fine but attempts to access it fail. I get the error the requested resource is not available. Any thoughts are welcome.

Cuong Bui Quang
6 years ago

I follow your tutorial and my spring boot application runs twice when I deploy war to tomcat. I also solve this by remove Spring Boot Application from extending SpringBootServletInitializer, my Spring Boot version is 1.5.7.RELEASE