JRE 不使用可运行 jar 的清单文件指定的类路径
JRE not using classpath specified by manifest file of runnable jar
首先post,很抱歉我的格式不好。我有一个在 eclipse 中开发的 java 程序。我将程序导出为 jar (myJar.jar),然后我将程序依赖的所有外部 jar 放入位于同一位置的名为 lib 的文件夹中作为 myJar.jar。为了设置我的class路径,我有一个具有以下格式的清单文件:
Main-Class: exe.myMain
Class-Path: lib/jar_1.jar lib/jar_2.jar ... lib/jar_n.jar
Manifest-Version: 1.0
但是,当我尝试使用 "java -jar myJar.jar" 运行 程序时,lib 中的 classes 不是正在加载(我收到 ClassNotFoundException)。我在我的程序中使用了以下代码来打印 classpath:
ClassLoader cl = ClassLoader.getSystemClassLoader();
URL[] urls = ((URLClassLoader)cl).getURLs();
for(URL url:urls){
System.out.println(url.getFile());
}
当我 运行 这段代码时 class 路径只是 "myJar.jar"。
我有两个问题:
1.) 上面的代码实际上是在 运行 时为我提供了 JRE 的 class 路径,还是只是向我提供了主 class 的地址?
2.) 鉴于上述代码确实在 运行 时为我提供了 JRE 的 class 路径,我做错了什么吗?
请随时索取更多信息,我会很乐意提供您所需要的。
您的 manifest
文件似乎有误。你有 Main-Class: exe.myMain
=> java 但有 exe 类型?推荐给你的是你应该使用 eclipse 来导出你的 jar 文件,它会自动为你创建所有的东西,你不必手动创建清单文件,所以你可能会犯错误。详见如下:
我已经通过使用 eclipse 创建了一个 java 项目进行了测试 => 使用 eclipse 的导出功能导出可运行的 JAR => 使用第三个选项(将所需的库复制到子文件夹中...) .导出后,我得到了名称为 myJarName.jar
的 jar 和名称为 myJarName_lib
的文件夹。使用 7zip
程序打开 jar => 在 META-INF
=> 打开 MANIFEST.MF
=> 下面是它的结构:
Manifest-Version: 1.0
Class-Path: . myJarName_lib/gson-2.8.0.jar myJarName_lib/jsoup-1.8.3.jar myJarName_lib/commons-cli-1.2.jar myJarName_lib/jackson-core-2.8.8.jar
Main-Class: upwork.Main
你所做的听起来是正确的。
出于某种原因,清单中的 Class-Path
条目在检查类路径时没有显示(例如 here and here;这些示例使用 属性 "java.class.path"
但我的测试表明 ClassLoader.getURLs()
表现相同)。不过,它仍应搜索 类。我不知道如何从清单中获取包含 Class-Path
条目的真实类路径。
我要检查的第一件事是 myJar.jar
中的文件 META-INF/MANIFEST.MF
是否与您创建的清单匹配。您可以通过将 myJar.jar
重命名为具有 .zip
文件扩展名来打开它。
我试图重现你的问题,但 lib/jar_1.jar
中的 类 是为我加载的,所以如果 META-INF/MANIFEST.MF
是正确的,我将详细描述我所做的,以便你可以发现我们所做的不同。
编辑:
以下是我使用的步骤:
创建一个名为 "experiment" 的新目录。下面的步骤都在该目录下完成。
创建名为 "jar_1"、"lib" 和 "exe"
的新目录
在目录 "jar_1" 中创建名为 "ClassInJar1.java" 的文件,内容如下:
package jar_1;
public class ClassInJar1 {
public static void method() {
System.out.println("Hello from ClassInJar1");
}
}
运行 javac jar_1/ClassInJar1.java
运行 jar cf lib/jar_1.jar jar_1/ClassInJar1.class
在目录 "exe" 中创建一个名为 "myMain.java" 的文件,内容如下:
package exe;
import java.net.*;
import jar_1.ClassInJar1;
public class myMain {
public static void main(String[] args) {
ClassLoader cl = ClassLoader.getSystemClassLoader();
URL[] urls = ((URLClassLoader) cl).getURLs();
for (URL url : urls) {
System.out.println(url.getFile());
}
ClassInJar1.method();
}
}
运行 javac exe/myMain.java
在 "experiment" 目录中创建一个名为 "manifest" 的文件,内容如下:
Main-Class: exe.myMain
Class-Path: lib/jar_1.jar lib/jar_2.jar
Manifest-Version: 1.0
运行 jar cfm myJar.jar manifest exe/myMain.class
运行 java -jar myJar.jar
输出:
/.../experiment/myJar.jar
Hello from ClassInJar1
首先post,很抱歉我的格式不好。我有一个在 eclipse 中开发的 java 程序。我将程序导出为 jar (myJar.jar),然后我将程序依赖的所有外部 jar 放入位于同一位置的名为 lib 的文件夹中作为 myJar.jar。为了设置我的class路径,我有一个具有以下格式的清单文件:
Main-Class: exe.myMain
Class-Path: lib/jar_1.jar lib/jar_2.jar ... lib/jar_n.jar
Manifest-Version: 1.0
但是,当我尝试使用 "java -jar myJar.jar" 运行 程序时,lib 中的 classes 不是正在加载(我收到 ClassNotFoundException)。我在我的程序中使用了以下代码来打印 classpath:
ClassLoader cl = ClassLoader.getSystemClassLoader();
URL[] urls = ((URLClassLoader)cl).getURLs();
for(URL url:urls){
System.out.println(url.getFile());
}
当我 运行 这段代码时 class 路径只是 "myJar.jar"。
我有两个问题:
1.) 上面的代码实际上是在 运行 时为我提供了 JRE 的 class 路径,还是只是向我提供了主 class 的地址?
2.) 鉴于上述代码确实在 运行 时为我提供了 JRE 的 class 路径,我做错了什么吗?
请随时索取更多信息,我会很乐意提供您所需要的。
您的 manifest
文件似乎有误。你有 Main-Class: exe.myMain
=> java 但有 exe 类型?推荐给你的是你应该使用 eclipse 来导出你的 jar 文件,它会自动为你创建所有的东西,你不必手动创建清单文件,所以你可能会犯错误。详见如下:
我已经通过使用 eclipse 创建了一个 java 项目进行了测试 => 使用 eclipse 的导出功能导出可运行的 JAR => 使用第三个选项(将所需的库复制到子文件夹中...) .导出后,我得到了名称为 myJarName.jar
的 jar 和名称为 myJarName_lib
的文件夹。使用 7zip
程序打开 jar => 在 META-INF
=> 打开 MANIFEST.MF
=> 下面是它的结构:
Manifest-Version: 1.0
Class-Path: . myJarName_lib/gson-2.8.0.jar myJarName_lib/jsoup-1.8.3.jar myJarName_lib/commons-cli-1.2.jar myJarName_lib/jackson-core-2.8.8.jar
Main-Class: upwork.Main
你所做的听起来是正确的。
出于某种原因,清单中的 Class-Path
条目在检查类路径时没有显示(例如 here and here;这些示例使用 属性 "java.class.path"
但我的测试表明 ClassLoader.getURLs()
表现相同)。不过,它仍应搜索 类。我不知道如何从清单中获取包含 Class-Path
条目的真实类路径。
我要检查的第一件事是 myJar.jar
中的文件 META-INF/MANIFEST.MF
是否与您创建的清单匹配。您可以通过将 myJar.jar
重命名为具有 .zip
文件扩展名来打开它。
我试图重现你的问题,但 lib/jar_1.jar
中的 类 是为我加载的,所以如果 META-INF/MANIFEST.MF
是正确的,我将详细描述我所做的,以便你可以发现我们所做的不同。
编辑:
以下是我使用的步骤:
创建一个名为 "experiment" 的新目录。下面的步骤都在该目录下完成。
创建名为 "jar_1"、"lib" 和 "exe"
的新目录
在目录 "jar_1" 中创建名为 "ClassInJar1.java" 的文件,内容如下:
package jar_1; public class ClassInJar1 { public static void method() { System.out.println("Hello from ClassInJar1"); } }
运行
javac jar_1/ClassInJar1.java
运行
jar cf lib/jar_1.jar jar_1/ClassInJar1.class
在目录 "exe" 中创建一个名为 "myMain.java" 的文件,内容如下:
package exe; import java.net.*; import jar_1.ClassInJar1; public class myMain { public static void main(String[] args) { ClassLoader cl = ClassLoader.getSystemClassLoader(); URL[] urls = ((URLClassLoader) cl).getURLs(); for (URL url : urls) { System.out.println(url.getFile()); } ClassInJar1.method(); } }
运行
javac exe/myMain.java
在 "experiment" 目录中创建一个名为 "manifest" 的文件,内容如下:
Main-Class: exe.myMain
Class-Path: lib/jar_1.jar lib/jar_2.jar
Manifest-Version: 1.0
运行
jar cfm myJar.jar manifest exe/myMain.class
运行
java -jar myJar.jar
输出:
/.../experiment/myJar.jar
Hello from ClassInJar1