How to deploy war files to Spring Boot Embedded Tomcat
In this tutorial, we are going to learn about adding other WAR files to the embedded tomcat server.
In real-time environments, there will be a need or requirement to bundle more than one or more WAR or JAR into the same tomcat server due to multi-model project requirements. So to do this we need to configure it in the spring boot Since it provides an option to do so.
Usually, we keep our WAR or JAR in the web apps folder in the tomcat server. In the application, we need to create a bean of type TomcatServletWebServerFactory in the @Configuration class. Since setting up the tomcat is related to configuration and we need to override the method getTomcatWebServer() and need to specify the context path of the WAR in tomcat.addWebApp().
@Bean
public TomcatServletWebServerFactory servletContainerFactory() {
return new TomcatServletWebServerFactory() {
@Override
protected TomcatWebServer getTomcatWebServer(Tomcat tomcat) {
// webapps directory does not exist by default, needs to be created
new File(tomcat.getServer().getCatalinaBase(), "webapps").mkdirs();
// Add a war with given context path
// Can add multiple wars this way with different context paths
tomcat.addWebapp("context-path", "path-to-your-war.war");
return super.getTomcatWebServer(tomcat);
}
};
}
Since hardcoding the path and context path to the WAR or JAR is not a best practise we can go with externalization by providing them in the application.properties and can fetch on demand or on loading the WAR using @ConditionalOnProperty.
@Bean
@ConditionalOnProperty(name = "external.war.file")
public TomcatServletWebServerFactory servletContainerFactory(@Value("${external.war.file}") String path,
@Value("${external.war.context}") String contextPath) {
return new TomcatServletWebServerFactory() {
@Override
protected TomcatWebServer getTomcatWebServer(Tomcat tomcat) {
new File(tomcat.getServer().getCatalinaBase(), "webapps").mkdirs();
tomcat.addWebapp(contextPath, path);
return super.getTomcatWebServer(tomcat);
}
};
}
We can change the context root in your application. properties by setting server.servlet.context-path to avoid collisions and we can use an empty string as context root when we want to deploy our war to /.
Using dependencies from both JAR’s in a multimodel project
In the case of multi-model projects, we can have the same JAR or WAR with the same dependencies present in both the WAR’s or JAR to avoid the duplicate dependencies used in our artifacts we specify using the external WAR using the classloader of the fat jar.
Context context = tomcat.addWebapp("context-path", "path-to-your-war.war");
context.setParentClassLoader(getClass().getClassLoader());
Adding Support for JSP’s in pom.xml of our external non-spring boot War that contains JSP’s and below are the dependencies that need to be added since tomcat doesn’t have these dependencies by default. For Maven:
<dependency>
<groupId>org.apache.tomcat.embed</groupId>
<artifactId>tomcat-embed-jasper</artifactId>
</dependency>
<dependency>
<groupId>javax.servlet</groupId>
<artifactId>jstl</artifactId>
</dependency>
For Gradle:
compile "org.apache.tomcat.embed:tomcat-embed-jasper"
compile "javax.servlet:jstl"