47

I have a webapp which contains a manifest file, in which I write the current version of my application during an ant build task. The manifest file is created correctly, but when I try to read it in during runtime, I get some strange side-effects. My code for reading in the manifest is something like this:

    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());
    }

When I attach eclipse to tomcat, I see that the above code works, but it seems to get a different manifest file than the one I expected, which I can tell because the ant version and build timestamp are both different. Then, I put "META-INFFFF" in there, and the above code still works! This means that I'm reading some other manifest, not mine. I also tried

this.getClass().getClassLoader().getResourceAsStream(...)

But the result was the same. What's the proper way to read the manifest file from inside of a webapp running in tomcat?

Edit: Thanks for the suggestions so far. Also, I should note that I am running tomcat standalone; I launch it from the command line, and then attach to the running instance in Eclipse's debugger. That shouldn't make a difference, should it?

4

7 回答 7

91

也许您的副作用来自几乎所有罐子都包含 MANIFEST.MF 而您没有得到正确的事实。要从 webapp 中读取 MANIFEST.MF,我会说:

ServletContext application = getServletConfig().getServletContext();
InputStream inputStream = application.getResourceAsStream("/META-INF/MANIFEST.MF");
Manifest manifest = new Manifest(inputStream);

请注意,从 Eclipse 运行 Tomcat 与单独运行 Tomcat 不同,因为 Eclipse 使用类加载器。

于 2009-03-05T16:28:39.870 回答
11

有点晚了,但这对我有用(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}"));
于 2010-03-18T11:29:18.897 回答
3

尝试使用jcabi-manifests,它会为您完成所有这些加载工作。例如:

String version = Manifests.read("My-Version");

从可用文件之一加载My-Version属性。MANIFEST.MF

重要的是要提到(更多细节在这里)在大多数 Web 容器中,当前线程类加载器与 servlet 上下文类加载器不同。这就是为什么您应该在运行时将您的 servlet 上下文附加到寄存器(更多信息):

Manifests.append(servletContext);

另外,请查看:http ://www.yegor256.com/2014/07/03/how-to-read-manifest-mf.html

于 2012-12-02T16:18:38.183 回答
2

类加载器的默认工作方式是在尝试查找自己的资源之前先顺从父级。因此,如果父类加载器有任何可用的清单,这就是您将得到的。事实上,应用服务器不一定会这样做,以允许应用程序覆盖库的版本。此外,类加载器可以有多个 jar,因此可以有多个清单。

它可能能够获取您唯一命名的资源之一的资源 URL。打开一个连接。投射到JarURLConnection. 获取JarFile. 从中加载清单。这可能行不通,特别是如果 Tomcat 引发战争。

[更新] 当然,war 文件本身不在类路径中。类路径将包含类似 WEB-INF/lib/( .jar| .zip) 和 WEB-INF/classes/ 的内容。从ServletContext应该工作中获取资源。

最佳解决方案:做一些不同的事情。:)

于 2009-03-05T16:34:14.600 回答
2

正确的清单存在于服务器的应用程序根目录中。找出应用程序根,例如通过找出类的类路径:

String rootPath  = getClass().getProtectionDomain().getCodeSource().getLocation().getPath()

然后将上面的路径替换为已建立的路径: Glassfish 示例:

/applications/<webProject>/META-INF/MANIFEST.MF

它对我有用。

于 2015-06-22T16:15:02.433 回答
1

不知道“官方”的阅读方式,但是如果 MANIFEST.MF 不能作为资源正确加载,那么尝试从某个 Web 路径上的“ServletContext.getRealPath()”获取其路径怎么样在您的应用程序中定义?

在构建期间由 ant 将应用程序版本也写入其他地方(WEB-INF/类中的属性文件)是我想到的另一个解决方案。

于 2009-03-05T16:26:25.227 回答
0

这就是我将各种版本打印到日志文件的方法。我已经硬编码了一个扩展路径,但应用程序可以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();
}
于 2015-08-30T10:43:54.623 回答