Apache Tomcat 7.0 now has a beta release out. One of it’s features is improved support for embedding. I have been embedding Jetty successfully in various projects, so I was hoping that Tomcat’s support for embedding was on par with Jetty’s. So far, Tomcat 7.0’s embedding API is quite easy to use and has been working well. However, I did not find any documentation on how to actually use it, so it took a small bit of digging to figure out how.
The one suggestion I read was to look at the test cases, because they used embedded Tomcat. So I checked out the source code, and found TomcatBaseTest which was an abstract class that tests were subclassing which provided a running embedded Tomcat. The org.apache.catalina.startup.Tomcat
class is what you need to use. After setting various settings, adding the application(s), you then call the start()
to start Tomcat. Note that start()
does not block, so if you exit your main
method, Tomcat will quit.
Like it’s non-embedded version, embedded Tomcat needs to create a work
directory for temporary files. You specify a base directory which the work
directory will be created in. I believe this base directory is the equivalent to Tomcat home directory. Use the setBaseDir(String baseDir)
method to set this. Looking at the source for Tomcat.initBaseDir()
method, it looks like if you don’t set it using this method, it will try to obtain this by trying:
catalina.base
system propertycatalina.base
system propertyuser.dir
system property as a base and tomcat.PORT_NUMBER as the temp directory it creates (replacing PORT_NUMBER with the actual port number.You can set a port number with setPort(int port)
. This defaults to 8080 if not set.
To add an application, use the addWebapp(String contextPath, String baseDir)
method, setting the webapp’s context path and specifying the location of the webapp folder for baseDir.
Once you are configured, you can call the start()
method. Then you need to make sure your app doesn’t exit, the simplest way is to do an infinite loop, e.g. while(true) { Thread.sleep(999999999); }
From the Tomcat 7.0.2 distribution, I put the following jar files in my classpath (not sure if all of them are necessary):
Notes:
TOMCAT_HOME/bin
folder, whereas the rest were in the TOMCAT_HOME/lib
folderHere is a little example app that assumes you have a webapp (WEB-INF with a web.xml in it) in the folder examplewebapp
:
import java.io.File;
import java.io.IOException;
import java.lang.InterruptedException;
import javax.servlet.ServletException;
import org.apache.catalina.LifecycleException;
import org.apache.catalina.startup.Tomcat;
public class TomcatEmbedExample {
public static void main(String[] args)
throws IOException, ServletException,
LifecycleException, InterruptedException {
String currentDir = new File(".").getCanonicalPath();
String tomcatDir = currentDir + File.separatorChar + "tomcat";
String webRoot = currentDir + File.separatorChar + "examplewebapp";
Tomcat tomcat = new Tomcat();
tomcat.setBaseDir(tomcatDir);
tomcat.setPort(4040);
tomcat.addWebapp("/examplewebapp", webRoot);
// or we could do this for root context:
// tomcat.addWebapp("/", webRoot);
tomcat.start();
while (true) {
Thread.sleep(999999999);
}
}
}
This has replace embedded Jetty as my development server. I run it inside of a debugger (Eclipse), and Java hot code replace works nicely. One thing that I am experimenting with is monitoring specific files to know when to restart the app. I am currently using JNotify to monitor file changes, and restart the app when XML files or other configuration files change that need a restart to get applied. It is working great so far, and I no longer have to manually restart the server or sacrifice Java hot code replace.
© 2017 Nilesh D Kapadia