我想构建一个可以加载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<PluginService> it = ServiceLoader.load(PluginService.class).iterator();
该迭代器也会让您访问ServiceLoader
找到的所有插件。
由于某些原因,Gradle默认情况下不会将文件包含到META-INF
目录中。有没有办法让生成的JAR包含这样的文件?
我已在课程Jar
中找到方法metaInf
。但我不知道groovy足以找到我自己的解决方案。
答案 0 :(得分:34)
您将META-INF/services/org.example.plugins.PluginService
放在src/main/java
中,但它不是来源,而是资源文件,因此应根据Maven目录布局惯例将其放在资源文件夹中,即
src/main/resources/META-INF/services/org.example.plugins.PluginService
在这种情况下,一切都应该开箱即用。
答案 1 :(得分:5)
与此同时,我在(有点)similar Question找到了我的问题的解决方案。
将以下内容添加到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
答案 2 :(得分:0)
希望他们能像jar一样在jar任务中实现这一点。有人已经开始研究它:http://fgaliegue.blogspot.fr/2013/06/gradle-serviceloader-support.html
答案 3 :(得分:0)
如果您碰巧继承了一些不遵循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' }
}
}
答案 4 :(得分:0)
嗨,您可以尝试以下操作:https://plugins.gradle.org/plugin/com.github.harbby.gradle.serviceloader
用法
serviceLoader {
serviceInterface 'org.example.plugins.PluginService'
serviceInterface 'org.example.plugins.PluginService2'
}