我正在尝试在创建uberjar
时理解“Lieningen”的行为。以下是再现行为的最小示例:
(ns my-stuff.core
(:gen-class))
(def some-var (throw (Exception. "boom!")))
(defn -main [& args]
(println some-var))
当使用lein run
执行此操作时,它显然会因异常而失败。但是,我不明白为什么执行lein uberjar
也会因变量定义的异常而失败?为什么执行lein uberjar
尝试评估变量值?这是特定的uberjar
任务,还是我错过了关于Clojure或Leiningen更重要的内容?
答案 0 :(得分:12)
为了编译uberjar的命名空间(如果你打开了AOT),clojure编译器必须加载你的命名空间。这将始终调用所有顶级副作用。
处理此问题的最佳方法是不要在顶级代码(无论是def
形式内部还是外部)中产生副作用,并使用初始化函数来实现所需的任何启动副作用。
解决方法可以是创建一个使用内省的小命名空间在运行时加载其余代码但不在编译时加载 - 使用如下函数:
(defn -main
[]
(require 'my.primary.ns)
((resolve 'my.primary.ns/start)))
如果编译了该命名空间,jvm可以找到-main并运行它,尽管你的其他代码都没有被编译。运行时require
将使Clojure编译器仅在运行时加载其余代码,并且需要resolve
以便-main
将干净地编译 - 它返回引用的var,然后调用时调用你的函数。