每个 Java JAR 文件都必须有文件 META-INF/MANIFEST.MF
添加。如果它不存在,则不能在(正常)JAR 文件中运行。虽然您可以通过在类路径中放置一个伪造文件(例如,在 ./resources 中)来欺骗此检测器,但这是检测正常 JAR 文件的可靠方法。
问题:
依赖项 JAR 文件有时很草率,并且会用它们自己的 META-INF/MANIFEST.MF 文件污染类路径,因此任何随机的 META-INF/MANIFEST.MF 的存在都不足以在存在“噪声”文件的情况下确定答案。因此,您需要检查您自己的特定META-INF/MANIFEST.MF 文件是否存在。如果您知道 ArtifactId 和 GroupId 的 Maven 值,这很容易做到。
在一个 Leiningen 项目中,project.clj 的第一行看起来像
(defproject demo-grp/demo-art "0.1.0-SNAPSHOT"
对于 demo-grp 的组 ID 和 demo-art 的工件 ID。如果您的文件如下所示:
(defproject demo "0.1.0-SNAPSHOT"
那么组 ID 和工件 ID 都是 demo。您特定的 MANIFEST.MF 看起来像
> cat META-INF/MANIFEST.MF
Manifest-Version: 1.0
Created-By: Leiningen 2.9.1
Built-By: alan
Build-Jdk: 15
Leiningen-Project-ArtifactId: demo-art
Leiningen-Project-GroupId: demo-grp
Leiningen-Project-Version: 0.1.0-SNAPSHOT
Main-Class: demo.core
使用 to ID 字符串设置一个函数来检测您的特定项目 MANIFEST.MF 的存在:
(ns demo.core
(:require [clojure.java.io :as io])
(:gen-class))
(def ArtifactId "demo-art")
(def GroupId "demo-grp")
(defn jar-file? []
(let [re-ArtifactId (re-pattern (str ".*ArtifactId.*" ArtifactId))
re-GroupId (re-pattern (str ".*GroupId.*" GroupId))
manifest (slurp (io/resource "META-INF/MANIFEST.MF"))
f1 (re-find re-ArtifactId manifest)
f2 (re-find re-GroupId manifest)
found? (boolean (and f1 f2))]
found?))
(defn -main []
(println "main - enter")
(println "Detected JAR file: " (jar-file?))
)
您现在可以测试代码了:
~/expr/demo > lein clean ; lein run
main - enter
Detected JAR file: false
~/expr/demo > lein clean ; lein uberjar
Compiling demo.core
Created /home/alan/expr/demo/target/uberjar/demo-art-0.1.0-SNAPSHOT.jar
Created /home/alan/expr/demo/target/uberjar/demo-art-0.1.0-SNAPSHOT-standalone.jar
~/expr/demo > java -jar /home/alan/expr/demo/target/uberjar/demo-art-0.1.0-SNAPSHOT-standalone.jar
main - enter
Detected JAR file: true
“噪音”JAR 文件示例:如果我们执行lein clean; lein run,并在我们的主程序中添加一行
(println (slurp (io/resource "META-INF/MANIFEST.MF")))
我们出去:
Manifest-Version: 1.0
Archiver-Version: Plexus Archiver
Built-By: jenkins
Created-By: Apache Maven 3.2.5
Build-Jdk: 1.8.0_111
我不知道这是从哪里进入 CLASSPATH 的。
附注对于 Leiningen JAR 文件
当使用lein 构建JAR 文件时,它总是将project.clj 文件的副本放在以下位置:
META-INF/leiningen/demo-grp/demo-art/project.clj
因此您也可以将此文件的存在/不存在用作检测器。
更新
好的,MANIFEST.MF 文件似乎高度依赖于您的构建工具。见
因此,您的选择似乎是:
- 对于
lein,您可以使用上述技术。
- 您可以使用另一个答案中
*1 的 REPL 技巧。
- 您始终可以让构建工具在清单中包含自定义键值对,然后检测它。
更新 #2
另一个答案,也许更简单,是使用lein-environ 插件和environ 库(您需要两者)来检测环境(假设您使用lein 创建您的REPL)。你的project.clj 应该是这样的:
:dependencies [
[clojure.java-time "0.3.2"]
[environ "1.2.0"]
[org.clojure/clojure "1.10.2-alpha1"]
[prismatic/schema "1.1.12"]
[tupelo "21.01.05"]
]
:plugins [[com.jakemccrary/lein-test-refresh "0.24.1"]
[lein-ancient "0.6.15"]
[lein-codox "0.10.7"]
[lein-environ "1.2.0"]
]
你需要一个profiles.clj:
{:dev {:env {:env-mode "dev"}}
:test {:env {:env-mode "test"}}
:prod {:env {:env-mode "prod"}}}
还有一个命名空间demo.config,比如:
(ns demo.config
(:require
[environ.core :as environ]
))
(def ^:dynamic *env-mode* (environ/env :env-mode))
(println " *env-mode* => " *env-mode*)
然后你会得到如下结果:
*env-mode* => dev ; for `lein run`
*env-mode* => test ; for `lein test`
*env-mode* => nil ; from `java -jar ...`
您需要输入:
lein with-profile :prod run
生产
*env-mode* => prod