0

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

<EDIT>我想跨 WAR 缓存应用程序数据,因为这些数据对它们来说是通用的。(这是一个门户项目,在不同的“视图”之间共享公共数据可能很有用,这些“视图”实现为部署为不同 WAR 的不同 portlet,并且使用 Java 对象缓存比使用中央数据保存服务更快、更简单。 ) </编辑>

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

请参阅:Java、Classpath、Classloading => 同一个 jar/项目的多个版本

请参阅:当同一个类存在于同一服务器上的不同应用程序中时,类加载如何工作?

请参阅:跨类加载器强制转换?

请参阅:什么是 serialVersionUID,我为什么要使用它?

4

3 回答 3

0

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

如果所讨论的 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/任何你想要的东西:“模块优先/父最后”类加载策略应该防止冲突,即使(如本例中)Spring 4.2。 Spring 9 可用于父类加载器,Spring 3.0.7 可用于 WAR 类加载器。但是以这种方式混淆事物对我来说看起来有点“不干净”和混乱。

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

然而,这种方法不允许跨 WAR 缓存:实际上每个 WAR 都会获得自己的私有缓存段。

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

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

于 2017-04-07T12:04:24.830 回答
0

是的,最好的选择是将类放在作为两个应用程序父级的类加载器中。如果lib/ext你的意思是JAVA_HOME/lib/ext,那么我不会推荐。相反,您应该将它们放在CATALINA_HOME/lib目录中。请参阅文档的共享库文件部分,该部分链接到类加载器 HOW-TO文档。

于 2017-04-05T23:03:00.477 回答
0

您可以将公共类(jar)添加shared.loaderconf/catalina.properties. 这些类可用于所有 Web 应用程序,但不适用于 tomcat 本身。

如果您围绕静态单例实现缓存,那么您将能够从不同的 Web 应用程序访问对象。但是,我不知道这是否是最佳做法。例如,它很难扩展,因为它无法将应用程序负载平衡到许多服务器上。

于 2017-04-07T00:17:40.237 回答