Clojure热代码替换适用于uberjars/.classes

8
我希望在项目更新时进行热代码交换,但我没有找到有关如何动态加载.class文件的任何信息。
更具体地说,我想要以下内容:
1. 运行lein uberjar,获取some-client-0.0.0-standalone.jar。 2. 使用java -jar some-client-0.0.0-standalone.jar运行它。 3. 对项目进行更改。获取新的程序版本some-client-0.0.1-standalone.jar,将其复制到some-client-0.0.0-standalone.jar目录中。 4. 客户端接收到升级到新版本所需的命令序列。 5. (可选)更新资源。不再使用旧jar中的资源。 6. (可选)现在可以删除some-client-0.0.0-standalone.jar

2
我觉得重新启动客户端会容易得多。你为什么不能直接重启它呢? - Mikita Belahlazau
2
如果是在开发过程中加载代码,我会热加载源代码或重新启动。但我希望为客户端应用程序获得类似于Erlang热代码交换的功能。是的,我知道这不是很好,可能会导致程序崩溃,但这是我想尝试的东西。 - desudesudesu
2个回答

6

插件框架方法

您已经表达了您想要热代码交换,但实际上您需要的是松散耦合的模块和能够在运行时进行解析的能力。坦率地说,任何插件框架都可以帮助,包括成熟的OSGi(将在下面介绍)。

enter image description here

既然你正在进行某种 PoC,我建议您查看以下示例:

  1. 您有一个具有一些扩展点(比喻解释)定义的元应用程序
  2. 要升级或替换的功能将被实现为松耦合模块(插件)
  3. 元应用程序通过请求或自动执行解析,以查找更新的“功能”(根据定义的扩展点)

有了这个定义,可以提出简单的升级方案:

  1. 用户使用应用程序
  2. 用户安装(复制)带有一个或多个扩展点的新实现的 JAR(其他类型的 bundle)
  3. 用户触发全局系统解析或扫描新更新或每次用户尝试访问某些功能时系统执行解析

通过这种方式,元应用程序将能够在不重新启动的情况下提供新的或更新的功能。所以你可以:

  1. 尝试使用一些简单的Java插件框架(例如,Java Simple Plugin Framework。只需5分钟即可操作,无需XML。 这种方法似乎有点丑陋
  2. 使用Clojure的动态特性,如此处所建议的

您还可以查看并采用Waterfront(Clojure编辑器)的发现(可能需要增强生命周期管理等)

关于实现方面,Waterfront基于上下文模式。它允许事件处理程序以函数式(无副作用)的方式进行通信。在此基础上,有一个插件加载机制,可以加载在Waterfront配置文件中指定的插件。这意味着可以轻松地添加或删除功能(在调试时非常有用!)。 OSGI方法 正如建议的那样,OSGi似乎是解决您问题的好方法。请注意,OSGi很好、成熟,并且提供了很多开箱即用的东西,但它也有些复杂:

enter image description here

顺便说一下,OSGi是Clojure社区的长期目标。你可以查看Clojure Todo

> better modularization for OSGi etc 
>  * names
>  * no single namespace pool
>  * namespaces found via classes, thus tracks classloader and modules 
>  * deal with import proxying a la Class.forName stack walk?

已经有一些解决方案可用:

  1. clojure-osgi-utils
  2. clojure.osgi

第二个项目使用Clojure和OSGi提供生产者-消费者示例:

愉快编码!


https://dev59.com/U0rSa4cB1Zd3GeqPXIu1 -- 我尝试过 (while true (Thread/sleep 5000) (load "/class_that_changes") (println (eval 'class_that_changes/hello)) (eval '(chass_that_changes/hello)))。它可以重新加载.clj文件,但是无法重新加载.class文件。class_that_changes/hello指向同一对象。我做错了吗? jspf -- 这可能是一个选择,但需要用Java编写代码。然而,Java互操作性仍然是一个选项。 - desudesudesu
1
而 clojure.osgi 不是 lein 项目,这让我感到难过。 - desudesudesu
Waterfront使用load-file,它“顺序地读取并评估文件中包含的一组表单”。再次强调,这里使用的是.clj而不是.class - desudesudesu

2

如果需要在运行时从jar文件中重新加载严格的代码,您可能需要研究OSGi类加载器。 对于Clojure代码,您可以在客户端上启动侦听本地端口的nrepl,然后当您想要重新加载代码时,连接到该端口并调用load-file


我会试一下。在Clojure中使用它的成功示例可能会有所帮助。 - desudesudesu

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