Spring 个 jars 在 tomcat 个 lib 文件夹中
Spring jars in tomcat lib folder
我对 class 加载如何发生在 tomcat 中感到非常困惑。如果我的问题听起来很愚蠢,请耐心等待。
我们在单个 tomcat 服务器上部署多个 spring 网络应用程序。为了减少内存占用,我们考虑在 tomcat lib 文件夹中放置 spring、hibernate 和数据库驱动程序 jar,以便所有 Web 应用程序共享它们。
我首先将 spring 依赖项标记为 provided
,然后将这些 jar 复制到 tomcat 库。但是在服务器启动时,我开始获得多个 ClassNotFoundErrors
,例如 commons-logging
、commons-fileupload
、jackson
,所以我不得不将这些罐子也移动到 tomcat 库.
但后来这开始让人觉得可疑。如果将来我向我的项目添加另一个 spring 依赖项,比如 spring-data-cassandra。我还需要移动它的依赖罐吗?这可能是无止境的。另外,我可能会在运行时遇到 CNF 错误。
我试着跟着this link and brought back spring-context and spring-web back to application war. But it didn't work, got ClassNotFound on some class during WebApplicationIntializer
initialization. I tried to understand the order of classes getting loaded in tomcat,但听不懂。
然后我找到了 JDBC driver loading 的完全不同的解释,这与所有其他解释有点矛盾,让我完全困惑。
随着我阅读更多,我认为将 spring jar 移动到 tomcat lib 不是正确的方法,但仍然没有很好的推理。然后为什么 JDBC 驱动程序工作?有人可以解释一下吗?每个 webapp 的 classloader 是否也会为每个 class 创建一个副本?
编辑 1:我了解到 spring jar 中 optional
很少有依赖项,如果在我的 webapp 中使用,则将是必需的。所以 spring-web 依赖于 jackson
库,但对于我的应用程序来说是可选的。所以我需要找出我的项目需要哪些所有 jar,spring 也需要这些 jar,这些 jar 需要移动到 tomcat lib.
我会尽量解释我所知道的。
当您在 tomcat 上部署 WAR 时,class 加载将以这种方式进行:
- 在您的 WAR classLoader
中寻找要加载的 class
- 如果找不到则移至父文件夹(tomcat /lib 文件夹)
你的情况是 spring 也有很多依赖项,如果你将它打包在你的 war 中,它的依赖项也会被打包并且一切都会正常工作.但是因为你定义了 spring 作为 provided ,所以它的所有依赖也被认为是 provided ,当你把它放在 /lib 文件夹中时, spring 是可以访问的,但它的依赖不是。
你需要做的是将所有spring 依赖项和依赖项的依赖项(等)也放在lib 文件夹中。另一种解决方案是在 class 加载层次结构中定义一个中介 WAR,它将包含所有公共库。
如果您更喜欢创建这种类型的瘦 WAR,一个解决方案是首先收集所有 runtime/provided 依赖项,然后将它们显式复制到 Tomcat 的公共(或共享)库目录:
如果在 Maven 项目下,收集 target/dependency
下的所有内容(包括传递依赖项):
mvn dependency:copy-dependencies -DincludeScope=runtime
mvn dependency:copy-dependencies -DincludeScope=provided
之后,复制到图书馆。例如:
cp target/dependency/*.jar /usr/local/tomcat/lib/
我对 class 加载如何发生在 tomcat 中感到非常困惑。如果我的问题听起来很愚蠢,请耐心等待。
我们在单个 tomcat 服务器上部署多个 spring 网络应用程序。为了减少内存占用,我们考虑在 tomcat lib 文件夹中放置 spring、hibernate 和数据库驱动程序 jar,以便所有 Web 应用程序共享它们。
我首先将 spring 依赖项标记为 provided
,然后将这些 jar 复制到 tomcat 库。但是在服务器启动时,我开始获得多个 ClassNotFoundErrors
,例如 commons-logging
、commons-fileupload
、jackson
,所以我不得不将这些罐子也移动到 tomcat 库.
但后来这开始让人觉得可疑。如果将来我向我的项目添加另一个 spring 依赖项,比如 spring-data-cassandra。我还需要移动它的依赖罐吗?这可能是无止境的。另外,我可能会在运行时遇到 CNF 错误。
我试着跟着this link and brought back spring-context and spring-web back to application war. But it didn't work, got ClassNotFound on some class during WebApplicationIntializer
initialization. I tried to understand the order of classes getting loaded in tomcat,但听不懂。
然后我找到了 JDBC driver loading 的完全不同的解释,这与所有其他解释有点矛盾,让我完全困惑。
随着我阅读更多,我认为将 spring jar 移动到 tomcat lib 不是正确的方法,但仍然没有很好的推理。然后为什么 JDBC 驱动程序工作?有人可以解释一下吗?每个 webapp 的 classloader 是否也会为每个 class 创建一个副本?
编辑 1:我了解到 spring jar 中 optional
很少有依赖项,如果在我的 webapp 中使用,则将是必需的。所以 spring-web 依赖于 jackson
库,但对于我的应用程序来说是可选的。所以我需要找出我的项目需要哪些所有 jar,spring 也需要这些 jar,这些 jar 需要移动到 tomcat lib.
我会尽量解释我所知道的。
当您在 tomcat 上部署 WAR 时,class 加载将以这种方式进行:
- 在您的 WAR classLoader 中寻找要加载的 class
- 如果找不到则移至父文件夹(tomcat /lib 文件夹)
你的情况是 spring 也有很多依赖项,如果你将它打包在你的 war 中,它的依赖项也会被打包并且一切都会正常工作.但是因为你定义了 spring 作为 provided ,所以它的所有依赖也被认为是 provided ,当你把它放在 /lib 文件夹中时, spring 是可以访问的,但它的依赖不是。
你需要做的是将所有spring 依赖项和依赖项的依赖项(等)也放在lib 文件夹中。另一种解决方案是在 class 加载层次结构中定义一个中介 WAR,它将包含所有公共库。
如果您更喜欢创建这种类型的瘦 WAR,一个解决方案是首先收集所有 runtime/provided 依赖项,然后将它们显式复制到 Tomcat 的公共(或共享)库目录:
如果在 Maven 项目下,收集 target/dependency
下的所有内容(包括传递依赖项):
mvn dependency:copy-dependencies -DincludeScope=runtime
mvn dependency:copy-dependencies -DincludeScope=provided
之后,复制到图书馆。例如:
cp target/dependency/*.jar /usr/local/tomcat/lib/