代码之家  ›  专栏  ›  技术社区  ›  Nik Reiman

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

  •  46
  • Nik Reiman  · 技术社区  · 17 年前

    我有一个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-infff”放进去,上面的代码仍然有效!这意味着我在读其他的清单,而不是我的。我也试过了

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

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

    编辑 :谢谢你到目前为止的建议。另外,我应该注意到 独立运行tomcat;我从命令行启动它,然后附加到eclipse调试器中正在运行的实例。这不应该有什么区别,是吗?

    7 回复  |  直到 13 年前
        1
  •  89
  •   Pascal Thivent    17 年前

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

        2
  •  11
  •   javadude    16 年前

    有点晚了,但这对我有效(glassfish中的web appl)

    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}"));
    
        3
  •  3
  •   yegor256    11 年前

    尝试使用 jcabi-manifests ,这就完成了所有的装载工作。例如:

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

    荷载 My-Version 其中一个可用的属性 MANIFEST.MF 文件夹。

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

    Manifests.append(servletContext);
    

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

        4
  •  2
  •   Tom Hawtin - tackline    17 年前

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

    它可能能够获取一个唯一命名资源的资源url。打开连接。投到 JarURLConnection 是的。得到 JarFile 是的。从中加载清单。这可能行不通,尤其是在Tomcat引爆战争的情况下。

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

    最好的解决办法:做些不同的事情。:)

        5
  •  2
  •   user3687374    11 年前

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

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

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

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

    对我有用。

        6
  •  1
  •   david a.    17 年前

    不知道如何用“正式”的方式读取它,但是如果manifest.mf不能正确地作为资源加载,那么尝试从应用程序中定义的某个web路径上的“servletcontext.getrealpath()”派生它的路径如何?

    我想到的另一个解决方案是,在构建过程中,由ant将应用程序版本也写到其他地方(web-inf/classes中的属性文件)。

        7
  •  0
  •   Whome    10 年前

    这就是我打印不同版本到日志文件的方法。我已经硬编码了扩展路径,但应用程序可能会使用 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();
    }