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