使用Gradle的JAR中的META-INF /服务

我想构建一个可以加载ServiceLoader的插件模块。 这需要将文件添加到META-INF/services目录,该目录以服务接口命名,并包含实现它的类的限定路径。 然后,您可以通过调用ServiceLoader.load()来加载这些服务。

这是一个例子:

假设我们想要提供一个名为org.example.plugins.PluginService的插件接口。 然后,我们在org.example.plugins.impl.ExamplePlugin类中提供此服务的实现。

如果我们想要某种插件机制,我们可以创建一个包含实现的JAR文件。 此JAR文件还必须包含文件META-INF/services/org.example.plugins.PluginService 。 该文件必须包含一行

 org.example.plugins.impl.ExamplePlugin 

使ServiceLoader能够找到实现。 如果该JAR文件位于构建路径中,则可以通过调用来加载插件

 Iterator it = ServiceLoader.load(PluginService.class).iterator(); 

该迭代器将允许您访问ServiceLoader找到的所有插件。

出于某种原因,Gradle默认情况下不会将文件包含到META-INF目录中。 有没有办法让生成的JAR包含这样的文件?

我已经在类Jar找到了方法metaInf 。 但我不知道groovy足以找到我自己的解决方案。

你将META-INF/services/org.example.plugins.PluginService放在src/main/java ,但它不是源文件,它是一个资源文件,因此它应该根据Maven目录布局约定放在resources文件夹中,即

 src/main/resources/META-INF/services/org.example.plugins.PluginService 

在这种情况下,一切都应该开箱即用。

与此同时,我在一个(有点) 类似的问题中找到了我的问题的解决方案。

将以下内容添加到gradle.build文件中可以解决我的问题

 jar { from ('./src/main/java') { include 'META-INF/services/org.example.plugins.PluginService' } } 

现在JAR文件看起来像预期的那样

 . |- org | `- example | `- plugins | `- impl | `- ExamplePlugin.class `- META-INF |- MANIFEST.MF `- services `- org.example.plugins.PluginService 

希望他们能像jar一样在jar任务中实现这一点。 有人已经开始研究它: http : //fgaliegue.blogspot.fr/2013/06/gradle-serviceloader-support.html

如果您碰巧inheritance了一些不遵循maven约定的基于ant的遗留代码,则以下内容可能有所帮助。

定义源集以匹配旧结构,并包含如下所示的行:

include 'META-INF/services/**'

在您的源集中。 此模式是通用的,将获取所有的meta inf服务。

完整的例子如下。

 sourceSets { main { java { srcDir 'src' exclude '**/Test*.java' } resources { srcDir 'src' include '**/*.xml' include 'META-INF/services/**' } } test { java { srcDir 'src' include '**/Test*.java' } resources { srcDir 'resources' } } } 

您可以试试这个: https : //plugins.gradle.org/plugin/com.github.harbby.gradle.serviceloader

用法

 serviceLoader { serviceInterface 'org.example.plugins.PluginService' serviceInterface 'org.example.plugins.PluginService2' }