如何读取在apache tomcat中运行的webapp的清单文件?

时间:2009-03-05 16:19:16

标签: java tomcat jar manifest

我有一个包含清单文件的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时,我看到上面的代码有效,但它似乎得到了一个不同于我预期的清单文件,我可以告诉它,因为ant版本和构建时间戳都不同。然后,我在那里放了“META-INFFFF”,上面的代码仍然有效!这意味着我正在阅读其他一些清单,而不是我的清单。我也试过

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

但结果是一样的。从tomcat中运行的webapp内部读取清单文件的正确方法是什么?

修改:感谢您提出的建议。另外,我应该注意我运行tomcat独立;我从命令行启动它,然后附加到Eclipse调试器中正在运行的实例。这不应该有所作为,不是吗?

7 个答案:

答案 0 :(得分:89)

也许你的副作用来自这样一个事实:几乎所有的罐子都包含一个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使用类加载器。

答案 1 :(得分: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}"));

答案 2 :(得分:3)

尝试使用jcabi-manifests,这可以帮助您完成所有这些加载工作。例如:

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

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

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

Manifests.append(servletContext);

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

答案 3 :(得分:2)

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

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

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

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

答案 4 :(得分:2)

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

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

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

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

它对我有用。

答案 5 :(得分:1)

不知道读取它的“官方”方式,但是如果MANIFEST.MF无法正确加载为资源,那么如何尝试从“ServletContext.getRealPath()”中获取其路径您的应用中定义了一些网络路径?

在构建过程中,也可以通过ant将应用程序版本编写到其他地方(WEB-INF / classes中的属性文件),这是我想到的另一种解决方案。

答案 6 :(得分: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();
}