如何使用 Maven 将配置文件包含在 JAR 的“META-INF/services”文件夹中

2022-08-31 11:43:42

我正在Eclipse中开发一个Java项目,它是使用Maven构建的。我正在使用一些来自旧项目的回收代码,其中一个类在JAR的文件夹中查找具有特定名称的文件,然后解析此文件的文本。在此特定示例中,它查找具有 Java 接口名称的文件,然后从文件内部获取实现的类名。META-INF/services

因此,基本上,我试图做的是在JAR的“META-INF/services”文件夹中包含一个文件名(X)和一行文本(Y)的文件。我想这应该使用Maven来完成,也许通过在POM文件中指定一个属性来完成,但我的研究没有发现任何东西。我知道你不应该硬编码或手动键入任何META文件,所以我不确定在这里做什么。


答案 1

使用位置创建一个新的源文件夹,然后在其中创建文件夹并放入完全限定的类名 (FQCN) 文件。这应该会自动将它们复制到jar文件中。因此,对于 FQCN 为 的接口的实现,您将拥有:src/main/resourcesMETA-INF/servicescom.acme.MyInterface

Project
| src
| | main
|   | java
|     | [your source code]
|   | resources
|     | META-INF
|       | services
|         | com.acme.MyInterface

请注意,这是文件的名称,而不是像 Java 包那样的目录结构。该文件的名称是要实现的接口的 FQCN,在其中,每个实现的 FQCN 将在其自己的行上,例如:com.acme.MyInterface

com.example.MyInterfaceImpl
com.example.AnotherMyInterfaceImpl

值得注意的是,这也适用于具有默认源代码集的 Gradle 项目。

完成此操作后,您可以使用以下命令加载接口的所有实现:ServiceLoader

ServiceLoader<MyInterface> loader = ServiceLoader.load(MyInterface.class);
for (MyInterface service : loader) {
    // Prints com.example.MyInterfaceImpl and com.example.AnotherMyInterfaceImpl
    System.out.println(service.class.getName());
}

需要注意的一些事项:

  • 所有实现都必须具有无参数构造函数
  • 使用模块或自定义类装入器的应用程序可能必须使用ServiceLoader.load

如果这些条件对您不起作用,那么您可能需要切换到另一个系统,例如CDI风格的框架,如Spring,EJB等。


答案 2

默认情况下,Maven 在以下位置查找资源:

src/main/resources

所以把它放在

src/main/resources/META-INF/services

推荐