概述
在这篇简短的文章中,我们将探讨如何程序化地创建jar文件。在编写软件时,最终需要将其部署到生产环境。有时,使用类路径包含单独的文件是可以接受的。通常,处理单个文件会更方便。对于Java而言,标准的做法是使用JAR、WAR或EAR文件。
基本过程包括编写manifest文件,打开jar,添加内容,最后关闭jar。
2. jar文件的结构
jar文件是ZIP文件格式的扩展,其中包含一个manifest文件。manifest文件是专为JAR文件设计的特殊文件,可能包含各种设置,如主类、可选数据(如作者、版本等)以及代码签名信息。
我们可以使用zip兼容的工具,如WinRAR,查看和提取部分或全部存档。我们还可以包含一个名为jars或libs的子目录,用于存放依赖的jar文件。由于jar是zip文件的扩展,我们可以包含任何文件或目录。
3. 创建JarTool类
为了简化创建jar文件的过程,我们可以创建一个单独的、简单的Java对象(POJO)类,封装我们的操作,例如在manifest文件中放置条目,创建jar文件,添加文件或目录。
我们还可以创建方法来从jar中删除项,甚至向现有jar中追加条目,尽管这些操作需要完全读取并重写jar。
3.1. jar的manifest
要创建jar文件,首先必须开始manifest:
public class JarTool {
private Manifest manifest = new Manifest();
public void startManifest() {
manifest.getMainAttributes().put(Attributes.Name.MANIFEST_VERSION, "1.0");
}
}
如果要使jar可执行,必须设置主类:
public void setMainClass(String mainFQCN) {
if (mainFQCN != null && !mainFQCN.equals("")) {
manifest.getMainAttributes().put(Attributes.Name.MAIN_CLASS, mainFQCN);
}
}
如果要指定其他属性,可以将它们添加到manifest中,例如:
addToManifest("Can-Redefine-Classes", "true");
以下是相应的方法:
public void addToManifest(String key, String value) {
manifest.getMainAttributes().put(new Attributes.Name(key), value);
}
3.2. 打开jar进行写入
完成manifest后,现在可以将条目写入jar文件。为此,首先需要打开jar:
public JarOutputStream openJar(String jarFile) throws IOException {
return new JarOutputStream(new FileOutputStream(jarFile), manifest);
}
3.3. 将文件添加到jar中
在将文件添加到jar中时,Java使用Solaris风格的文件名,使用斜杠作为分隔符(/)。注意,我们可以添加任何类型的任何文件,包括其他jar文件或空目录,这对于包含依赖项非常有用。
此外,因为jar文件是一种classpath形式,我们需要指定希望在jar内部使用的绝对路径的一部分。对于我们的情况,项目类路径的根路径将是我们的目的。
理解这一点后,现在我们可以用以下方法完成JarTool
类:
public void addFile(JarOutputStream target, String rootPath, String source)
throws FileNotFoundException, IOException {
String remaining = "";
if (rootPath.endsWith(File.separator)) {
remaining = source.substring(rootPath.length());
} else {
remaining = source.substring(rootPath.length() + 1);
}
String name = remaining.replace("\\","/");
JarEntry entry = new JarEntry(name);
entry.setTime(new File(source).lastModified());
target.putNextEntry(entry);
BufferedInputStream in = new BufferedInputStream(new FileInputStream(source));
byte[] buffer = new byte[1024];
while (true) {
int count = in.read(buffer);
if (count == -1) {
break;
}
target.write(buffer, 0, count);
}
target.closeEntry();
in.close();
}
4. 工作示例
为了演示可执行jar的最小要求,我们将编写一个应用程序类,并看看它是如何工作的:
public class Driver {
public static void main(String[] args) throws IOException {
JarTool tool = new JarTool();
tool.startManifest();
tool.addToManifest("Main-Class", "com.baeldung.createjar.HelloWorld");
JarOutputStream target = tool.openJar("HelloWorld.jar");
tool.addFile(target, System.getProperty("user.dir") + "\\src\\main\\java",
System.getProperty("user.dir") + "\\src\\main\\java\\com\\baeldung\\createjar\\HelloWorld.class");
target.close();
}
}
HelloWorld类是一个非常简单的类,只包含一个打印文本的main()
方法:
public class HelloWorld {
public static void main(String[] args) {
System.out.println("Hello World!");
}
}
为了验证它工作,我们有这个例子:
$ javac -cp src/main/java src/main/java/com/baeldung/createjar/HelloWorld.java
$ javac -cp src/main/java src/main/java/com/baeldung/createjar/JarTool.java
$ javac -cp src/main/java src/main/java/com/baeldung/createjar/Driver.java
$ java -cp src/main/java com/baeldung/createjar/Driver
$ java -jar HelloWorld.jar
Hello World!
在这里,我们编译了每个类,然后执行Driver
类,这将创建HelloWorld
jar。最后,我们执行jar,结果输出“Hello World”消息。
上述命令应在项目位置下执行。
5. 总结
在本教程中,我们了解了如何程序化地创建jar文件,添加内容,并最终执行它。
当然,代码可以在GitHub上找到。