85 votes

Comment inclure un fichier de configuration dans le dossier "META-INF/services" d'un JAR avec Maven ?

Je travaille sur un projet Java dans Eclipse, qui est construit avec Maven. J'utilise du code recyclé d'un ancien projet, et l'une de ces classes recherche un fichier dans le répertoire META-INF/services du JAR avec un nom particulier, puis analyse le texte de ce fichier. Dans cet exemple particulier, il recherche un fichier portant le nom d'une interface Java, puis récupère le nom de la classe de l'implémentation à l'intérieur du fichier.

En gros, ce que j'essaie de faire, c'est inclure un fichier dans le dossier "META-INF/services" du JAR avec un nom de fichier (X), et une ligne de texte (Y) . Je suppose que cela devrait être fait en utilisant Maven, peut-être en spécifiant un attribut dans le fichier POM, mais mes recherches n'ont rien donné. Je sais que vous n'êtes pas censé coder en dur ou taper manuellement des fichiers META, donc je ne sais pas trop quoi faire ici.

139voto

Brian Points 7975

Créer un nouveau dossier source avec l'emplacement src/main/resources puis créez votre META-INF/services et déposez-y votre fichier de nom de classe entièrement qualifié (FQCN). Cela devrait les copier automatiquement dans le fichier jar. Ainsi, pour les implémentations d'une interface avec un FQCN de com.acme.MyInterface Vous aurez :

Project
| src
| | main
|   | java
|     | [your source code]
|   | resources
|     | META-INF
|       | services
|         | com.acme.MyInterface

Il convient de noter que com.acme.MyInterface est le nom du fichier, et non une structure de répertoire comme un paquetage Java. Le nom du fichier est le FQCN de l'interface que vous implémentez, et dans ce fichier, vous aurez le FQCN de chaque implémentation sur sa propre ligne, par exemple :

com.example.MyInterfaceImpl
com.example.AnotherMyInterfaceImpl

Il est intéressant de noter que cela s'applique également aux projets Gradle avec les jeux de sources par défaut.

Une fois que vous avez fait cela, vous pouvez charger toutes les implémentations de l'interface à l'aide de la fonction ServiceLoader :

ServiceLoader<MyInterface> loader = ServiceLoader.load(MyInterface.class);
for (MyInterface service : loader) {
    // Prints com.example.MyInterfaceImpl and com.example.AnotherMyInterfaceImpl
    System.out.println(service.class.getName());
}

Quelques points à noter :

  • Toutes les implémentations doivent avoir un constructeur no-args
  • Les applications qui utilisent des modules ou des chargeurs de classe personnalisés peuvent être amenées à utiliser les surcharges de ServiceLoader.load

Si ces conditions ne vous conviennent pas, vous pouvez opter pour un autre système, par exemple un cadre de type CDI comme Spring, EJB, etc.

25voto

Puce Points 13540

Par défaut, Maven recherche des ressources à :

src/main/resources

Mettez-le donc à

src/main/resources/META-INF/services

16voto

Si votre projet n'utilise pas une structure de répertoire standard (ou si vous souhaitez simplement disposer de répertoires de ressources alternatifs), vous pouvez également spécifier répertoires de ressources manuellement le fichier POM.

Par exemple, si votre META-INF/services se trouve dans un dossier appelé resources qui se trouve à la racine de votre répertoire de projet, pourrait être spécifié comme suit :

<project>
...
  <build>
    ...
    <resources>
      <resource>
        <directory>resources</directory>
      </resource>
    </resources>
    ...
  </build>
  ...
</project>

Vous pouvez l'utiliser pour spécifier plusieurs répertoires en ajoutant plusieurs <resource> éléments.

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X