jar包本质上就是一个zip包,可以只用流行的压缩软件进行解压。
jar包的版本被定义在解压后的META-INF\MANIFEST.MF文件中,示例是tomcat8.0.45中catalina.jar包里的MANIFEST.MF文件中的内容:
Manifest-Version: 1.0
Ant-Version: Apache Ant 1.9.7
Created-By: 1.7.0_80-b15 (Oracle Corporation)
Specification-Title: Apache Tomcat
Specification-Version: 8.0
Specification-Vendor: Apache Software Foundation
Implementation-Title: Apache Tomcat
Implementation-Version: 8.0.45
Implementation-Vendor: Apache Software Foundation
X-Compile-Source-JDK: 1.7
X-Compile-Target-JDK: 1.7
在MANIFEST.MF文件中,常见的与版本相关的属性包括Implementation-Version、Specification-Version和Bundle-Version,它们分别表示不同的版本号含义。
1.Implementation-Version:表示当前JAR文件或模块的实现版本号,即程序代码的版本号。如果你的应用程序或库是基于某个框架或API开发的,那么这个版本号通常是由框架或API提供的,用来标识程序代码的版本信息。例如,Spring Framework的JAR文件中的Implementation-Version属性指定了Spring版本号。
2.Specification-Version:表示当前JAR文件或模块实现的规范版本号,即程序代码所遵循的规范的版本号。通常情况下,这个版本号由规范或API的发布者指定,用来标识该规范或API的版本信息。例如,Java SE API的JAR文件中的Specification-Version属性指定了Java SE版本号。
3.Bundle-Version:表示OSGi bundle的版本号,即用于在OSGi容器中进行模块化开发和部署的标准化方式。OSGi是一种面向Java的动态模块化系统,可以将应用程序拆分成多个独立的模块(即bundle),每个bundle可以依赖于其他bundle,并在运行时动态加载和卸载。在OSGi中,每个bundle都必须包含一个MANIFEST.MF文件,其中Bundle-Version属性指定了该bundle的版本号。
需要注意的是,Implementation-Version、Specification-Version和Bundle-Version的格式都是类似的,通常采用“主版本号.次版本号.修订版本号”的形式。例如,1.0.0表示主版本号为1、次版本号为0、修订版本号为0的版本。
在使用JAR文件或模块时,可以通过读取MANIFEST.MF文件中的版本号属性来判断程序代码或规范的版本信息,以确保所使用的版本与预期的版本一致。
如果需要批量获取某个目录下所有jar包的版本,可以参考以下python脚本:
from zipfile import ZipFile
import os
import sys
def showjarversion(start):
jar_list = []
#遍历目录
for relpath, dirs, files in os.walk(start):
for name in files:
#判断,如果是jar文件,把文件路径添加到需要检查的路径列表中。
if name.endswith('.jar'):
full_path = os.path.join(start, relpath, name)
jar_list.append(os.path.normpath(os.path.abspath(full_path)))
for file in jar_list:
with ZipFile(file) as myzip:
try:
myfile = myzip.open('META-INF/MANIFEST.MF')
#部分jar包打包不规范,没有“META-INF/MANIFEST.MF”,需要进行错误处理。
except KeyError:
print(file + '中没有“META-INF/MANIFEST.MF”文件,无法检查版本!')
continue
else:
#将MANIFEST.MF导入字典myfile_dict,方便后面查询。
myfile_str = myfile.read().decode("utf-8")
myfile_lines = myfile_str.split("\n")
myfile_dict = {}
for line in myfile_lines:
if ":" in line:
key, value = line.split(":", 1)
myfile_dict[key.strip()] = value.strip()
#取得jar包版本。
#优先获取Implementation-Version(实现版本)
#如没有则获取Specification-Version(规范版本)
#如都没有则获取Bundle-Version(包版本)。
#如果都没有则报告无法获取版本。
try:
version = myfile_dict['Implementation-Version']
print(file + ' 实现版本:' + version)
except KeyError:
try:
version = myfile_dict['Specification-Version']
print(file + ' 规范版本:' + version)
except KeyError:
try:
version = myfile_dict['Bundle-Version']
print(file + ' Bundle版本:' + version)
except KeyError:
print(file + 'MANIFEST.MF中无版本信息!')
if __name__ == '__main__':
showjarversion(sys.argv[1])