【发布时间】:2010-09-09 08:55:09
【问题描述】:
在 Java 中,您经常会看到一个 META-INF 文件夹,其中包含一些元文件。这个文件夹的用途是什么,我可以放什么?
【问题讨论】:
在 Java 中,您经常会看到一个 META-INF 文件夹,其中包含一些元文件。这个文件夹的用途是什么,我可以放什么?
【问题讨论】:
来自the official JAR File Specification(链接到 Java 7 版本,但至少从 v1.3 开始文本没有改变):
META-INF 目录
META-INF 目录中的以下文件/目录被 Java 2 平台识别和解释,以配置应用程序、扩展、类加载器和服务:
MANIFEST.MF清单文件,用于定义扩展和打包相关数据。
INDEX.LIST此文件由 jar 工具的新“
-i”选项生成,其中包含应用程序或扩展中定义的包的位置信息。它是 JarIndex 实现的一部分,被类加载器用来加速类加载过程。
x.SFJAR 文件的签名文件。 'x' 代表基本文件名。
x.DSA与具有相同基本文件名的签名文件关联的签名块文件。该文件存储了对应签名文件的数字签名。
services/这个目录存放了所有的服务提供者配置文件。
自 Java 9 以来实现 JEP 238 的新功能是多版本 JAR。您将看到一个子文件夹versions。这是一项允许将用于不同 Java 版本的类打包到一个 jar 中的功能。
【讨论】:
一般来说,您不应该自己在 META-INF 中添加任何内容。相反,您应该依赖于您用来打包 JAR 的任何东西。这是我认为 Ant 真正擅长的领域之一:指定 JAR 文件清单属性。很容易说这样的话:
<jar ...>
<manifest>
<attribute name="Main-Class" value="MyApplication"/>
</manifest>
</jar>
至少,我认为这很容易...... :-)
关键是 META-INF 应该被认为是一个内部 Java meta 目录。不要惹它!您想要包含在 JAR 中的任何文件都应该放在其他子目录或 JAR 本身的根目录中。
【讨论】:
我注意到一些 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 中究竟有什么问题。但它似乎是一个新兴的事实上的标准。要么是那个,要么是一个新兴的反模式:-)
【讨论】:
META-INF 文件夹是 MANIFEST.MF 文件的主目录。此文件包含有关 JAR 内容的元数据。例如,有一个名为 Main-Class 的条目,它使用可执行 JAR 文件的静态 main() 指定 Java 类的名称。
【讨论】:
在 Maven 中,META-INF 文件夹的理解是因为 Standard Directory Layout,它按照名称约定将您的项目资源打包在 JAR 中:放置在 ${basedir 中的任何目录或文件}/src/main/resources 目录被打包到你的 JAR 中,并且从 JAR 的底部开始具有完全相同的结构。
文件夹 ${basedir}/src/main/resources/META-INF 通常包含 .properties 文件,而 jar 中包含生成的 MANIFEST。 MF、pom.properties、pom.xml 等文件。像Spring 这样的框架也使用classpath:/META-INF/resources/ 来提供网络资源。
欲了解更多信息,请参阅How do I add resources to my Maven Project。
【讨论】:
你也可以在里面放置静态资源。
例如:
META-INF/resources/button.jpg
并通过 web3.0-container 获取它们
http://localhost/myapp/button.jpg
/META-INF/MANIFEST.MF 有特殊含义:
java -jar myjar.jar org.myserver.MyMainClass 运行 jar,您可以将主类定义移动到 jar 中,这样您就可以将调用缩小到 java -jar myjar.jar。java.lang.Package.getPackage("org.myserver").getImplementationTitle(),你可以为包定义元信息。【讨论】:
除了这里的信息,META-INF 是一个特殊的文件夹,ClassLoader 对待它的方式与 jar 中的其他文件夹不同。
嵌套在 META-INF 文件夹中的元素不会与它之外的元素混合。
把它想象成另一个根。从Enumerator<URL> ClassLoader#getSystemResources(String path)方法等角度:
当给定路径以“META-INF”开头时,该方法会搜索嵌套在类路径中所有 jar 的 META-INF 文件夹中的资源。
当给定路径不以“META-INF”开头时,该方法会在类路径中所有 jar 和目录的所有其他文件夹(META-INF 之外)中搜索资源。
如果您知道getSystemResources方法特殊处理的另一个文件夹名称,请评论它。
【讨论】:
在此补充一下信息,如果是 WAR 文件,META-INF/MANIFEST.MF 文件为开发人员提供了一个工具来启动容器的部署时间检查,以确保容器可以找到所有您的应用程序所依赖的类。这样可以确保万一您错过了一个 JAR,您不必等到您的应用程序在运行时崩溃才意识到它丢失了。
【讨论】:
我最近一直在思考这个问题。似乎对 META-INF 的使用没有任何限制。当然,关于将清单放在那里的必要性有一定的限制,但似乎没有任何禁止将其他东西放在那里。
为什么会这样?
cxf 案可能是合法的。这是另一个建议使用这种非标准来解决 JBoss-ws 中的一个讨厌的错误的地方,该错误会阻止服务器端对 wsdl 的架构进行验证。
http://community.jboss.org/message/570377#570377
但似乎真的没有任何标准,任何你不应该这样做。通常这些东西是非常严格的定义,但由于某种原因,这里似乎没有标准。奇怪的。似乎 META-INF 已成为任何无法通过其他方式轻松处理的所需配置的包罗万象的地方。
【讨论】:
如果您使用 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
【讨论】:
所有答案都是正确的。 Meta-inf 有很多用途。另外,这里有一个使用tomcat容器的例子。
转到 Tomcat Doc 并检查 “标准实现>copyXML”属性。
描述如下。
如果您希望在部署应用程序时将嵌入在应用程序中的上下文 XML 描述符(位于 /META-INF/context.xml)复制到拥有主机的 xmlBase,则设置为 true。在随后的启动中,复制的上下文 XML 描述符将优先于嵌入在应用程序中的任何上下文 XML 描述符使用,即使嵌入在应用程序中的描述符是更新的。该标志的值默认为 false。注意如果拥有Host的deployXML属性为false,或者拥有Host的copyXML属性为true,则该属性无效。
【讨论】:
您的 META-INF 文件夹中有 MANIFEST.MF 文件。您可以定义您必须有权访问的可选或外部依赖项。
示例:
假设您已经部署了您的应用程序,并且您的容器(在运行时)发现您的应用程序需要一个不在 lib 文件夹内的较新版本的库,在这种情况下,如果您在 @987654321 中定义了可选的较新版本@ 然后您的应用将引用那里的依赖项(并且不会崩溃)。
Source: Head First Jsp & Servlet
【讨论】:
此外,META-INF 文件夹现在也用于multi-release jars。这是一项允许将用于不同 Java 版本的类打包到一个 jar 中的功能,例如在一个同样适用于 Java 8 的 jar 中包含一个用于 Java 11 的类,该类具有 Java 11 提供的新功能,其中包含一个用于 Java 8 的不同类,其中包含的功能较少。例如,如果较新的 Java 版本提供了增强的、不同的或新的 API 方法,这些方法由于 API 违规而在早期版本中不起作用。然后会看到一个子文件夹versions。
【讨论】: