Spring Boot With External Tomcat
Let's look at some common problems you might fave when starting a project from scratch.
Join the DZone community and get the full member experience.
Join For FreeOver the last few months, I disappeared. The reason is that I began a very exciting project that became a real challenge. Hence, I couldn’t take care of my blog, but now, I am here and would like to share you my experience. Let’s look at the most common problems you face when starting a project from scratch, specifically how to run a Spring Boot app with external Tomcat.
The Spring Boot Approach
In my Spring Boot article, I wrote about the basic fundamentals of how this technology works and what benefits it has over the core framework.
One of the main advantages of using Spring Boot is the ability to easily set up your web applications with the built-in embedded Tomcat. By default, the auto-configurer sets up your project with Tomcat. You simply hit the run button, and your web server starts up with your application. In your application.yaml or properties file, you can configure this Tomcat server easily like below:
server:
port: 9091 //set the port number of our running application
servlet:
context-path: /springapplication /set the context path of our application
To run our application, we only need a single main method:
@SpringBootApplication
public class App
{
public static void main( String[] args )
{
SpringApplication.run(App.class, args);
}
}
If you aren't familiar with how to create a single Spring Boot application, check my article for the details where I went through the basics step-by-step.
The Problem With External Tomcat
It can be a common expectation for the application to run on an external Tomcat server. Usually, it happens because of the operational infrastructure. At this point, some problems come. Your Spring Boot application won’t start by simply deploying it to the web server. It has several reasons:
- By default, Spring Boot creates a .jar file as an output. The Tomcat needs a .war file.
- In a Tomcat environment, you wouldn’t like to use the embedded server.
- The Tomcat server won’t hit your main method. Hence, you need to start your application as a normal Spring app.
Spring Boot is a cutting edge technology and mainly supports runs in a containerized environment. What can you do if you would like to operate your application in the standard way?
First, you could go back to a native Spring, which you normally do not want. Second, you could do some modifications that prepare your application to run on an old school Tomcat server. So, I will show you how.
Running Spring Boot With External Tomcat
Firstly, you need to do some modifications in your pom.xml:
Set war packaging for your artifact:
<packaging>war</packaging>
Set the Tomcat server dependency to provide:
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-tomcat</artifactId>
<scope>provided</scope>
</dependency>
If some of your Spring Boot libraries contain it by default, exclude it:
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
<exclusions>
<exclusion>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-tomcat</artifactId>
</exclusion>
</exclusions>
</dependency>
@SpringBootApplication
public class App extends SpringBootServletInitializer
{
public static void main( String[] args )
{
SpringApplication.run(App.class, args);
}
}
The SpringBootServerInitializer
class does the following (taken from the original class header):
* An opinionated {@link WebApplicationInitializer} to run a {@link SpringApplication} from a traditional WAR deployment. Binds {@link Servlet}, {@link Filter} and {@link ServletContextInitializer} beans from the application context to the server.
* To configure the application either override the {@link #configure(SpringApplicationBuilder)} method (calling {@link SpringApplicationBuilder#sources(Class...)}) or make the initializer itself a {@code @Configuration}. If you are using {@link SpringBootServletInitializer} in combination with other {@link WebApplicationInitializer WebApplicationInitializers} you might also want to add an {@code @Ordered} annotation to configure a specific startup order.
* Note that a WebApplicationInitializer is only needed if you are building a war file and deploying it. If you prefer to run an embedded web server then you won't need this at all.
After you do these modifications, you will be able to run your application from a traditional war deployment.
The External Configuration of Your Spring Boot App on Tomcat
It could be a general expectation to read your configuration file from an external source where the IT operation can handle it easily.
To achieve this, you need to override the configure method from the mentioned class above in our main class.
In the following example, I brought a real-time example. Here, I needed to read the config path from an environment variable. They set it in the Tomcat’s server setenv.sh file.
@Override
protected SpringApplicationBuilder configure(SpringApplicationBuilder application) {
String configLocation = System.getProperty("global.appconf.dir"); //get the default config directory location
String configPath = configLocation + File.separator + "springApplication" + File.separator + "application.yml"; //set the configpath of this application instance exclusively
log.info("Configpath: " + configPath);
log.info("Starting to run Spring boot app...");
if(configLocation != null && !configLocation.isEmpty()) {
Properties props = new Properties();
props.setProperty("spring.config.location", configPath); //set the config file to use
application.application().setDefaultProperties(props);
}else{
log.info("No global.appconf.dir property found, starting with default on classpath");
}
return application.sources(SpringApplication.class);
}
Note that when you run on external Tomcat, the settings under your server node in your configuration file don’t take effect. These properties only influence embedded Tomcat.
Summary
In this article, I demonstrated how you can run your Spring Boot application on external Tomcat. For me, this was a real-world scenario where I had to solve this problem.
Hopefully, this will provide some useful information when you will face a similar problem. If you like my post, do not forget to share!
Lastly, for deeper knowledge, I recommend you to read the official Spring documentation here.
Opinions expressed by DZone contributors are their own.
Comments