Java 如何读取在ApacheTomcat中运行的webapp的清单文件?

Java 如何读取在ApacheTomcat中运行的webapp的清单文件?,java,tomcat,jar,manifest,Java,Tomcat,Jar,Manifest,我有一个webapp,其中包含一个清单文件,在ant构建任务期间,我在其中编写应用程序的当前版本。清单文件的创建是正确的,但当我在运行时尝试读入它时,会产生一些奇怪的副作用。我在清单中读取的代码如下: InputStream manifestStream = Thread.currentThread() .getContextClassLoader() .g

我有一个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的调试器中连接到正在运行的实例。这应该不会有什么区别,对吧?

我不知道用“官方”的方式来读取它,但是如果MANIFEST.MF不能作为资源正确加载,那么尝试从应用程序中定义的某个web路径上的“ServletContext.getRealPath()”派生其路径如何


我想到的另一个解决方案是,在构建过程中,由ant将应用程序版本也写到其他地方(WEB-INF/classes中的属性文件)。可能你的副作用来自这样一个事实:几乎所有JAR都包含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使用类加载器。

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

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

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


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

有点晚了,但这对我很有效(Glassfish中的web应用程序)

尝试使用,这将为您完成所有加载工作。例如:

String version = Manifests.read("My-Version");
从可用的
MANIFEST.MF
文件之一加载
My Version
属性

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


另外,请检查以下内容:

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

String rootPath  = getClass().getProtectionDomain().getCodeSource().getLocation().getPath()
然后将上面的路径替换为已创建的路径:Glassfish示例:

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

这对我来说很有用。

这就是我将各种版本打印到日志文件的方法。我已经硬编码了一个扩展路径,但是应用程序可以使用
servletContext.getRealPath(“/”)
读取webapp文件夹的完整路径。可以打印给定的库或库文件夹中的所有内容

// 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();
}
//打印库版本(jersey-common.jar、jackson-core-2.6.1.jar)
试一试{
List jars=Arrays.asList(“jersey common”、“jackson core”、“openjpa”、“mylib”);
StringBuilder verbuf=新的StringBuilder();
对于(文件:新文件(“/opt/tomcat/webapps/myapp/WEB-INF/lib/”).listFiles()){
字符串名称=file.getName();
如果(file.isDirectory()| | |!file.isFile()| |!name.endsWith(“.jar”))继续;
name=name.substring(0,name.length()-4);
boolean found=jars.contains(名称);
如果(!找到){
int idx=name.lastIndexOf('-');
如果(idx>0)
found=jars.contains(name.substring(0,idx));
}
如果(!found)继续;
JarFile JarFile=新的JarFile(file,false);
试一试{
弦长;
Manifest mf=jarFile.getManifest();
if(mf!=null){
ver=mf.getMainAttributes().getValue(“捆绑版本”);
if(ver==null | | ver.isEmpty())
ver=mf.getMainAttributes().getValue(“实现版本”);
}else-ver=null;
如果(verbuf.length()>0)verbuf.append(“,”);
append(name+“=”+(ver!=null?ver:);
}最后{
jarFile.close();
}
}
System.out.println(verbuf.toString());
}捕获(例外情况除外){
例如printStackTrace();
}

请注意:由于长值在更多行中被打断,因此使用
属性会发现以下问题。用户
Manifest
class。@PascalThivent的答案是正确的。添加一些异常处理,以防您的清单不存在(即:IDE),并且它应该是A1。这个通用方法帮助了我:[@PascalThivent有什么方法可以使它在eclipse中运行tomcat时工作吗?非常感谢。我在中对此进行了详细介绍,以了解如何进入
@服务
/applications/<webProject>/META-INF/MANIFEST.MF
// 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();
}