Je voulais construire un module de plugin qui puisse être chargé avec un ServiceLoader
. Cela nécessite l'ajout d'un fichier au répertoire META-INF/services
, nommé d'après l'interface de service et contenant le chemin d'accès qualifiant à la classe qui l'implémente. Ensuite, vous pouvez charger ces services en appelant ServiceLoader.load()
.
Voici un exemple:
Supposons que nous voulions fournir une interface de plug-in appelée org.example.plugins.PluginService
. Nous fournissons ensuite une implémentation de ce service dans la classe org.example.plugins.impl.ExamplePlugin
.
Si nous voulons avoir une sorte de mécanisme de plugin, nous pourrions créer un fichier JAR contenant l’implémentation. Ce fichier JAR doit également contenir le fichier META-INF/services/org.example.plugins.PluginService
. Ce fichier doit contenir une ligne
org.example.plugins.impl.ExamplePlugin
pour permettre à la ServiceLoader
de trouver l'implémentation. Si ce fichier JAR se trouve dans le chemin de génération, vous pouvez charger le plug-in en appelant
Iterator<PluginService> it = ServiceLoader.load(PluginService.class).iterator();
Cet itérateur vous donnera également accès à tous les plugins trouvés par la variable ServiceLoader
.
Pour une raison quelconque, Gradle n'inclut pas de fichiers dans le répertoire META-INF
par défaut. Existe-t-il un moyen de laisser le fichier JAR résultant contenir un tel fichier?
J'ai déjà trouvé la méthode metaInf
in class Jar
. Mais je ne sais pas assez bien pour trouver la solution moi-même.
Vous placez META-INF/services/org.example.plugins.PluginService
dans src/main/Java
, mais ce n'est pas une source, c'est un fichier de ressources. Par conséquent, il doit être placé dans le dossier des ressources conformément à la convention de mise en forme de répertoire Maven, c'est-à-dire
src/main/resources/META-INF/services/org.example.plugins.PluginService
Dans ce cas, tout devrait fonctionner hors de la boîte.
En attendant, j'ai trouvé une solution à mon problème dans une (un peu) Question similaire .
Ajouter ce qui suit dans le fichier gradle.build
résout mon problème
jar {
from ('./src/main/Java') {
include 'META-INF/services/org.example.plugins.PluginService'
}
}
Maintenant, le fichier JAR ressemble comme prévu
.
|- org
| `- example
| `- plugins
| `- impl
| `- ExamplePlugin.class
`- META-INF
|- MANIFEST.MF
`- services
`- org.example.plugins.PluginService
J'espère qu'ils mettront cela en œuvre dans la tâche du bocal, tout comme le fait ant. Quelqu'un a déjà travaillé dessus: http://fgaliegue.blogspot.fr/2013/06/gradle-serviceloader-support.html
Si vous héritez d'un code hérité basé sur ant qui ne respecte pas les conventions Maven, voici ce qui pourrait vous aider.
Définissez vos ensembles source pour qu'ils correspondent à la structure existante et incluez une ligne comme celle-ci:
include 'META-INF/services/**'
Dans vos ensembles de sources. Ce modèle est générique et récupérera tous vos services meta inf.
Exemple complet ci-dessous.
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' }
}
}
Salut peut essayer ceci: https://plugins.gradle.org/plugin/com.github.harbby.gradle.serviceloader
Usage
serviceLoader {
serviceInterface 'org.example.plugins.PluginService'
serviceInterface 'org.example.plugins.PluginService2'
}