我对如何在tomcat中发生类加载感到困惑。如果我的问题听起来很愚蠢,请耐心等待。
我们在单个tomcat服务器上部署多个spring webapps。为了减少内存占用,我们考虑在tomcat lib文件夹中安装spring,hibernate和数据库驱动程序jar,以便所有webapp共享。
我首先将spring依赖项标记为provided
并将这些jar复制到tomcat lib。但是在服务器启动时,我开始获得多个ClassNotFoundErrors
,例如commons-logging
,commons-fileupload
,jackson
,所以我不得不将这些jar移到tomcat lib。
我尝试关注this链接,并将spring-context和spring-web带回应用程序之战。但它没有工作,在WebApplicationIntializer
初始化期间在某些类上获得了ClassNotFound。我试图理解classes getting loaded in tomcat的顺序,但不太了解。
然后我找到了JDBC driver loading的完全不同的解释,这与所有其他解释相矛盾,让我完全糊涂了。
当我读到更多内容时,我认为将弹簧罐移到tomcat lib并不是一个正确的方法,但仍然没有一个好的推理。然后为什么JDBC驱动程序有效?有人可以解释一下吗?每个webapp的classloader也会创建每个类的副本吗?
编辑1:我开始知道春季罐中的少数依赖项是optional
,如果在我的webapp中使用,则需要它们。所以spring-web依赖于jackson
库,但对于我的应用程序是可选的。因此,我需要找出我的项目所需的所有罐子,并且春天也需要这些罐子,这些罐子需要移动到tomcat lib。
答案 0 :(得分:2)
我会尝试解释我所知道的事情。
在tomcat上部署WAR时,类加载将以这种方式进行:
在你的情况下发生的事情是spring也有很多依赖关系,如果你把它打包在你的战争中,它的依赖关系也会被打包,一切都会好起来的。但是由于你将spring定义为提供的,所以它的所有依赖关系都被认为是提供的,当你把它放在/ lib文件夹中时,spring是可访问的,但它的依赖关系不是。
您需要做的是将所有spring依赖项和依赖项的依赖项(等)放在lib文件夹中。另一种解决方案是在类加载层次结构中定义一个中间WAR,它将包含所有常用的库。
答案 1 :(得分:0)
如果您想创建这种类型的瘦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/