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

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

所以基本上我要做的就是 在 JAR 的“ META-INF/services”文件夹中包含一个具有文件名(X)和一行文本(Y)的文件。我猜这应该使用 Maven 来完成,也许可以在 POM 文件中指定一个属性,但是我的研究没有发现任何东西。我知道你不应该硬编码或手动输入任何 META 文件,所以我不知道该怎么办。

100701 次浏览

Create a new source folder with the location src/main/resources, then create your META-INF/services folder in there and drop in your fully-qualified class name (FQCN) file. This should copy them into the jar file automatically. So for implementations of an interface with a FQCN of com.acme.MyInterface, you'll have:

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

Note that com.acme.MyInterface is the name of the file, not a directory structure like a Java package. The name of the file is the FQCN of the interface that you're implementing, and in it, you'll have the FQCN of each implementation on its own line, e.g.:

com.example.MyInterfaceImpl
com.example.AnotherMyInterfaceImpl

It's worth noting that this applies to Gradle projects with the default source sets as well.

Once you do this, you can load all the implementations of the interface using 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());
}

Some things to note:

  • All the implementations must have a no-args constructor
  • Applications that use modules or custom classloaders may have to use the overloads of ServiceLoader.load

If these conditions won't work for you, then you may want to switch to another system, e.g. a CDI-style framework like Spring, EJB, etc.

By default Maven looks for resources at:

src/main/resources

So put it at

src/main/resources/META-INF/services

Alternatively, if your project does not use a standard directory structure (or your simply wish to have alternate resource directories), you can specify resource directories manually the POM file.

For example, if your META-INF/services is located in a folder called resources which lies in the root of your project directory, could specify it as follows:

<project>
...
<build>
...
<resources>
<resource>
<directory>resources</directory>
</resource>
</resources>
...
</build>
...
</project>

You can use this to specify several directories by adding multiple <resource> elements.