在Tomcat中重新加载Clojure代码

5
我有一个在Tomcat中运行的现有Java Web应用程序,我正在添加一些基本的Clojure支持。目前,我只是将Clojure源文件作为类路径上的资源包含进来,并通过 clojure.lang.RT 调用它。它很原始,但是工作得很好。
然而,我注意到Tomcat的 WebappClassLoader 会缓存通过getResourceAsInputStream()检索到的资源,而Clojure使用这个方法检索和编译源代码。也就是说,进行 (require 'my-ns :reload) 重载时仍然会缓存版本,即使更新后的文件已经在磁盘上可用。有没有办法规避或避免缓存Clojure文件?
经过反复搜索,我想到的最好的办法就是使用反射手动从 WebappClassLoader.resourceEntries 中删除条目,这很糟糕。
我一定是错过了什么。不希望得到像“使用Jetty/Glassfish/JBoss”、“重新启动Tomcat”等答案。
4个回答

2
您无法规避WebappClassLoader的行为。您可以将正在加载的代码移动到其管辖范围之外,例如移到$CATALINA_HOME/lib中,如此描述所述。
您还需要将所有依赖项都移动到那里,只需将实际部署为Web应用程序的.war文件留作一个小型外壳,它期望所有代码已经在其他地方可用。
这将使您摆脱WebappClassLoader的管辖范围,并希望也能避免其语义。(如果它缓存从父类加载器加载的内容,那么我认为它似乎是完全错误的。)

谢谢 Chas。我需要再考虑一下这个问题。把东西放在 lib 里面并不是很方便。我想知道如果使用 *use-context-classloader* 是否会有影响,而不会搞砸其他东西。 - Dave Ray
@DaveRay *use-context-classloader* 默认为 true。将其设置为 false 将导致加载通过加载 Clojure 本身的 ClassLoader 路由,这将不会产生任何影响(如果从 Web 应用程序加载 Clojure),或者会导致破坏(即,如果您将 clojure.jar 放在 $CATALINA_HOME/lib 中但尝试从 Web 应用程序中加载代码)。问:为什么不直接从 Web 应用程序启动 REPL 服务器,连接到它,并以这种方式自由地加载代码呢? - cemerick
谢谢。也许我在如何使用REPL服务器方面不够有创意 :) 假设我有一堆分布在磁盘上的代码文件。我启动带有repl服务器的Tomcat,如何将所有代码上传到服务器? - Dave Ray
具体细节取决于您选择的工具,但通常的工作流程是:(a)连接到REPL;(b)打开/切换到要加载的文件;(c)命令您的工具将文件发送到已连接的REPL。Counterclockwise、SLIME、nrepl.el、vimclojure、Enclojure和其他工具都支持这种工作流程。如果您想详细讨论,请在IRC中与我联系。 :-) - cemerick

0

或者使用一个修补过的Clojure版本,它可以执行类似以下操作:

(io/input-stream (io/resource "bla.clj"))

我在网络上发现了一条评论,指出这个没有被缓存。

(io/resource) 使用上下文类加载器,因此它将通过Tomcat并被缓存。 :( - Dave Ray
@dave-ray 我发现有人声称 .getResource(被 io/resource 使用)没有被缓存。但我不了解 Tomcat。在我的角度,这只是猜测而已。:] - kotarak

0

如果我能让 clojure.lang.RT 以那种方式加载文件,似乎这样做会起作用。否则,(require 'foo :reload) 将继续使用上下文类加载器。 - Dave Ray

0
这与这里描述的cachingAllowed标志有关吗?只是瞎猜。

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