Spring Boot And The Embedded Tomcat Container

There’s one thing that has been bothering me with Spring Boot’s embedded Tomcat container on Windows: it forks a new process which doesn’t die when the the parent process is terminated.

Here’s an example of the problem:

  1. Run the app using maven mvn clean spring-boot:run command
  2. Container starts up, do some testing, changed controller code and it’s now time to recompile again..
  3. Clicked Eclipse’s stop and run button, and port has been used error came up. Now I have to go task manager, find the java process (among 3-4 other java processes) and kill it manually

This additional step really frustates me, identifying which java process you should kill isn’t always straight forward, you have to see the full command and see what it does.

Fortunately I found a workaround for this: scrap spring-boot-maven-plugin altogether and use the old-school tomcat7-maven-plugin. Here’s the step required to achieve this:

  1. Remove spring-boot-maven-plugin configuration on pom.xml
  2. Setup tomcat7-maven-plugin
    
      org.apache.tomcat.maven
      tomcat7-maven-plugin
      2.0
    
    
  3. Instead of SpringApplication.run(Application.class, args), bootstrap Spring Boot using SpringBootServletInitializer instead, eg:
    
    guration
    
    public class Application extends SpringBootServletInitializer {
    
      
      protected SpringApplicationBuilder configure(SpringApplicationBuilder application) {
        return application.sources(Application.class);
      }
      
    }
    

    This is required such that SpringBoot can boot the container when tomcat starts up

Ok all good now, I started my app with mvn clean test tomcat7:run command, but wait.. there’s a weird exception being thrown:

Aug 22, 2014 4:01:46 PM org.apache.catalina.startup.ContextConfig parseWebXml
SEVERE: Parse error in application web.xml file at file:/C:/***/***/***/target/tomcat/conf/web.xml
org.xml.sax.SAXParseException; systemId: file:/C:/***/***/***/target/tomcat/conf/web.xml; lineNumber: 108; columnNumber: 15; Error at (108, 15) : org.apache.catalina.deploy.WebXml addServlet
  at org.apache.tomcat.util.digester.Digester.createSAXException(Digester.java:2687)
  at org.apache.tomcat.util.digester.Digester.createSAXException(Digester.java:2719)
  at org.apache.tomcat.util.digester.Digester.endElement(Digester.java:1054)
  at com.sun.org.apache.xerces.internal.parsers.AbstractSAXParser.endElement(AbstractSAXParser.java:606)
...
Caused by: java.lang.NoSuchMethodException: org.apache.catalina.deploy.WebXml addServlet
  at org.apache.tomcat.util.IntrospectionUtils.callMethod1(IntrospectionUtils.java:855)
  at org.apache.tomcat.util.digester.SetNextRule.end(SetNextRule.java:201)
  at org.apache.tomcat.util.digester.Digester.endElement(Digester.java:1051)
  ... 27 more

Took me quite a while to figure out, but it seems this problem is caused by a classpath conflict. My app uses spring-boot-started-web dependency which pulls spring-boot-starter-tomcat, which pulls various tomcat jars as dependency.

After a few trial and errors, I found the solution by marking spring-boot-started-tomcat as provided in the dependencies in pom.xml


  org.springframework.boot
  spring-boot-starter-tomcat
  provided

2 thoughts on “Spring Boot And The Embedded Tomcat Container”

Leave a Reply