0
votes

I am trying to get a Spring Boot jar featuring an embedded Tomcat server to load an external war at runtime. I'm trying to do this using the technique shown in this post.

The container bean in the Spring Boot application:

@Bean
public EmbeddedServletContainerFactory servletContainerFactory() {
    return new TomcatEmbeddedServletContainerFactory() {
        @Override
        protected TomcatEmbeddedServletContainer getTomcatEmbeddedServletContainer(Tomcat tomcat) {
            try {
                Context context = tomcat.addWebapp(tomcat, "/first", "path/to/my.war");
                WebappLoader loader = new WebappLoader(Thread.currentThread().getContextClassLoader());
                context.setLoader(loader);
            } catch (ServletException e) {
                throw new IllegalStateException("Failed to add webapp", e);
            }
            return super.getTomcatEmbeddedServletContainer(tomcat);
        }
    };
}

Maven Dependencies for the external war:

<dependencies>
    <dependency>
        <groupId>org.springframework</groupId>
        <artifactId>spring-webmvc</artifactId>
        <version>4.3.4.RELEASE</version>
    </dependency>
    <dependency>
        <groupId>javax.servlet</groupId>
        <artifactId>javax.servlet-api</artifactId>
        <version>3.1.0</version>
        <scope>provided</scope>
    </dependency>
</dependencies>

When i start the Spring Boot container app, the container bean locates the warfile and adds it to the classpath, but then throws a ClassNotFoundException:

2017-01-13 15:14:22.520  INFO 208 --- [ost-startStop-1] o.a.c.c.C.[Tomcat].[localhost].[/first]  : 1 Spring WebApplicationInitializers detected on classpath
2017-01-13 15:14:22.520  INFO 208 --- [ost-startStop-1] o.a.c.c.C.[Tomcat].[localhost].[/first]  : Marking servlet jsp as unavailable
2017-01-13 15:14:22.520 ERROR 208 --- [ost-startStop-1] o.a.c.c.C.[Tomcat].[localhost].[/first]  : Servlet [jsp] in web application [/first] threw load() exception

java.lang.ClassNotFoundException: org.apache.jasper.servlet.JspServlet
    at org.apache.catalina.loader.WebappClassLoaderBase.loadClass(WebappClassLoaderBase.java:1285) ~[tomcat-embed-core-8.5.6.jar!/:8.5.6]
    at org.apache.catalina.loader.WebappClassLoaderBase.loadClass(WebappClassLoaderBase.java:1119) ~[tomcat-embed-core-8.5.6.jar!/:8.5.6]
    at org.apache.catalina.core.DefaultInstanceManager.loadClass(DefaultInstanceManager.java:520) ~[tomcat-embed-core-8.5.6.jar!/:8.5.6]
    at org.apache.catalina.core.DefaultInstanceManager.loadClassMaybePrivileged(DefaultInstanceManager.java:501) ~[tomcat-embed-core-8.5.6.jar!/:8.5.6]
    at org.apache.catalina.core.DefaultInstanceManager.newInstance(DefaultInstanceManager.java:118) ~[tomcat-embed-core-8.5.6.jar!/:8.5.6]
    at org.apache.catalina.core.StandardWrapper.loadServlet(StandardWrapper.java:1050) ~[tomcat-embed-core-8.5.6.jar!/:8.5.6]
    at org.apache.catalina.core.StandardWrapper.load(StandardWrapper.java:989) ~[tomcat-embed-core-8.5.6.jar!/:8.5.6]
    at org.apache.catalina.core.StandardContext.loadOnStartup(StandardContext.java:4913) [tomcat-embed-core-8.5.6.jar!/:8.5.6]
    at org.apache.catalina.core.StandardContext.startInternal(StandardContext.java:5223) [tomcat-embed-core-8.5.6.jar!/:8.5.6]
    at org.apache.catalina.util.LifecycleBase.start(LifecycleBase.java:150) [tomcat-embed-core-8.5.6.jar!/:8.5.6]
    at org.apache.catalina.core.ContainerBase$StartChild.call(ContainerBase.java:1403) [tomcat-embed-core-8.5.6.jar!/:8.5.6]
    at org.apache.catalina.core.ContainerBase$StartChild.call(ContainerBase.java:1393) [tomcat-embed-core-8.5.6.jar!/:8.5.6]
    at java.util.concurrent.FutureTask.run(Unknown Source) [na:1.8.0_112]
    at java.util.concurrent.ThreadPoolExecutor.runWorker(Unknown Source) [na:1.8.0_112]
    at java.util.concurrent.ThreadPoolExecutor$Worker.run(Unknown Source) [na:1.8.0_112]
    at java.lang.Thread.run(Unknown Source) [na:1.8.0_112]

I've tried including jars with org.apache.jasper.servlet.JspServlet in the war. I've also tried using a Spring Boot war (application class extends SpringBootApplicationInitializer, packaging to war and giving the tomcat starter dependency a provided scope) which also gives the same error. Open to any suggestions.

1

1 Answers

2
votes

Tomcat-Jasper is missing. Depending on the version of the embedded Tomcat, that your Spring Boot uses add following dependency to your pom.xml:

<dependency>
  <groupId>org.apache.tomcat.embed</groupId>
  <artifactId>tomcat-embed-jasper</artifactId>
  <version>8.5.5</version>
</dependency>

For Spring Boot 1.4.1.RELEASE it is version 8.5.5 (Available versions of "tomcat-embed-jasper").

To check if the library is present after adding the dependency to Maven, package your application. In the packaged application you will find it under

\BOOT-INF\lib\tomcat-embed-jasper-8.5.5.jar