Spring JAR包在Tomcat lib文件夹中

12
我不太清楚Tomcat中的类加载是如何进行的,我们在单个Tomcat服务器上部署了多个Spring Web应用程序。为了减少内存占用,我们考虑将Spring、Hibernate和数据库驱动程序JAR文件放在Tomcat lib文件夹中,以便这些文件能被所有Web应用程序共享。我首先标记Spring依赖关系为“provided”,并将这些JAR文件复制到Tomcat lib中。但是,在服务器启动时,我开始收到多个ClassNotFoundErrors错误,例如对于commons-logging、commons-fileupload和jackson等。因此,我不得不将这些JAR文件也移动到Tomcat lib中。但是这让我感到有些可疑。如果将来我向项目添加另一个Spring依赖项,例如Spring-data-cassandra,是否还需要移动其相关的JAR文件?这可能是无法解决的问题。此外,我可能会在运行时遇到CNF错误。
我试图跟随this链接,并将spring-context和spring-web带回应用程序war。但是它没有起作用,在WebApplicationIntializer初始化期间出现了一些类的ClassNotFound错误。我试图理解在tomcat中加载类的顺序,但并没有理解太多。
然后我找到了一个完全不同的JDBC驱动程序加载解释,这有点与所有其他解释相矛盾,让我完全困惑了。
随着我阅读更多,我认为将Spring JAR文件移动到Tomcat lib中不是正确的方法,但仍然没有得到充分的理由。那么为什么JDBC驱动程序可以工作呢?有人可以解释一下吗?此外,每个Web应用程序的类加载器是否会创建每个类的副本?

编辑1:我了解到spring jars中有一些依赖是可选的,如果在我的webapp中使用,将会被需要。所以spring-web依赖于jackson库,但对于我的应用程序来说是可选的。因此,我需要找出哪些jar包是我的项目所需的,并且也是spring所需的,这些jar包需要移动到tomcat lib中。

2个回答

5

我将尝试解释我所知道的内容。

当您在Tomcat上部署WAR时,类加载会按照以下方式进行:

  1. 在您的WAR classLoader中查找要加载的类
  2. 如果未找到,请移至其父级(Tomcat /lib文件夹)

在您的情况下发生的情况是,Spring也具有许多依赖项,如果将其打包到WAR中,则其依赖项也将被打包,并且一切都将正常工作。但是,由于您定义了提供的Spring,因此其所有依赖项也被认为是提供的,而当您将其放入/lib文件夹中时,可以访问Spring,但不能访问其依赖项。

您需要做的是将所有Spring依赖项和依赖项的依赖项(等等)也放在lib文件夹中。另一种解决方案是在您的类加载层次结构中定义一个中间WAR,其中包含所有常见库。


感谢您的输入。看起来造成问题的依赖关系是可选的。因此,找出我需要的传递性依赖关系真的很困难。 - sidgate
如果你使用 Maven 来构建你的 WAR 文件,它会将所有的传递依赖打包到 WAR 的构件中。 - Victor Sorokin

0
如果您喜欢创建这种类型的“thin WAR”,一种解决方案是首先收集所有运行时/提供的依赖项,然后将它们明确地复制到Tomcat的公共(或共享)库目录下:
如果在Maven项目中,请在“target/dependency”下收集所有内容(包括传递依赖项):
mvn dependency:copy-dependencies -DincludeScope=runtime
mvn dependency:copy-dependencies -DincludeScope=provided

之后,复制到库中。例如:

cp target/dependency/*.jar /usr/local/tomcat/lib/

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接