如何在不使用 uberjar 的情况下 运行 来自新鲜 lein 应用程序的 jar?
How can I run a jar from a fresh lein app without using uberjar?
我发现来自 lein 的新应用可以 运行 作为 uberjar 而不是 jar。它应该以这种方式工作,还是我的设置有问题?
$ lein new app feedme
$ cd feedme
Lein uberjar 工作正常:
$ lein uberjar
Compiling feedme.core
Created .../feedme/target/uberjar+uberjar/feedme-0.1.0-SNAPSHOT.jar
Created .../feedme/target/uberjar/feedme-0.1.0-SNAPSHOT-standalone.jar
$ java -jar target/uberjar/feedme-0.1.0-SNAPSHOT-standalone.jar
Hello, World!
Lein jar 失败:
$ lein jar
Warning: The Main-Class specified does not exist within the jar. It may not be executable as expected. A gen-class directive may be missing in the namespace which contains the main method.
Created .../feedme/target/feedme-0.1.0-SNAPSHOT.jar
$ java -jar target/feedme-0.1.0-SNAPSHOT.jar
Error: Could not find or load main class feedme.core
在 core.clj 的 ns 部分有一个 :gen-class 指令,所以我不确定问题是什么:
$ cat src/feedme/core.clj
(ns feedme.core
(:gen-class))
(defn -main
"I don't do a whole lot ... yet."
[& args]
(println "Hello, World!"))
Lein jar 仅将您自己的代码包装在一个 jar 中,以便它可以被其他项目使用,例如。它不包括您的任何依赖项(将在您的 pom.xml
中声明),包括 clojure 本身。没有有效的 class 到 运行(例如 clojure.main
),它不能 运行 您的代码。下一个问题是您的 require 语句引用了不在您的 class 路径上的工件中的定义(除非某些程序加载了您的 pom.xml
并且知道如何实现这些依赖关系)。
查看任何 jar(它们只是 zip 文件)的 MANIFEST.MF 文件。该文件将告诉您主要 class。因此,如果您确保 MANIFEST.MF 进入您的 jar 文件,它将可以自行运行。 jar 文件包含 .class 文件并引用其他 jar 文件 - 因此只要引用的 jar 文件可访问,它就可以构成自己的 class 路径。
我刚刚查看了几个 jar 文件。 MANIFEST.MF
在 META-INF
中。这是一个示例内容:
Manifest-Version: 1.0
Ant-Version: Apache Ant 1.8.3
Created-By: 1.7.0_76-b13 (Oracle Corporation)
Main-Class: com.cmts.client.applic.upgrader.UsersGUI
Date-Created: 15/07/2015 02:23 AM
Class-Path: ../lib/config-1.2.1.jar
../lib/scala-library-2.11.5.jar
../lib/org.springframework.beans-3.1.0.RC2.jar
../lib/org.springframework.aop-3.1.0.RC2.jar
这个是 Ant 创建的。不知道lein是不是也这样。但即使没有,也没有理由不能将 META-INF\MANIFEST.MF
放入罐子中。然后您将拥有一个可自运行的 jar 文件。
稍后编辑 - lein 清单示例:
:manifest {"Class-Path" "../lib/clojure-1.8.0.jar"}
你得到 Error: Could not find or load main class feedme.core
因为 jar 不包含 feedme/core.class 文件。如果你 运行 jar -tf target/feedme-0.1.0-SNAPSHOT.jar
你会发现它根本不包含任何 .class 文件。 lein jar
默认情况下不编译源代码。这是预期的行为:除非请求 AOT 编译,否则 Clojure 会即时编译代码。如果 uberjar AOT 编译 is 通过 {:uberjar {:aot :all}}
配置文件在 project.clj 文件中请求(您可以通过将 uberjar 配置文件更改为空配置文件来做一个小实验 {:uberjar {}}
,那么 lein uberjar && java -jar target/uberjar/feedme-0.1.0-SNAPSHOT-standalone.jar
将导致完全相同的错误)。
您可以运行 lein with-profile uberjar jar
来编译您的代码。但是如果你 运行 java -jar target/uberjar+uberjar/feedme-0.1.0-SNAPSHOT.jar
你会得到另一个错误:java.lang.NoClassDefFoundError: clojure/lang/IFn
。正如 noisesmith 所指出的,lein jar
没有打包任何依赖项,包括 Clojure 本身。因此,您必须在 class 路径中显式指定 Clojure:java -cp "$HOME/.m2/repository/org/clojure/clojure/1.8.0/clojure-1.8.0.jar:target/uberjar+uberjar/feedme-0.1.0-SNAPSHOT.jar" feedme.core
。这将打印 Hello, World! (假设您的本地 Maven 存储库中有 Clojure 1.8,您可能需要先获取它或更改 path/version)。
无需编译,您可以 运行 使用 lein jar
生成的 jar:java -cp "$HOME/.m2/repository/org/clojure/clojure/1.8.0/clojure-1.8.0.jar:target/feedme-0.1.0-SNAPSHOT.jar" clojure.main --main feedme.core
(同样,您的 Clojure jar 的 path/version 可以不同)。
我发现来自 lein 的新应用可以 运行 作为 uberjar 而不是 jar。它应该以这种方式工作,还是我的设置有问题?
$ lein new app feedme
$ cd feedme
Lein uberjar 工作正常:
$ lein uberjar
Compiling feedme.core
Created .../feedme/target/uberjar+uberjar/feedme-0.1.0-SNAPSHOT.jar
Created .../feedme/target/uberjar/feedme-0.1.0-SNAPSHOT-standalone.jar
$ java -jar target/uberjar/feedme-0.1.0-SNAPSHOT-standalone.jar
Hello, World!
Lein jar 失败:
$ lein jar
Warning: The Main-Class specified does not exist within the jar. It may not be executable as expected. A gen-class directive may be missing in the namespace which contains the main method.
Created .../feedme/target/feedme-0.1.0-SNAPSHOT.jar
$ java -jar target/feedme-0.1.0-SNAPSHOT.jar
Error: Could not find or load main class feedme.core
在 core.clj 的 ns 部分有一个 :gen-class 指令,所以我不确定问题是什么:
$ cat src/feedme/core.clj
(ns feedme.core
(:gen-class))
(defn -main
"I don't do a whole lot ... yet."
[& args]
(println "Hello, World!"))
Lein jar 仅将您自己的代码包装在一个 jar 中,以便它可以被其他项目使用,例如。它不包括您的任何依赖项(将在您的 pom.xml
中声明),包括 clojure 本身。没有有效的 class 到 运行(例如 clojure.main
),它不能 运行 您的代码。下一个问题是您的 require 语句引用了不在您的 class 路径上的工件中的定义(除非某些程序加载了您的 pom.xml
并且知道如何实现这些依赖关系)。
查看任何 jar(它们只是 zip 文件)的 MANIFEST.MF 文件。该文件将告诉您主要 class。因此,如果您确保 MANIFEST.MF 进入您的 jar 文件,它将可以自行运行。 jar 文件包含 .class 文件并引用其他 jar 文件 - 因此只要引用的 jar 文件可访问,它就可以构成自己的 class 路径。
我刚刚查看了几个 jar 文件。 MANIFEST.MF
在 META-INF
中。这是一个示例内容:
Manifest-Version: 1.0
Ant-Version: Apache Ant 1.8.3
Created-By: 1.7.0_76-b13 (Oracle Corporation)
Main-Class: com.cmts.client.applic.upgrader.UsersGUI
Date-Created: 15/07/2015 02:23 AM
Class-Path: ../lib/config-1.2.1.jar
../lib/scala-library-2.11.5.jar
../lib/org.springframework.beans-3.1.0.RC2.jar
../lib/org.springframework.aop-3.1.0.RC2.jar
这个是 Ant 创建的。不知道lein是不是也这样。但即使没有,也没有理由不能将 META-INF\MANIFEST.MF
放入罐子中。然后您将拥有一个可自运行的 jar 文件。
稍后编辑 - lein 清单示例:
:manifest {"Class-Path" "../lib/clojure-1.8.0.jar"}
你得到 Error: Could not find or load main class feedme.core
因为 jar 不包含 feedme/core.class 文件。如果你 运行 jar -tf target/feedme-0.1.0-SNAPSHOT.jar
你会发现它根本不包含任何 .class 文件。 lein jar
默认情况下不编译源代码。这是预期的行为:除非请求 AOT 编译,否则 Clojure 会即时编译代码。如果 uberjar AOT 编译 is 通过 {:uberjar {:aot :all}}
配置文件在 project.clj 文件中请求(您可以通过将 uberjar 配置文件更改为空配置文件来做一个小实验 {:uberjar {}}
,那么 lein uberjar && java -jar target/uberjar/feedme-0.1.0-SNAPSHOT-standalone.jar
将导致完全相同的错误)。
您可以运行 lein with-profile uberjar jar
来编译您的代码。但是如果你 运行 java -jar target/uberjar+uberjar/feedme-0.1.0-SNAPSHOT.jar
你会得到另一个错误:java.lang.NoClassDefFoundError: clojure/lang/IFn
。正如 noisesmith 所指出的,lein jar
没有打包任何依赖项,包括 Clojure 本身。因此,您必须在 class 路径中显式指定 Clojure:java -cp "$HOME/.m2/repository/org/clojure/clojure/1.8.0/clojure-1.8.0.jar:target/uberjar+uberjar/feedme-0.1.0-SNAPSHOT.jar" feedme.core
。这将打印 Hello, World! (假设您的本地 Maven 存储库中有 Clojure 1.8,您可能需要先获取它或更改 path/version)。
无需编译,您可以 运行 使用 lein jar
生成的 jar:java -cp "$HOME/.m2/repository/org/clojure/clojure/1.8.0/clojure-1.8.0.jar:target/feedme-0.1.0-SNAPSHOT.jar" clojure.main --main feedme.core
(同样,您的 Clojure jar 的 path/version 可以不同)。