Is $CATALINA_HOME/shared/lib a real feature in Tomcat?

后端 未结 1 934
心在旅途
心在旅途 2020-12-20 06:42

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

相关标签:
1条回答
  • 2020-12-20 07:19

    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.

    tl;dr

    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.

    Shared class 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.

    Several 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.).

    • If you have not enabled the Realm user lookup feature in Tomcat, then Tomcat may have no use of its own for your database. So you can put your JDBC driver in the Shared class loader, for use across one or more web apps.
    • If you have enabled something in Tomcat that needs your database, then put that JDBC JAR file in the 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 file

    As 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).

    Create and specify your own folder of JARs

    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.

    Inside the Tomcat folder

    If you want to use the Tomcat folder for something like $CATALINA_HOME/shared/lib:

    1. Create the pair of shared & lib folders (with proper file system privileges).
    2. Edit the $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.

    Outside the Tomcat folder

    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:

    1. Create the pair of shared & lib folders (with proper file system privileges) in your outside folder.
    2. Edit the $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.

    Both inside and outside Tomcat folder.

    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.

    0 讨论(0)
提交回复
热议问题