$CATALINA_HOME/shared/lib 是 Tomcat 中的真正功能吗? [英] Is $CATALINA_HOME/shared/lib a real feature in Tomcat?
问题描述
在
通过编辑 catalina.properties
文件来告诉 Tomcat 使用该文件夹,为名为 shared.loader
的属性赋值.
共享类加载器
您指的是 Tomcat 的共享加载器功能.
正如您所提到的,不应在 Tomcat 实例中的多个 Web 应用程序之间单独复制某些具有 JDBC 驱动程序的 JAR.此主题已在 Stack Overflow 上多次讨论.
此类 JAR 应由共享的 Java 类加载器加载,而不是由每个网络应用类加载器.
几个类加载器
如上图所示,Tomcat 可以使用许多不同的类加载器,如 在文档中解释.
Bootstrap
和 System
类加载器与我们在这里的讨论无关.
Server
类加载器是 Tomcat 自己需要的.这可能包括代表您在数据库中查找与 Realm 相关的用户.在这种情况下,Tomcat 需要您选择的数据库的 JDBC 驱动程序.
如Webapp1
的图表所示 &Webapp2
,您的每个网络应用程序也都有一个类加载器.这使每个网络应用程序保持独立,防止它们相互影响.例如,每个 Web 应用程序可能使用不同版本的日志记录框架.
JDBC 驱动程序的诀窍在于它们在 JVM 范围的单例 DriveManager
对象中共享一个注册表.不幸的是,JDBC 团队的这种设计选择与使用各种类加载器的应用服务器(例如 Tomcat)的需求相冲突.这在问题中讨论,为什么必须将 JDBC 驱动程序放在 TOMCAT_HOME/lib 文件夹中?以及许多其他.
因此最好为 Tomcat 的类加载器中的每种 JDBC 驱动程序共享一个 JAR 文件.这确实意味着您的所有 Web 应用程序必须使用相同版本的每种 JDBC 驱动程序(Postgres、H2、Oracle 等).
- 如果您未在 Tomcat 中启用 Realm 用户查找功能,那么 Tomcat 可能无法使用自己的数据库.因此,您可以将 JDBC 驱动程序放在
Shared
类加载器中,以便在一个或多个 Web 应用程序中使用. - 如果您已经在 Tomcat 中启用了一些需要您的数据库的东西,那么将该 JDBC JAR 文件放在
Common
类加载器中,以便在 Tomcat 的内部和您的一个或多个网络应用.
诀窍是,默认情况下,Tomcat 只专门定义了 Common
类加载器.Common
类加载器与 Server
和 Shared
类加载器有双重作用.要为 Server
和/或 Shared
激活单独的类加载器,请编辑 catalina.properties
文件.寻找 server.loader
&shared.loader
属性.
catalina.properties
文件
至于文档,请参阅手册中的此主页:类加载器操作方法.也在 wiki 页面中提及†.
在 $CATALINA_HOME/conf/catalina.properties
文件中的注释中简要讨论了这个问题.根据他们的 Apache 许可 2 条款摘录:
请注意 shared.loader
属性的默认值为空.正如评论所解释的那样,Tomcat 将回退到使用其通用加载器",该加载器从 Catalina Home 文件夹中的 lib
文件夹以及 Catalina 中的 lib
文件夹加载 JAR.基本文件夹(有些人将其定义为 Tomcat 文件夹之外的文件夹,以便于管理).
创建并指定您自己的 JAR 文件夹
您可以自由地指定任何文件夹来保存您的 JAR 文件,以便 Tomcat 通过其共享加载程序"访问(前提是您运行 Tomcat 的系统用户帐户具有 该文件夹的文件系统权限).AFAIK,创建嵌套的 shared/lib
文件夹只是约定.
Tomcat 文件夹内
如果您想将 Tomcat 文件夹用于诸如 $CATALINA_HOME/shared/lib
之类的内容:
- 创建一对
shared
&lib
文件夹(具有适当的文件系统权限). - 编辑
$CATALINA_HOME/conf/catalina.properties
以将shared.loader=
替换为:shared.loader="${catalina.home}/shared/lib","${catalina.home}/shared/lib/*.jar"
请注意我们如何按照上面引用的注释的说明使用双引号.我们只为类文件指定了 lib
,为 JAR 文件指定了 lib/*.jar
.
Tomcat 文件夹外
如果您是选择将 Web 应用程序保存在 Tomcat 文件夹外部的文件夹中的人之一,那么您将定义 catalina.base
为那个外面的文件夹.在这种情况下,您可能希望将共享的 JAR 文件也保存在那里,而不是保存在 Tomcat 文件夹中.所以你可能希望在那里创建你的 shared/lib
.按照那些引用评论中的例子:
- 创建一对
shared
&lib
文件夹(具有适当的文件系统权限)在您的外部文件夹中. - 编辑
$CATALINA_HOME/conf/catalina.properties
以将shared.loader=
替换为:shared.loader="${catalina.base}/shared/lib","${catalina.base}/shared/lib/*.jar"
注意我们如何使用 catalina.base
而不是 catalina.home
.
在Tomcat文件夹内和.
您可以指定查看 Tomcat 文件夹(home")内和 Tomcat 文件夹外(base")的 /shared/lib
文件夹.
同时使用 .base
&.home
:
shared.loader="${catalina.base}/shared/lib","${catalina.base}/shared/lib/*.jar","${catalina.home}/shared/lib","${catalina.home}/shared/lib/*.jar"
<小时>
如果您使用 Maven 来驱动您的 Java 项目,您将需要编辑您的POM 文件为您的特定 JDBC 驱动程序设置依赖项.在该
元素中,您需要将
设置为值 provided
以避免捆绑您的副本Web 应用程序的 WAR 文件中的 JDBC 驱动程序.请参阅此答案.
†这个旧的 Tomcat wiki 页面简要提到了创建 shared/lib
文件夹的相同技术,然后编辑 catalina.properties
文件以定义名为 shared.loader
的属性的值.
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 nested in the Tomcat home folder.
I do see a $CATALINA_HOME/lib
path, a lib
folder nested in the Tomcat home folder. I understand this is the proper place for JAR files that should not be copied across "contexts" (web apps) in Tomcat. JDBC drivers are one important example of such.
The problem is that Tomcat populates that $CATALINA_HOME/lib
folder with many JARs for its own use. So for the sake of neatness and ease of administration, it would make sense to have another folder that held nothing but our added JARs, separate from Tomcat’s own JARs. So I can understand the need for something like $CATALINA_HOME/shared/lib
.
The problem is that:
- (a) I see no
shared
folder, - (b) I cannot find any documentation about such a folder.
➥ Is this shared/lib
a real feature, and should I create this pair of folders nested within the Tomcat home folder?
➥ Is $CATALINA_HOME/shared/lib
an undocumented feature, perhaps just a hack that might go away in future updates?
I am asking for Tomcat 9 specifically. But Tomcat 8 is still in common usage, so an answer there too would be of use to other folks.
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
:
- Create the pair of
shared
&lib
folders (with proper file system privileges). - Edit the
$CATALINA_HOME/conf/catalina.properties
to replaceshared.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:
- Create the pair of
shared
&lib
folders (with proper file system privileges) in your outside folder. - Edit the
$CATALINA_HOME/conf/catalina.properties
to replaceshared.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
.
这篇关于$CATALINA_HOME/shared/lib 是 Tomcat 中的真正功能吗?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!