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:
- Run the app using maven mvn clean spring-boot:run command
- Container starts up, do some testing, changed controller code and it’s now time to recompile again..
- 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:
- Remove spring-boot-maven-plugin
configuration on pom.xml - Setup tomcat7-maven-plugin
org.apache.tomcat.maven tomcat7-maven-plugin 2.0 - 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
Don’t use maven to run it :). Simply run the applications main method in eclipse and you can just stop/start the application.