如何在Java中读取MANIFEST.MF版本信息用于“关于”窗口展示
原因排查
首先确认以下几个常见触发点:
- 运行环境不是直接执行目标jar:如果在IDE中直接运行类、或者测试类路径下存在同名Main类,此时加载的Main类不是来自你打包好的jar,JVM不会关联到你配置好的MANIFEST.MF,自然读不到版本属性。
- MANIFEST.MF格式不符合规范:属性名
Implementation-Version和冒号之间不能存在空格,冒号和版本值之间必须保留1个半角空格,文件末尾必须保留至少1个空行,任意格式错误都会导致JVM跳过该属性的解析。 - 同包名冲突:如果类路径下存在多个jar包包含和Main类同包名的类,JVM会取第一个加载的jar包的MANIFEST.MF属性,如果该jar没有配置对应属性就会返回null。
- 可执行fat jar类加载机制限制:如果是SpringBoot等框架打的嵌套fat jar,应用类默认由框架自定义的类加载器加载,
getPackage()方法不会读取jar根目录的MANIFEST.MF属性。
通用解决方案
直接主动读取类路径下的MANIFEST.MF文件匹配目标属性,兼容性最强,代码示例如下:
import java.io.IOException; import java.io.InputStream; import java.net.URL; import java.util.Enumeration; import java.util.jar.Attributes; import java.util.jar.Manifest; public class AppVersionFetcher { // 替换为你自己在MANIFEST.MF中配置的Implementation-Title值 private static final String APP_TITLE = "My Application"; public static String getVersion() { String defaultVersion = "1.0.0"; try { Enumeration<URL> manifestResources = Thread.currentThread() .getContextClassLoader() .getResources("META-INF/MANIFEST.MF"); while (manifestResources.hasMoreElements()) { URL resourceUrl = manifestResources.nextElement(); try (InputStream inputStream = resourceUrl.openStream()) { Manifest manifest = new Manifest(inputStream); Attributes mainAttrs = manifest.getMainAttributes(); String title = mainAttrs.getValue("Implementation-Title"); if (APP_TITLE.equals(title)) { return mainAttrs.getValue("Implementation-Version"); } } } } catch (IOException ignored) { // 读取异常时返回兜底版本 } return defaultVersion; } }
打包配置核验(以Maven为例)
确保你的打包插件已正确生成MANIFEST.MF属性,maven-jar-plugin配置参考:
<plugin> <groupId>org.apache.maven.plugins</groupId> <artifactId>maven-jar-plugin</artifactId> <version>3.3.0</version> <configuration> <archive> <manifestEntries> <Implementation-Title>My Application</Implementation-Title> <Implementation-Version>${project.version}</Implementation-Version> </manifestEntries> </archive> </configuration> </plugin>
内容的提问来源于stack exchange,提问作者lmattcris
相关产品推荐
相关产品推荐

