[英]How do I read the manifest file for a webapp running in apache tomcat?
我有一个包含清单文件的 webapp,我在 ant 构建任务期间编写了我的应用程序的当前版本。 清单文件已正确创建,但是当我尝试在运行时读取它时,我得到了一些奇怪的副作用。 我在清单中读取的代码是这样的:
InputStream manifestStream = Thread.currentThread()
.getContextClassLoader()
.getResourceAsStream("META-INFFFF/MANIFEST.MF");
try {
Manifest manifest = new Manifest(manifestStream);
Attributes attributes = manifest.getMainAttributes();
String impVersion = attributes.getValue("Implementation-Version");
mVersionString = impVersion;
}
catch(IOException ex) {
logger.warn("Error while reading version: " + ex.getMessage());
}
当我将 eclipse 附加到 tomcat 时,我看到上面的代码有效,但它似乎得到了一个与我预期不同的清单文件,我可以看出这是因为 Z63B07E828BF016E976FF95D6EE07A10Z 版本和构建时间戳都不同。 然后,我把“META-INFFFF”放在那里,上面的代码仍然有效,这意味着我正在阅读其他一些清单。 不是我的。 我也试过
this.getClass().getClassLoader().getResourceAsStream(...)
但结果是一样的。 从在 tomcat 中运行的 web 应用程序内部读取清单文件的正确方法是什么?
编辑:感谢到目前为止的建议。 另外,我应该注意我正在独立运行 tomcat; 我从命令行启动它,然后附加到 Eclipse 调试器中正在运行的实例。 这不应该有所作为,不是吗?
也许您的副作用来自几乎所有 jars 都包含 MANIFEST.MF 而您没有得到正确的事实。 要从 webapp 中读取 MANIFEST.MF,我会说:
ServletContext application = getServletConfig().getServletContext();
InputStream inputStream = application.getResourceAsStream("/META-INF/MANIFEST.MF");
Manifest manifest = new Manifest(inputStream);
Please note that running Tomcat from Eclipse is not the same as running Tomcat alone as Eclipse plays with the classloader.
有点晚了,但这对我有用(Glassfish中的网络应用程序)
Properties prop = new Properties();
prop.load(getServletContext().getResourceAsStream("/META-INF/MANIFEST.MF"));
System.out.println("All attributes:" + prop.stringPropertyNames());
System.out.println(prop.getProperty("{whatever attribute you want}"));
尝试使用jcabi-manifests ,它会为您完成所有这些加载工作。 例如:
String version = Manifests.read("My-Version");
从可用的MANIFEST.MF
文件之一加载My-Version
属性。
重要的是要提到(更多细节在这里)在大多数 web 容器当前线程 class 加载器与 servlet 上下文 class 加载器不同。 这就是为什么您应该在运行时将您的 servlet 上下文 append 到寄存器中的原因(更多信息):
Manifests.append(servletContext);
另外,请查看:http://www.yegor256.com/2014/07/03/how-to-read-manifest-mf.html
正确的清单存在于服务器的应用程序根目录中。 找出应用程序根,例如找出 class 的类路径:
String rootPath = getClass().getProtectionDomain().getCodeSource().getLocation().getPath()
然后将上面的路径替换为已建立的路径: Glassfish 示例:
/applications/<webProject>/META-INF/MANIFEST.MF
它对我有用。
class 加载程序的默认工作方式是在尝试查找自己的资源之前先推迟到父级。 因此,如果父 class 加载程序有任何可用的清单,这就是您将得到的。 事实上,应用服务器不一定会这样做,以允许应用程序覆盖库的版本。 此外,class 加载程序可以具有多个 jars 并因此具有多个清单。
它可能能够获得您唯一命名的资源之一的资源 URL。 打开一个连接。 投射到JarURLConnection
。 获取JarFile
。 从中加载清单。 这可能行不通,特别是如果 Tomcat 引发战争。
[更新] 当然,war 文件本身不在类路径中。 类路径将包含类似 WEB-INF/lib/( .jar| .zip) 和 WEB-INF/classes/ 的内容。 从ServletContext
获取资源应该可以工作。
最佳解决方案:做一些不同的事情。 :)
不知道阅读它的“官方”方式,但如果 MANIFEST.MF 无法正确加载为资源,那么尝试从某些 web 路径上的“ServletContext.getRealPath()”获取其路径怎么样在您的应用程序中定义?
在构建期间由 ant 将应用程序版本也写入其他地方(WEB-INF/类中的属性文件)是我想到的另一个解决方案。
这就是我将各种版本打印到日志文件的方法。 我已经对扩展路径进行了硬编码,但应用程序可能会使用servletContext.getRealPath("/")
来读取 webapp 文件夹的完整路径。 可以打印刚刚给定的库或 lib 文件夹中的所有内容。
// print library versions (jersey-common.jar, jackson-core-2.6.1.jar)
try {
List<String> jars = Arrays.asList( "jersey-common", "jackson-core", "openjpa", "mylib" );
StringBuilder verbuf = new StringBuilder();
for(File file : new File("/opt/tomcat/webapps/myapp/WEB-INF/lib/").listFiles() ) {
String name = file.getName();
if (file.isDirectory() || !file.isFile() || !name.endsWith(".jar") ) continue;
name = name.substring(0, name.length()-4);
boolean found = jars.contains(name);
if (!found) {
int idx = name.lastIndexOf('-');
if (idx>0)
found = jars.contains( name.substring(0, idx) );
}
if (!found) continue;
JarFile jarFile = new JarFile(file, false);
try {
String ver;
Manifest mf = jarFile.getManifest();
if (mf!=null) {
ver = mf.getMainAttributes().getValue("Bundle-Version");
if (ver==null || ver.isEmpty())
ver = mf.getMainAttributes().getValue("Implementation-Version");
} else ver=null;
if (verbuf.length()>0) verbuf.append(", ");
verbuf.append(name + "=" + (ver!=null?ver:"") );
} finally {
jarFile.close();
}
}
System.out.println( verbuf.toString() );
} catch(Exception ex) {
ex.printStackTrace();
}
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.