Java META-INF/带有Gradle的JAR中的服务

Java META-INF/带有Gradle的JAR中的服务,java,plugins,jar,gradle,Java,Plugins,Jar,Gradle,我想建立一个插件模块,可以加载一个。这需要向META-INF/services目录添加一个文件,该文件以服务接口命名,并包含实现该接口的类的限定路径。然后,您可以通过调用ServiceLoader.load()来加载这些服务 以下是一个例子: 假设我们想提供一个名为org.example.plugins.PluginService的插件接口。然后,我们在类org.example.plugins.impl.ExamplePlugin中提供此服务的实现 如果我们想要某种插件机制,我们可以创建一个JA

我想建立一个插件模块,可以加载一个。这需要向
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<PluginService> it = ServiceLoader.load(PluginService.class).iterator();
Iterator it=ServiceLoader.load(PluginService.class).Iterator();
该迭代器将允许您访问
ServiceLoader
找到的所有插件

出于某种原因,Gradle默认情况下不将文件包含到
META-INF
目录中。有没有办法让结果JAR包含这样一个文件


我已经在类
Jar
中找到了该方法。但我对groovy的了解还不够好,无法自己找到解决方案。

与此同时,我在一个(某种程度上)中找到了问题的解决方案

将以下内容添加到
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

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

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

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

希望他们能像ant一样在jar任务中实现这一点。有人已经做过了:

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

定义源集以匹配旧式结构,并包括以下行:

包括“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' }
    }
}
嗨,你可以试试这个:

用法


你确定吗?对我来说很好。你把这个文件放在哪里?你的
build.gradle
是什么样子?在主源文件夹
src/main/java
中有一个
META-INF
目录。构建脚本没有什么特别之处。这几乎是一个标准版本,包含一些附加依赖项和一些自定义存储库。我现在不接受我自己的答案,因为我认为这只是一个解决办法。像上面提到的@axtavt一样,它应该在
build.gradle
中没有这些行的情况下工作。
serviceLoader {
    serviceInterface 'org.example.plugins.PluginService'
    serviceInterface 'org.example.plugins.PluginService2'
}