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

Posted

技术标签:

【中文标题】使用 Gradle 的 JAR 中的 META-INF/服务【英文标题】:META-INF/services in JAR with Gradle 【发布时间】:2012-10-26 14:49:30 【问题描述】:

我想构建一个可以用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 足够好,无法自己找到解决方案。

【问题讨论】:

你确定吗?对我来说很好。你到底把这个文件放在哪里?你的build.gradle看起来怎么样? 在主源文件夹src/main/java 中有一个META-INF 目录。构建脚本没有什么特别之处。它几乎是一个标准的,包含一些额外的依赖项和一些自定义存储库。 【参考方案1】:

与此同时,我在(有点)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

【讨论】:

我暂时不会接受我自己的答案,因为我认为这只是一种解决方法。就像上面提到的@axtavt,它应该在build.gradle 中没有这些行。【参考方案2】:

你把META-INF/services/org.example.plugins.PluginService放在src/main/java里面,但是它不是源文件,是资源文件,所以应该按照Maven目录布局约定放在resources文件夹中,也就是

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

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

【讨论】:

【参考方案3】:

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

【讨论】:

【参考方案4】:

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

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

include 'META-INF/services/**'

在您的源集中。这种模式是通用的,将获取您所有的元信息服务。

下面的完整示例。

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' 
    

【讨论】:

【参考方案5】:

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

用法

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

【讨论】:

以上是关于使用 Gradle 的 JAR 中的 META-INF/服务的主要内容,如果未能解决你的问题,请参考以下文章

gradle使用本地jar包

更改 gradle 中的 fat jar 名称

Android Gradle 构建中不使用 libs 文件夹中的 Jar 文件

如何将 git 存储库中的 jar 文件添加为 gradle 中的依赖项?

Gradle:使用依赖关系jar中的资源作为源集

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