我正在尝试从我的Spring Boot Web应用程序(包含在jar文件中)中读取我的META-INF / MANIFEST.MF文件。
我正在尝试以下代码:
InputStream is = getClass().getResourceAsStream("/META-INF/MANIFEST.MF");
Properties prop = new Properties();
prop.load( is );
但显然Spring Boot中有一些东西加载了一个不同的manifest.mf(而不是我自己位于META-INF文件夹中)。
有谁知道如何在Spring Boot应用程序中阅读我的清单应用程序?
更新:经过一番研究后,我注意到使用通常的方式读取manifest.mf文件,在Spring Boot应用程序中,这是正在访问的Jar
org.springframework.boot.loader.jar.JarFile
答案 0 :(得分:17)
我使用java.lang.Package从清单中读取spring boot中的Implementation-Version
属性。
String version = Application.class.getPackage().getImplementationVersion();
应在Implementation-Version
build.gradle
属性
jar {
baseName = "my-app"
version = "0.0.1"
manifest {
attributes("Implementation-Version": version)
}
}
答案 1 :(得分:4)
几乎所有jar文件都附带一个清单文件,因此您的代码将返回 第一个文件,它可以在类路径中找到 。
为什么你还想要清单呢?它是Java使用的文件。将您需要的任何自定义值放在其他位置,例如.properties
文件旁边的.class
文件。
更新2
如下面的评论所述,问题中的不是,真正的目标是清单中的版本信息。 Java已经使用java.lang.Package
类提供了该信息。
不要尝试自己阅读清单,即使你能找到它。
更新1
请注意,清单文件不是 Properties
文件。它的结构要复杂得多。
Manifest-Version: 1.0
Created-By: 1.7.0 (Sun Microsystems Inc.)
Name: common/class1.class
SHA-256-Digest: (base64 representation of SHA-256 digest)
Name: common/class2.class
SHA1-Digest: (base64 representation of SHA1 digest)
SHA-256-Digest: (base64 representation of SHA-256 digest)
如您所见,Name
和SHA-256-Digest
不止一次出现。 Properties
类无法处理,因为它只是一个Map
,并且键必须是唯一的。
答案 2 :(得分:4)
这很简单,只需添加此
即可 InputStream is = this.getClass().getClassLoader().getResourceAsStream("META-INF/MANIFEST.MF");
Properties prop = new Properties();
try {
prop.load( is );
} catch (IOException ex) {
Logger.getLogger(IndexController.class.getName()).log(Level.SEVERE, null, ex);
}
为我工作。
注意:
getClass()。getClassLoader()很重要
和
" META-INF / MANIFEST.MF"不是" /META-INF/MANIFEST.MF"
由于 亚历山大
答案 3 :(得分:2)
在测试和搜索Spring文档后,我找到了一种读取清单文件的方法。
首先,Spring Boot实现了自己的ClassLoader,它改变了资源的加载方式。当您调用getResource()
时,Spring Boot将加载与类路径中可用的所有JAR列表中的给定资源名称匹配的第一个资源,并且您的应用程序jar不是第一选择。
因此,当发出如下命令时:
getClassLoader().getResourceAsStream("/META-INF/MANIFEST.MF");
返回在类路径的任何Jar中找到的第一个MANIFEST.MF文件。就我而言,它来自JDK jar库。
<强> SOLUTION:强>
我设法得到包含资源“/META-INF/MANIFEST.MF”的应用程序加载的所有Jars的列表,并检查资源是否来自我的应用程序jar。如果是这样,请阅读其MANIFEST.MF文件并返回应用程序,如下所示:
private Manifest getManifest() {
// get the full name of the application manifest file
String appManifestFileName = this.getClass().getProtectionDomain().getCodeSource().getLocation().toString() + JarFile.MANIFEST_NAME;
Enumeration resEnum;
try {
// get a list of all manifest files found in the jars loaded by the app
resEnum = Thread.currentThread().getContextClassLoader().getResources(JarFile.MANIFEST_NAME);
while (resEnum.hasMoreElements()) {
try {
URL url = (URL)resEnum.nextElement();
// is the app manifest file?
if (url.toString().equals(appManifestFileName)) {
// open the manifest
InputStream is = url.openStream();
if (is != null) {
// read the manifest and return it to the application
Manifest manifest = new Manifest(is);
return manifest;
}
}
}
catch (Exception e) {
// Silently ignore wrong manifests on classpath?
}
}
} catch (IOException e1) {
// Silently ignore wrong manifests on classpath?
}
return null;
}
此方法将从Manifest对象内的manifest.mf文件返回所有数据。
借用了部分解决方案答案 4 :(得分:2)
我利用Spring的资源解析方法:
@Service
public class ManifestService {
protected String ciBuild;
public String getCiBuild() { return ciBuild; }
@Value("${manifest.basename:/META-INF/MANIFEST.MF}")
protected void setManifestBasename(Resource resource) {
if (!resource.exists()) return;
try (final InputStream stream = resource.getInputStream()) {
final Manifest manifest = new Manifest(stream);
ciBuild = manifest.getMainAttributes().getValue("CI-Build");
}
catch (IOException e) {
throw new RuntimeException(e);
}
}
}
这里我们得到CI-Build
,您可以轻松扩展示例以加载其他属性。
答案 5 :(得分:1)
public Properties readManifest() throws IOException {
Object inputStream = this.getClass().getProtectionDomain().getCodeSource().getLocation().getContent();
JarInputStream jarInputStream = new JarInputStream((InputStream) inputStream);
Manifest manifest = jarInputStream.getManifest();
Attributes attributes = manifest.getMainAttributes();
Properties properties = new Properties();
properties.putAll(attributes);
return properties;
}
答案 6 :(得分:0)
try {
final JarFile jarFile = (JarFile) this.getClass().getProtectionDomain().getCodeSource().getLocation().getContent();
final Manifest manifest = jarFile.getManifest();
final Map<Object, Object> manifestProps = manifest.getMainAttributes().entrySet().stream()
.collect(Collectors.toMap(entry -> entry.getKey(), entry -> entry.getValue()));
...
} catch (final IOException e) {
LOG.error("Unable to read MANIFEST.MF", e);
...
}
仅当您通过java -jar
命令启动应用时,此功能才有效,如果创建集成测试,则无效。