使用Lisp或Scheme进行Java程序的运行时配置

时间:2011-05-28 09:16:32

标签: java lisp scheme

我现在看到几个项目的结尾处的实际配置取决于仅在运行时可用的内容。

配置Java程序的典型方法是根据某些特定于应用程序的规则读取一个或多个属性文件,然后根据其值采取操作。在某个时刻,这会破坏,您需要在配置中使用实际的程序逻辑,然后可以用标志指示并向您的应用程序添加代码,然后处理该标志。

我想知道一个小的Lisp配置阅读器模块是否是一个更好的选择,其中要读取的文件不是属性文件,而是一个Lisp程序,然后通过eval来创建表示配置的最终数据结构。然后,运行时库中的一组最小函数将允许字符串操作,甚至可能调用JVM。试想一下“根据当前主机名构建一个URL”。

对使用铃声和口哨声的完整Lisp引擎感兴趣,但只是一个用于此目的的小型库,它可以包含在甚至小程序中,而不需要包含Lisp引擎的大型jar。

这样的库存在吗?

  • 体积小
  • 只需要读取文件+ eval以及从主Java程序中读取结果数据结构的能力
  • 一个小的Lisp运行时库
  • 速度不太重要。
  • 积极维护。

建议?


编辑2012-01-20:我最初发现所有候选人都不受欢迎,但已决定将此作为Maven练习the 1998 jscheme 1.4 release。项目https://github.com/ravn/jscheme-1998


编辑2012-12-11:事实证明,在Scheme中解释的程序和宿主Java程序之间的集成层比我原先想的更重要,而且我需要在项目能够在运行时提供带有JAX-WS注释的类,我无法使用JScheme,但我可以使用Groovy。允许在库中使用代码片段的小型配置库的想法仍然有效,但我最终需要更多才能使它有用。

4 个答案:

答案 0 :(得分:8)

我知道你想要一个小尺寸和运行时。 Scheme是易于嵌入的常用选择,也是我的首选。但是,我没有关于该领域的信息。我的第二个选择是 Clojure

  • 不小;罐子是~3 MB
  • 用于简单配置读取的过度杀伤,但可以安全地忽略额外功能
  • 〜从Java轻松打电话:Calling clojure from java
  • 完全,出色地访问JVM
  • 可能会为启动调用一小部分,这可能太多了(见下文)
  • 现在我尝试用Clojure复制示例的功能,我觉得Clojure不适合这些脚本(rc等)。 Clojure 1.3将解决一些启动惩罚,但我不知道速度改进的程度

使用Clojure的相应代码

import clojure.lang.RT;
import clojure.lang.Var;
import clojure.lang.Compiler;
import java.io.FileReader;
import java.io.FileNotFoundException;

public class ClojTest {
    public static void main(String[] args) throws Exception {
        try {
            Compiler.load(new FileReader("hello.clj"));
        } catch(FileNotFoundException e) { return; }

        System.out.println("Message: '"+ RT.var("user", "msg").get() +"'");

        // Values
        int answer = (Integer) RT.var("user", "answer").get();

        // Function calls
        System.out.println(RT.var("user", "countdown").invoke(42));
    }
}

hello.clj

(ns user)
(defn countdown [n]
  (reduce + (range 1 (inc n))))

(def msg "Hello from Clojure!")
(def answer (countdown 42))

运行time java ClojTest一段时间会产生平均 0.75秒。 Clojure编译脚本会受到相当大的惩罚!

答案 1 :(得分:8)

好的,更小的解决方案是嵌入式Java方案。在许多实现中,我发现并测试了JScheme。 (API看起来没问题:http://jscheme.sourceforge.net/jscheme/doc/api/index.html

Java中的一个简单主程序:

import jscheme.JScheme;
import jscheme.SchemeException;
import java.io.*;
public class SchemeTest {
    public static void main(String[] args) {
        JScheme js = null;
        try {
            js = new JScheme();
            js.load(new FileReader("config.scm"));
        } catch (FileNotFoundException e) { return; }

        System.out.println("Message: '" + js.eval("msg") + "'");

        // Values
        int answer = (Integer) js.eval("answer");

        // Function calls
        System.out.println(js.call("countdown", 42));
    }
}

示例config.scm

(define (countdown x)
  (define (loop x acc)
    (if (= x 0)
      acc
      (loop (- x 1) (+ acc x))))
  (loop x 0))

;;; config variables
(define msg "Hello from JScheme!")
;; tail calls are optimized as required
(define answer (countdown 42))

每次启动时都会解释该方案,因此这是配置的不错选择。 JScheme的优点包括:

  • 良好的JVM集成
  • 显然是一个完整的Scheme实现
  • 小尺寸(572 kB)
  • 快速,从Java轻松调用

基准更新:此代码在 0.13秒时间内运行。与Clojure版本的时间相比,这非常快。

答案 2 :(得分:6)

尝试SISC,它是一个相当小的(300kb jar)Scheme实现,没有花里胡哨。使用Java进行粘贴是微不足道的,对于纯粹的解释器来说,执行速度相当令人印象深刻。

答案 3 :(得分:3)

Clojure非常出色,可嵌入,并且在调用Java库方面具有非常好的互操作性。但它并不是特别小(你得到一个完整的编译器和相当不错的运行时库)。如果你对这种功能有更广泛的要求,还是值得考虑 - 我发现Clojure可以作为Java代码的优秀动态“粘合剂”。

否则,你最好的选择可能是一个很小的嵌入式Scheme解释器。

有可能在这个链接上使用JScheme的早期版本(1998),它只有大约30k的jar文件: http://norvig.com/jscheme.html

否则,可能有可能在几百行Java中写一些更小的内容......考虑到Scheme的核心有多小,它可能只是一个周末项目。如果你想为Scheme编写一个迷你解释器,下面的页面非常有趣: http://archives.evergreen.edu/webpages/curricular/2000-2001/fofc00/eval.html