2012-11-06 28 views
17

Chciałem zbudować moduł wtyczki, który może być ładowany z ServiceLoader. Wymaga to dodania pliku do katalogu META-INF/services, nazwanego po interfejsie usługi i zawierającego ścieżkę kwalifikacyjną do klasy, która ją implementuje. Następnie możesz załadować te usługi, dzwoniąc pod numer ServiceLoader.load().META-INF/usługi w JAR z Gradle

Oto przykład:

że chcemy zapewnić interfejs wtyczki o nazwie org.example.plugins.PluginService. Następnie zapewniamy implementację tej usługi w klasie org.example.plugins.impl.ExamplePlugin.

Jeśli chcemy mieć jakiś mechanizm wtyczek, możemy stworzyć plik JAR zawierający implementację. Ten plik JAR musi również zawierać plik META-INF/services/org.example.plugins.PluginService. Plik ten musi zawierać jedną linię: , aby umożliwić ServiceLoader znalezienie implementacji. Jeśli plik JAR jest na ścieżce kompilacji można załadować wtyczki wywołując

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

To iterator da Ci dostęp too wszystkie wtyczki, które są znalezione przez ServiceLoader.

Z jakiegoś powodu Gradle domyślnie nie umieszcza plików w katalogu META-INF. Czy istnieje sposób, aby wynikowy plik JAR zawierał taki plik?

Już znalazłem metodę metaInf w klasie Jar. Ale nie wiem, że jest wystarczająco dobry, aby znaleźć rozwiązanie na własną rękę.

+1

Czy jesteś pewien? Działa dobrze dla mnie. Gdzie dokładnie umieścisz ten plik i jak wygląda twój 'build.gradle'? – axtavt

+0

Istnieje katalog 'META-INF' w głównym folderze źródłowym' src/main/java'. Nie ma nic specjalnego w skrypcie budowania. Jest prawie standardowy, zawiera pewne dodatkowe zależności i niektóre niestandardowe repozytoria. – pvorb

Odpowiedz

28

umieścić META-INF/services/org.example.plugins.PluginService w src/main/java, ale nie jest to źródło, to plik zasobów, dlatego należy go umieścić w folderze zasobów zgodnie z konwencją układu katalogów Maven, czyli

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

W tym przypadku wszystko powinno działać poprawnie po wyjęciu z pudełka.

5

Tymczasem znalazłem rozwiązanie mojego problemu w (nieco) similar Question.

Dodanie następujących do pliku gradle.build, rozwiązuje mój problem

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

Teraz plik JAR wygląda jak oczekiwano

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

Nie przyjmuję teraz mojej własnej odpowiedzi, ponieważ uważam, że jest to tylko obejście. Podobnie jak w przypadku @axtavt, o którym mowa powyżej, powinien działać bez tych wierszy w 'build.gradle'. – pvorb

0

Jeśli zdarzy ci się odziedziczyć kod źródłowy oparty na mrówce, który nie jest zgodny z konwencjami, pomocne mogą być poniższe wskazówki.

określić swoje źródło ustawia dopasować strukturę starszych i obejmują linię:

include 'META-INF/services/**'

w tabelach źródłowych. Ten wzór jest ogólny i zbierze wszystkie twoje usługi meta inf.

Pełny przykład poniżej.

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' } 
    } 
} 
Powiązane problemy