2012-11-06 51 views
17

我想構建一個插件模塊,可以使用ServiceLoader加載。這需要向META-INF/services目錄中添加一個文件,該文件以服務接口命名,幷包含實現該目錄的類的合格路徑。然後您可以致電ServiceLoader.load()加載這些服務。META-INF /帶有Gradle的JAR服務

下面是一個例子:

說,我們要提供所謂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能夠自己找到解決方案。

+1

你確定嗎?對我來說工作得很好。你究竟在哪裏放置這個文件,你的'build.gradle'看起來如何? – axtavt

+0

主要源文件夾「src/main/java」中有一個「META-INF」目錄。構建腳本沒有什麼特別之處。它幾乎是一個標準的,包含一些額外的依賴和一些自定義存儲庫。 – pvorb

回答

28

你把META-INF/services/org.example.plugins.PluginServicesrc/main/java,但它不是一個來源,這是一個資源文件,因此應根據Maven目錄佈局約定將其放置在資源文件夾中,即

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

在這種情況下,一切應該開箱即用。

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 
+0

我現在不會接受我自己的答案,因爲我認爲這只是一種解決方法。像上面提到的@axtavt一樣,它應該在'build.gradle'中沒有這些行。 – pvorb

0

如果您碰巧繼承了一些不遵循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' } 
    } 
}