Java 如何在不将包含JAR的类放入/lib/ext的情况下,跨多个WAR在Tomcat上缓存对象?

Java 如何在不将包含JAR的类放入/lib/ext的情况下,跨多个WAR在Tomcat上缓存对象?,java,tomcat,caching,classloader,web-container,Java,Tomcat,Caching,Classloader,Web Container,如何在服务器范围内(缓存范围在此服务器上跨越多个WAR)缓存JAR中的类实例,该JAR包含在web容器(服务器,例如Tomcat)的多个WAR中相同的二进制文件 我想跨战争缓存应用程序数据,因为这些数据对战争来说是公共的。(这是一个门户项目,在该项目中,跨不同的“视图”共享公共数据非常有用,这些视图作为部署为不同WAR的不同Portlet实现,使用Java对象缓存比使用中央数据保存服务更快、更简单。) 那有可能吗?或者,是否需要将这样的JAR放在公共父类加载器(如in/lib/ext)访问的路径

如何在服务器范围内(缓存范围在此服务器上跨越多个WAR)缓存JAR中的类实例,该JAR包含在web容器(服务器,例如Tomcat)的多个WAR中相同的二进制文件

我想跨战争缓存应用程序数据,因为这些数据对战争来说是公共的。(这是一个门户项目,在该项目中,跨不同的“视图”共享公共数据非常有用,这些视图作为部署为不同WAR的不同Portlet实现,使用Java对象缓存比使用中央数据保存服务更快、更简单。)

那有可能吗?或者,是否需要将这样的JAR放在公共父类加载器(如in/lib/ext)访问的路径上

见:

见:

见:


请参阅:

是的,最好的选择是将类放入作为两个应用程序父级的类装入器中。如果你所说的
lib/ext
是指
JAVA\u HOME/lib/ext
,那么我不建议这样做。相反,您应该将它们放在
CATALINA_HOME/lib
目录中。请参阅文档的链接部分。

您可以将公共类(JAR)添加到
conf/catalina.properties
中的
shared.loader
属性中。所有web应用程序都可以使用这些类,但tomcat本身不能使用

如果在静态单例周围实现缓存,则可以从不同的web应用程序访问对象。但我不知道这是否是最佳实践。例如,它很难扩展,因为它无法在多台服务器上平衡应用程序的负载。

答案似乎是“视情况而定”

如果所讨论的JAR(或类)没有与服务器上部署的其他组件冲突的依赖项,两个建议的解决方案(
CATALINA_HOME/lib/ext/
CATALINA_HOME/conf/CATALINA.properties::shared.loader
)都应该正常工作。因此,两者都是“正确答案”,我看不出哪一个比另一个“更正确”

然而,当我第一次问这个问题时,我忽略了一个关键的细节(但这并不能使它失效):在我的例子中,所讨论的JAR需要Spring 4.2.9.RELEASE(和其他依赖项),但部署在同一服务器上的其他相关WAR包含并需要Spring 3.0.7。(要缓存的对象不依赖于Spring,但JAR的设计并没有考虑到这个问题,它还包含其他依赖于Spring的相关代码,这些代码现在很难分离。)

一般来说,只要所有已部署的WAR都包含它们所需的一切,就可以放入
CATALINA_HOME/lib/ext/
任何您想要的内容:“模块优先/父级最后”类加载策略应该可以防止冲突,即使(如本例所示)Spring4.2.9可用于父类加载器,Spring3.0.7可用于WAR类加载器。但在我看来,这样把事情搞混有点“不干净”和混乱

因此,我决定使用“待缓存”对象的类加载器哈希代码作为映射中的键,其中缓存的数据是值。然后,所有缓存的数据都被“classloader”选择,这将自动且透明地确保分配兼容性。如果服务器上还部署了另一个WAR,该WAR可能会更改并使缓存的数据无效,则它可以从缓存中删除整个地图,从而强制“读取访问”WAR在下次访问时重新加载数据

但是这种方法不允许跨战争缓存:实际上,每一场战争都会有自己的私有缓存段

另一种方法是有意地将所有数据转换到缓存中,并与e进行交换。GJSON,以便为缓存的数据获取“自然全局”数据类型,如
java.lang.String
。如果从项目一开始就选择,对我来说,这似乎是最干净的方式,但是如果已经有一个复杂的(并且通常可以工作的)实现,这可能会导致一些工作要做


欢迎对此自我回答发表评论

我不明白你的问题,你是想跨战争缓存数据还是想跨战争加载类(JAR)?@javaguy see EDIT。非常有趣的功能!很难在这里选择正确答案,因为这两个答案(这一个和@brett kail的答案)都是有效的候选答案。