How to deploy a JAR file to Tomcat by example

Tomcat JAR deployment tutorial

The question of how to deploy a JAR file to Tomcat drives a surprising amount of traffic to TheServerSide. It’s a strange search query, because you don’t really deploy JAR files to Tomcat.

Apache Tomcat is a servlet engine that runs Java web applications, which are packaged as web application archive files, or WARs. A WAR file is the one that’s deployed to Tomcat, not a JAR file. But, despite the fact that the question of how to deploy a JAR isn’t one that’s commonly asked, it’s worth further exploration.

WAR file deployment to Tomcat

TheServerSide has a number of tutorials on how to deploy a WAR file to Tomcat, including a Maven Tomcat deploy or a WAR file deployment with Jenkins. If that’s the actual issue that needs to be resolved, I highly recommend that you view those tutorials.

However, that’s not to say there’s no relationship at all between JAR files and applications that run on Tomcat. Frameworks such as Spring and Hibernate are packaged in JAR files, and common utilities a team might put together also get packaged as JARs. These files need to be accessible to web applications hosted on the Apache Tomcat server at runtime.

I have an inkling that when developers ask how to deploy a JAR file to Tomcat, they actually mean to ask where JAR files should be placed to ensure they are part of the Apache Tomcat classpath at runtime and subsequently accessible to their deployed apps. After all, there’s nothing worse than when you deploy an application and run into a bunch of Tomcat’s ClassNotFoundExceptions.

JAR files and Tomcat

The right place to put a JAR file to make its contents available to a Java web application at runtime is in the WEB-INF\lib directory of the WAR file in which the application is packaged. With very few exceptions, the JAR files a Java web application must link to at runtime should be packaged within the WAR file itself. This approach helps reduce the number of external dependencies a web application has, and at the same time eliminates the potential for classloader conflicts.

Sometimes there are common utilities — such as a set of JDBC drivers — that are so ubiquitously required, it makes more sense to place them directly in a Tomcat sub-folder, and not actually package them inside of a WAR.

If every application hosted on your Tomcat server uses a MySQL database, it would make sense to place the MySQL database drivers in Tomcat’s \lib directory, and not in the WEB-INF\lib directory of the WAR. Furthermore, if you have an upgraded database but the JDBC drivers need to be upgraded, by updating the JAR file in that one shared location, it will mean all of the applications will start using the same set of updated Java libraries at the same time.

tomcat JAR deploy

A web app’s WEB-INF\lib folder and the Tomcat \lib directories are the best places to deploy JAR files in Tomcat.

A common organizational mistake is to place JAR files containing frameworks like JSF or Spring Boot in Tomcat’s \lib directory. People think that since every application deployed to Tomcat in their organization is built with Spring or JSF, it makes sense to put these JAR files in Tomcat’s \lib folder.

While this may work initially, as soon as one application needs to use an updated version of the JAR, a problem arises. If the shared JAR file is updated to a new version, all applications hosted on the Tomcat server that use that JAR file must be updated as well. This obviously creates unnecessary work and unnecessary risk, as even applications that don’t need to use the updated version must be regression tested. In contrast, if the required JAR file was packaged within the WAR file itself, you can avoid a mass migration issue.

JARs deployed to the Tomcat lib directory

One problem with the Tomcat \lib directory is the fact that it includes all of the standard libraries the application server needs to implement the Servlet and JSP API. Right out of the box, that folder is filled with over 30 JAR files that are required at runtime. Plus, you don’t want to mess around with any of those required JAR files, because if any of those files are deleted or disturbed, the Tomcat server will fail to start.

Some Tomcat administrators like to address this issue with a separate directory for application JAR files. Admins can do this with a simple edit to the common.loader property in Tomcat’s catalina.properties file. For example, to have Tomcat link to JAR files in a subdirectory named \applib, you can make the following change to the common.loader property:

#Note that catalina.base refers to the Tomcat installation directory
common.loader="${catalina.base}/lib","${catalina.base}/applib/*"

It should be noted that since Tomcat runs on a Java installation, it also has access to any JAR file placed on the classpath of the JVM. This is known as the system classpath, and while it is a viable option for JAR files that need to be linked to by Tomcat, I wouldn’t recommend using the system classpath.

This location should only be used for resources that are used to bootstrap the JVM, or are referenced directly by the JVM at runtime. Furthermore, the system classpath is typically highly restricted, so it is unlikely that software developers or any continuous integration tools would ever have the credentials required to read or write to this folder.

Tomcat JAR deployment options

In summary, I think that when you ask how to deploy a JAR file to Tomcat, you’re really wondering how to make a JAR file available to your web applications at runtime. There are three recommended options to make this happen:

  1. Package the JAR file in the WEB-INF\lib folder of the Java web application;
  2. Place the JAR file in the \lib subfolder of the Apache Tomcat installation;
  3. Configure a folder for shared JAR files by editing Tomcat’s common.loader property in the catalina.properties file.

If you follow this advice, your JAR file deployment issues with Tomcat should disappear, and ClassNotFoundExceptions in your logs will become a thing of the past.