jar的作用
- jar(Java Archive)能够将多个源码、资源等文件打包到一个归档文件中。
- jar是jdk自带的打包工具,它是通过zip格式进行打包的,它也可以用来进行日常的压缩、解压。
jar的使用示例
- jar命令打包会默认在压缩包中添加清单(Manifest)文件,如果不想添加默认的manifest文件,可手动指定-M选项:
jar cvf HelloWorld.jar HelloWorld.class // 将class文件压缩成jar包
jar tf HelloWorld.jar // jar包包含文件列表
META-INF/
META-INF/MANIFEST.MF
HelloWorld.class
- jar xf HelloWorld.jar META-INF/MANIFEST.MF // 解压出manifest文件
- jar cvfm HelloWorld.jar MY_MANIFEST.MF HelloWorld.class // 使用自己定义的清单文件
- jar uf HelloWorld.jar HelloWorld.txt // 向压缩包中添加文件
Manifest文件的作用
- 上面提到在使用jar压缩文件中会默认添加 Manifest清单文件,那么这个文件是用来干啥的呢? 有何作用? 查看manifest文件的内容可以知道它记录着jar包的版本信息、创建时间,如果指定jar包的入口程序,-e选项,清单文件中就会多一行Main-Class: HelloWorld, 也可以不使用-e选项,直接创建自己的清单文件,写入Main-Class: 启动类,然后适用-m选项,使用自己的清单文件。
- 在运行java命令的时候, 如果指定了-jar选项,那么环境变量ClASSPATH和在命令行中指定的所有类路径都会被jvm所忽略,如果jar包的class需要依赖其他的jar包,解决方案有两个,方案1:不带-jar选项, 使用java -cp 把该jar和所依赖的jar所在路径都作为classpath,后面带全限定名的启动类。方案2:使用-jar选项, java -jar hello.jar,但需要修改manifest文件中的内容,添加Class-Path来指定运行需要的其他jar,多个jar之间用空格隔开,如下所示:
Manifest-Version: 1.0
Main-Class: com.ibm.portalnews.entrance.Main
Class-Path: lib\commons-collections-3.2.jar lib\commons-configuration-1.5.jar lib\commons-lang-2.3.jar lib\commons-logging.jar lib\dom4j-1.6.1.jar lib\jaxen-1.1-beta-7.jar lib\jdom.jar lib\log4j-1.2.14.jar
Manifest-Version表示版本号, Main-Class 是jar文件的主类,程序的入口,Class-Path 指定需要的jar的路径,多个jar必须要在一行上,以空格隔开,注意:对于文件路径,windows下使用\来分割,linux下用/分割。 在清单文件中, 所有选项的冒号后面必须加个空格,最后一行必须是一个回车换行符。
jar cvfM AppServer.jar META-INF/MANIFEST.MF AppServer.class
jar uf AppServer.jar AppServer$1.class // \ 用于mac上转义
java -jar AppServer.jar server1 // 直接执行jar, server1 是参数
unzip AppServer.jar -d mytest // unzip 解压
是否可以将jar包A引用的其他jar包一同打包到A里面? 这样的话就很方便统一管理了,遗憾的是这样是不行的,java 类加载器是无法加载jar包内包含的其他jar包的class,这里可以使用-0 选项,它表示只打包不压缩, jar -cvf0m , 这样打的包不会压缩,classloader就可以加载其他jar中包含的class文件了。(貌似maven shade-plugin就是这么做的??)
jar cvf0M smconfweb.jar META-INF/MANIFEST.MF *
MANIFEST 作用
从 MANIFEST 文件中提供的信息大概可以了解到其基本作用
- JAR 包基本信息描述
- Main-Class 指定程序的入口,这样可以直接用java -jar xxx.jar来运行程序
- Class-Path 指定jar包的依赖关系,class loader会依据这个路径来搜索class
Jar 文件和 Manifest 在 java 中的定义
下面为 JarFile 的定义,从代码就可以看出,前面我们所介绍的 Jar 是以 ZIP 格式构建一种归档文件,因为它是 ZipFile 的子类。
public class JarFile extends ZipFile {
private SoftReference<Manifest> manRef;
private JarEntry manEntry;
private JarVerifier jv;
private boolean jvInitialized;
private boolean verify;
//指示是否存在Class-Path属性(仅当hasCheckedSpecialAttributes为true时才有效)
private boolean hasClassPathAttribute;
// 如果清单检查特殊属性,则为 true
private volatile boolean hasCheckedSpecialAttributes;
// 在SharedSecrets中设置JavaUtilJarAccess
static {
SharedSecrets.setJavaUtilJarAccess(new JavaUtilJarAccessImpl());
}
/**
* The JAR manifest file name.(JAR清单文件名)
*/
public static final String MANIFEST_NAME = "META-INF/MANIFEST.MF";
// 省略其他
}
下面是 Manifest 类的定义,用来描述 JAR 的 清单文件。从其属性中也很好的观察到,其存储的就是 K-V 键值对数据
public class Manifest implements Cloneable {
// manifest main attributes
private Attributes attr = new Attributes();
// manifest entries
private Map<String, Attributes> entries = new HashMap<>();
// 省略其他
}