【问题标题】:Clojure hot code swapping for uberjars/.classesuberjars/.classes 的 Clojure 热代码交换
【发布时间】:2013-02-15 05:53:05
【问题描述】:

我想在项目更新之间进行热代码交换,但我还没有找到有关如何动态加载 .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

【问题讨论】:

  • 我认为重启客户端会更容易很多。为什么不能重启一下?
  • @NikitaBeloglazov 如果是关于在开发时加载代码,我会热加载源代码或重新启动。但我希望为客户端应用程序获得类似 erlang 热代码交换的东西。是的,我知道它不是那么好,很容易让我的程序崩溃,但这是我想尝试的东西。

标签: clojure osgi


【解决方案1】:

插件框架方法

您已声明希望进行热代码交换,但您实际需要的是松散耦合的模块以及在运行时进行解析的能力。坦率地说,任何插件框架都可能有所帮助,包括成熟的 OSGi(将在下面介绍)。

由于您正在进行某种 PoC,我建议您查看以下示例:

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

可以提出定义simlle升级方案:

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

以这种方式,元应用程序将能够提供新的或更新的功能而无需重新启动。所以你可以:

  1. 尝试使用一些简单的java插件框架(比如Java Simple Plugin Framework. 5 minutes and it works. No XML.这种方式好像有点难看
  2. 使用 clojure 的动态特性,正如 here 所建议的那样

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

在实现方面,Waterfront 是基于上下文的 图案。它允许事件处理程序在函数式中进行通信 (无副作用)方式。最重要的是有一个插件加载器 加载 Waterfront 中指定的插件的机制 配置文件。这意味着可以轻松添加功能 或删除(在调试时非常有用!)。

OSGI 方法

正如建议的那样,OSGi 似乎是解决您的问题的好方法。另请注意,OSGi 很好,很成熟,提供了很多开箱即用的东西,但它也有些复杂:

顺便说一句,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的Producer-Consumer示例:

编码愉快。

【讨论】:

  • stackoverflow.com/questions/1810231/defining-a-spi-in-clojure -- 我试过了(虽然是真的 (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 互操作选项仍然是一个选项。
  • 而且 clojure.osgi 不是 lein 项目,这让我很伤心。
  • waterfront 使用加载文件,它“顺序​​读取和评估文件中包含的表单集”。 .clj,再说一遍,不是.class
【解决方案2】:

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

【讨论】:

  • 我会试试那个。在 clojure 中使用它的成功示例可能会有所帮助。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2012-08-30
  • 2011-02-27
  • 1970-01-01
  • 1970-01-01
  • 2014-09-16
  • 1970-01-01
  • 2014-02-28
相关资源
最近更新 更多