在 Java 中,您经常会看到一个 META-INF 文件夹,其中包含一些元文件。这个文件夹的用途是什么,我可以放什么?
13 回答
来自官方 JAR 文件规范(链接到 Java 7 版本,但至少从 v1.3 开始文本没有改变):
META-INF 目录
META-INF 目录中的以下文件/目录被 Java 2 平台识别和解释,以配置应用程序、扩展、类加载器和服务:
MANIFEST.MF
用于定义扩展和包相关数据的清单文件。
INDEX.LIST
此文件由
-i
jar 工具的新“”选项生成,其中包含在应用程序或扩展中定义的包的位置信息。它是 JarIndex 实现的一部分,并被类加载器用来加速其类加载过程。
x.SF
JAR 文件的签名文件。“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元目录。不要惹它!您想要包含在 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 用户指南。在我从事的一个项目中,我们必须允许通过 Spring 进行多级配置,我们遵循这个约定并将我们的配置文件放在 META-INF 中。
当我反思这个决定时,我不知道将配置文件简单地包含在特定的 Java 包中而不是 META-INF 中究竟有什么问题。但它似乎是一个新兴的事实上的标准。无论是那个,还是一个新兴的反模式:-)
META-INF 文件夹是MANIFEST.MF文件的主目录。此文件包含有关 JAR 内容的元数据。例如,有一个名为 Main-Class 的条目,它使用可执行 JAR 文件的静态 main() 指定 Java 类的名称。
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.MF、pom.properties、 pom.xml等文件。像Spring这样的框架也用于classpath:/META-INF/resources/
提供 Web 资源。
有关更多信息,请参阅如何将资源添加到我的 Maven 项目。
您也可以在其中放置静态资源。
例如:
META-INF/resources/button.jpg
并通过 web3.0-container 获取它们
http://localhost/myapp/button.jpg
/META-INF/MANIFEST.MF 具有特殊含义:
- 如果您使用 jar 运行,
java -jar myjar.jar org.myserver.MyMainClass
您可以将主类定义移动到 jar 中,这样您就可以将调用缩小到java -jar myjar.jar
. - 如果您使用
java.lang.Package.getPackage("org.myserver").getImplementationTitle()
. - 您可以参考您喜欢在 Applet/Webstart 模式下使用的数字证书。
在此处添加信息,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 文件夹内的库的较新版本,在这种情况下,如果您在其中定义了可选的较新版本,MANIFEST.MF
那么您的应用程序将引用从那里依赖(并且不会崩溃)。
Source:
Head First Jsp & Servlet
此外,META-INF 文件夹现在也用于多版本 jars。这是一个允许将用于不同 Java 版本的类打包在一个 jar 中的功能,例如,在一个 jar 中包含一个用于 Java 11 的类,该类具有 Java 11 提供的新功能,也适用于 Java 8,其中 Java 8 的不同类包含的功能较少。例如,如果较新的 Java 版本提供了增强的、不同的或新的 API 方法,这些方法由于 API 违规而在早期版本中不起作用。然后会看到一个子文件夹versions
。