【问题标题】:What's the purpose of META-INF?META-INF 的目的是什么?
【发布时间】:2010-09-09 08:55:09
【问题描述】:

在 Java 中,您经常会看到一个 META-INF 文件夹,其中包含一些元文件。这个文件夹的用途是什么,我可以放什么?

【问题讨论】:

标签: java meta-inf


【解决方案1】:

来自the official JAR File Specification(链接到 Java 7 版本,但至少从 v1.3 开始文本没有改变):

META-INF 目录

META-INF 目录中的以下文件/目录被 Java 2 平台识别和解释,以配置应用程序、扩展、类加载器和服务:

  • MANIFEST.MF

清单文件,用于定义扩展和打包相关数据。

  • INDEX.LIST

此文件由 jar 工具的新“-i”选项生成,其中包含应用程序或扩展中定义的包的位置信息。它是 JarIndex 实现的一部分,被类加载器用来加速类加载过程。

  • x.SF

JAR 文件的签名文件。 'x' 代表基本文件名。

  • x.DSA

与具有相同基本文件名的签名文件关联的签名块文件。该文件存储了对应签名文件的数字签名。

  • services/

这个目录存放了所有的服务提供者配置文件。

自 Java 9 以来实现 JEP 238 的新功能是多版本 JAR。您将看到一个子文件夹versions。这是一项允许将用于不同 Java 版本的类打包到一个 jar 中的功能。

【讨论】:

  • TLD 也必须在 META-INF 下。
  • @erickson,详细说明?
  • @Pacerier 用于 JSP 标记库的标记库描述符必须位于 META-INF 目录中。早在 2008 年,我就忘记了 TLD 代表什么。
【解决方案2】:

一般来说,您不应该自己在 META-INF 中添加任何内容。相反,您应该依赖于您用来打包 JAR 的任何东西。这是我认为 Ant 真正擅长的领域之一:指定 JAR 文件清单属性。很容易说这样的话:

<jar ...>
    <manifest>
        <attribute name="Main-Class" value="MyApplication"/>
    </manifest>
</jar>

至少,我认为这很容易...... :-)

关键是 META-INF 应该被认为是一个内部 Java meta 目录。不要惹它!您想要包含在 JAR 中的任何文件都应该放在其他子目录或 JAR 本身的根目录中。

【讨论】:

  • 服务怎么样?标签库描述符?将某些东西放在 JAR 的根目录中是个坏主意。在没有明确约定的情况下,根中的资源很可能发生冲突。
  • 如果您使用 JPA,那么您必须将 persistence.xml 放入该文件夹,这不会自动发生。
  • 这将是一个很好的答案,除了在简单的 Spring MVC 应用程序中,META-INF 是单元测试和控制器都可以引用配置文件的唯一目录。如果另一个目录可以工作,那就太好了——它不会(至少不是直截了当)。对我来说,建立一个 Jar 文件只是为了测试一个战争文件就像造一辆汽车,这样你就可以走到厨房了。至少对我来说。但是我花了一些时间做 Ruby,就配置文件而言,它们可能毁了我(尽管我会用一点 XML 地狱来换取我的参数类型)。 :)
  • 你能给我们举一些例子,说明应该包含这个文件夹的文件类型吗?
  • 这并不能回答 META-INF 是什么。如果我对此有答案,那么也许我可以自己判断是否应该“永远”将某些内容放入该文件夹中。
【解决方案3】:

我注意到一些 Java 库已经开始使用 META-INF 作为目录,其中包含应该与 JAR 一起打包并包含在 CLASSPATH 中的配置文件。例如,Spring 允许您使用以下方式导入位于类路径上的 XML 文件:

<import resource="classpath:/META-INF/cxf/cxf.xml" />
<import resource="classpath:/META-INF/cxf/cxf-extensions-*.xml" />

在这个例子中,我直接引用了Apache CXF User Guide。在我从事的一个项目中,我们必须允许通过 Spring 进行多级配置,我们遵循这个约定并将我们的配置文件放在 META-INF 中。

当我考虑这个决定时,我不知道将配置文件简单地包含在特定的 Java 包中而不是 META-INF 中究竟有什么问题。但它似乎是一个新兴的事实上的标准。要么是那个,要么是一个新兴的反模式:-)

【讨论】:

  • 配置不属于库。我认为你用“新兴的反模式”把它钉牢了。定位与库相关的配置文件非常容易;他们不需要在同一个 JAR 中找到。
  • 我不同意配置不属于库的说法。我认为配置,尤其是在默认情况下,可以很好地打包在库中。我真的很高兴有更多的框架选择这样工作,而不是像不久前那样强迫你包含各种外部配置文件。
  • 我已经看到很多 LICENSE.TXT 类型的文件也出现在 META_INF 中,我觉得这很烦人。
  • @Eelco,代码和数据不应混用。包含外部配置文件并不一定意味着可用性混乱。这取决于它的结构。
  • 声明@Pacerier 是一件相当随意的事情。作为一般性陈述,它主要是偏好。
【解决方案4】:

META-INF 文件夹是 MANIFEST.MF 文件的主目录。此文件包含有关 JAR 内容的元数据。例如,有一个名为 Main-Class 的条目,它使用可执行 JAR 文件的静态 main() 指定 Java 类的名称。

【讨论】:

    【解决方案5】:

    Maven 中的 META-INF

    在 Maven 中,META-INF 文件夹的理解是因为 Standard Directory Layout,它按照名称约定将您的项目资源打包在 JAR 中:放置在 ${basedir 中的任何目录或文件}/src/main/resources 目录被打包到你的 JAR 中,并且从 JAR 的底部开始具有完全相同的结构。

    文件夹 ${basedir}/src/main/resources/META-INF 通常包含 .properties 文件,而 jar 中包含生成的 MANIFEST。 MFpom.propertiespom.xml 等文件。像Spring 这样的框架也使用classpath:/META-INF/resources/ 来提供网络资源。

    欲了解更多信息,请参阅How do I add resources to my Maven Project

    【讨论】:

    • 标准目录布局是一个关键点。感谢发帖。
    【解决方案6】:

    你也可以在里面放置静态资源。

    例如:

    META-INF/resources/button.jpg 
    

    并通过 web3.0-container 获取它们

    http://localhost/myapp/button.jpg
    

    > Read more

    /META-INF/MANIFEST.MF 有特殊含义:

    1. 如果您使用 java -jar myjar.jar org.myserver.MyMainClass 运行 jar,您可以将主类定义移动到 jar 中,这样您就可以将调用缩小到 java -jar myjar.jar
    2. 如果你使用java.lang.Package.getPackage("org.myserver").getImplementationTitle(),你可以为包定义元信息。
    3. 您可以引用您喜欢在 Applet/Webstart 模式下使用的数字证书。

    【讨论】:

    • 因此应用程序中的任何静态内容都应放在此目录中,例如图像或其他内容。
    【解决方案7】:

    除了这里的信息,META-INF 是一个特殊的文件夹,ClassLoader 对待它的方式与 jar 中的其他文件夹不同。 嵌套在 META-INF 文件夹中的元素不会与它之外的元素混合。

    把它想象成另一个根。从Enumerator&lt;URL&gt; ClassLoader#getSystemResources(String path)方法等角度:

    当给定路径以“META-INF”开头时,该方法会搜索嵌套在类路径中所有 jar 的 META-INF 文件夹中的资源。

    当给定路径不以“META-INF”开头时,该方法会在类路径中所有 jar 和目录的所有其他文件夹(META-INF 之外)中搜索资源。

    如果您知道getSystemResources方法特殊处理的另一个文件夹名称,请评论它。

    【讨论】:

      【解决方案8】:

      在此补充一下信息,如果是 WAR 文件,META-INF/MANIFEST.MF 文件为开发人员提供了一个工具来启动容器的部署时间检查,以确保容器可以找到所有您的应用程序所依赖的类。这样可以确保万一您错过了一个 JAR,您不必等到您的应用程序在运行时崩溃才意识到它丢失了。

      【讨论】:

        【解决方案9】:

        我最近一直在思考这个问题。似乎对 META-INF 的使用没有任何限制。当然,关于将清单放在那里的必要性有一定的限制,但似乎没有任何禁止将其他东西放在那里。

        为什么会这样?

        cxf 案可能是合法的。这是另一个建议使用这种非标准来解决 JBoss-ws 中的一个讨厌的错误的地方,该错误会阻止服务器端对 wsdl 的架构进行验证。

        http://community.jboss.org/message/570377#570377

        但似乎真的没有任何标准,任何你不应该这样做。通常这些东西是非常严格的定义,但由于某种原因,这里似乎没有标准。奇怪的。似乎 META-INF 已成为任何无法通过其他方式轻松处理的所需配置的包罗万象的地方。

        【讨论】:

          【解决方案10】:

          如果您使用 JPA1,您可能需要在其中放置一个 persistence.xml 文件,该文件指定您可能要使用的持久性单元的名称。持久化单元提供了一种方便的方式来指定一组元数据文件、类和包含要在一个分组中持久化的所有类的 jar。

          import javax.persistence.EntityManagerFactory;
          import javax.persistence.Persistence;
          
          // ...
          
          EntityManagerFactory emf =
                Persistence.createEntityManagerFactory(persistenceUnitName);
          

          在此处查看更多信息: http://www.datanucleus.org/products/datanucleus/jpa/emf.html

          【讨论】:

            【解决方案11】:

            所有答案都是正确的。 Meta-inf 有很多用途。另外,这里有一个使用tomcat容器的例子。

            转到 Tomcat Doc 并检查 “标准实现>copyXML”属性。

            描述如下。

            如果您希望在部署应用程序时将嵌入在应用程序中的上下文 XML 描述符(位于 /META-INF/context.xml)复制到拥有主机的 xmlBase,则设置为 true。在随后的启动中,复制的上下文 XML 描述符将优先于嵌入在应用程序中的任何上下文 XML 描述符使用,即使嵌入在应用程序中的描述符是更新的。该标志的值默认为 false。注意如果拥有Host的deployXML属性为false,或者拥有Host的copyXML属性为true,则该属性无效。

            【讨论】:

              【解决方案12】:

              您的 META-INF 文件夹中有 MANIFEST.MF 文件。您可以定义您必须有权访问的可选或外部依赖项

              示例:

              假设您已经部署了您的应用程序,并且您的容器(在运行时)发现您的应用程序需要一个不在 lib 文件夹内的较新版本的库,在这种情况下,如果您在 @987654321 中定义了可选的较新版本@ 然后您的应用将引用那里的依赖项(并且不会崩溃)。

              Source: Head First Jsp & Servlet

              【讨论】:

              • 不清楚其中有多少是从源代码中引用的,而且看起来也不是逐字逐句。删除了奇怪的格式。不要对不是代码的文本使用代码格式。对被引用的文本使用引号格式。
              【解决方案13】:

              此外,META-INF 文件夹现在也用于multi-release jars。这是一项允许将用于不同 Java 版本的类打包到一个 jar 中的功能,例如在一个同样适用于 Java 8 的 jar 中包含一个用于 Java 11 的类,该类具有 Java 11 提供的新功能,其中包含一个用于 Java 8 的不同类,其中包含的功能较少。例如,如果较新的 Java 版本提供了增强的、不同的或新的 API 方法,这些方法由于 API 违规而在早期版本中不起作用。然后会看到一个子文件夹versions

              【讨论】: