In Apache Tomcat, I have seen some posts that refer to the path $CATALINA_HOME/shared/lib
.
When I download Tomcat, I see no shared
folder
Caveat: I am not a Tomcat expert, this Answer is merely my cobbled-together understanding of how things work. I may well be wrong; please correct me.
Yes, this is a real feature.
You can create a folder most anywhere you want to collect the JAR files to be shared across one or more web apps within Tomcat.
Tell Tomcat to use that folder by editing catalina.properties
file to assign a value to the property named shared.loader
.
You are referring to the shared loader feature of Tomcat.
As you mentioned, some JARs such has JDBC drivers should not be replicated separately across multiple web-apps within a Tomcat instance. This topic has been discussed many times on Stack Overflow.
Such JARs should be loaded by a shared Java Class Loader, rather than the per-web-app class loaders.
As you can see in the diagram above, Tomcat can use many different class loaders, as explained in the doc.
The Bootstrap
and System
class loaders are irrelevant to our discussion here.
The Server
class loader is used by Tomcat's own needs. This may include looking up Realm related users in a database on your behalf. In such a case, Tomcat needs a JDBC driver to your database of choice.
As seen in the diagram with Webapp1
& Webapp2
, each of your web apps also get a class loader. This keeps each web-app separate, preventing them from stepping on each other’s toes. For example, each web app might use a different version of a logging framework.
The trick with JDBC drivers is that they share a registry in a JVM-wide singleton DriveManager
object. This design choice by the JDBC team unfortunately conflicts with the needs of an app server such as Tomcat using various class loaders. This is discussed in Question, Why must the JDBC driver be put in TOMCAT_HOME/lib folder? and in many others.
So it is best to share a single JAR file for each kind of JDBC driver across Tomcat's class loaders. That does mean all your web-apps must use the same version of each kind of JDBC driver (Postgres, H2, Oracle, etc.).
Shared
class loader, for use across one or more web apps. Common
class loader for use across both Tomcat’s internals and one or more of your web apps.The trick is that by default, Tomcat only defines the Common
class loader specifically. The Common
class loader does double-duty as the Server
and Shared
class loaders. To activate separate class loaders for Server
and/or Shared
, edit the catalina.properties
file. Look for the server.loader
& shared.loader
properties.
catalina.properties
fileAs for documentation, see this main page in the manual: Class Loader How-To. Also a mention in a wiki page†.
This issue is briefly discussed in comments found within the $CATALINA_HOME/conf/catalina.properties
file. Excerpting, per their Apache License 2 terms:
#
# List of comma-separated paths defining the contents of the "shared"
# classloader. Prefixes should be used to define what is the repository type.
# Path may be relative to the CATALINA_BASE path or absolute. If left as blank,
# the "common" loader will be used as Catalina's "shared" loader.
# Examples:
# "foo": Add this folder as a class repository
# "foo/*.jar": Add all the JARs of the specified folder as class
# repositories
# "foo/bar.jar": Add bar.jar as a class repository
# Please note that for single jars, e.g. bar.jar, you need the URL form
# starting with file:.
#
# Note: Values may be enclosed in double quotes ("...") in case either the
# ${catalina.base} path or the ${catalina.home} path contains a comma.
# Because double quotes are used for quoting, the double quote character
# may not appear in a path.
shared.loader=
Notice how the default value for that shared.loader
property is blank. As the comments explain, Tomcat will fallback to using its “common loader” which loads JARs from a lib
folder in the Catalina Home holder as well as a lib
folder in the Catalina Base folder (which some folks define as being a folder outside of the Tomcat folder, for ease of administration).
You are free to designate any folder to hold your JAR files to be accessed by Tomcat via its “shared loader” (provided your system's user account running Tomcat has file system privileges to that folder). AFAIK, creating a nested shared/lib
folder is just convention.
If you want to use the Tomcat folder for something like $CATALINA_HOME/shared/lib
:
shared
& lib
folders (with proper file system privileges). $CATALINA_HOME/conf/catalina.properties
to replace shared.loader=
with:shared.loader="${catalina.home}/shared/lib","${catalina.home}/shared/lib/*.jar"
Notice how we used double-quotes as instructed by the comments quoted above. And we specified with just lib
for class files as well as lib/*.jar
for JAR files.
If you are one of those people who elect to keep your web-apps in a folder outside of the Tomcat folder, you will have defined catalina.base
to be that outside folder. In such a case, you will likely want to keep your shared JAR files there too, rather than inside the Tomcat folder. So you may want the create your shared/lib
there. Following the example in those quoted comments:
shared
& lib
folders (with proper file system privileges) in your outside folder. $CATALINA_HOME/conf/catalina.properties
to replace shared.loader=
with:shared.loader="${catalina.base}/shared/lib","${catalina.base}/shared/lib/*.jar"
Notice how we used catalina.base
rather than catalina.home
.
You could specify looking at /shared/lib
folders both inside your Tomcat folder ("home") and also outside your Tomcat folder ("base").
Use both .base
& .home
:
shared.loader="${catalina.base}/shared/lib","${catalina.base}/shared/lib/*.jar","${catalina.home}/shared/lib","${catalina.home}/shared/lib/*.jar"
If you are using Maven to drive your Java project, you will want to edit your POM file to set a dependency for your particular JDBC driver. In that <dependency>
element, you will want to set the <scope>
to the value provided
to avoid bundling a copy of your JDBC driver within your web-app’s WAR file. See this Answer.
†This old Tomcat wiki page mentions briefly this same technique of creating your shared/lib
folders, then editing catalina.properties
file to define a value for property named shared.loader
.