it-swarm.com.de

META-INF/Dienstleistungen in JAR mit Gradle

Ich wollte ein Plugin-Modul erstellen, das mit einer ServiceLoader geladen werden kann. Dazu müssen Sie dem Verzeichnis META-INF/services eine Datei hinzufügen, die nach der Service-Schnittstelle benannt ist und den qualifizierenden Pfad zu der Klasse enthält, die sie implementiert. Dann können Sie diese Dienste laden, indem Sie ServiceLoader.load() aufrufen.

Hier ist ein Beispiel:

Angenommen, wir möchten eine Plugin-Schnittstelle mit dem Namen org.example.plugins.PluginService bereitstellen. Wir bieten dann eine Implementierung dieses Dienstes in der Klasse org.example.plugins.impl.ExamplePlugin an.

Wenn wir einen Plugin-Mechanismus haben möchten, können Sie eine JAR-Datei erstellen, die die Implementierung enthält. Diese JAR-Datei muss auch die Datei META-INF/services/org.example.plugins.PluginService enthalten. Diese Datei muss eine Zeile enthalten

org.example.plugins.impl.ExamplePlugin

um die ServiceLoader zu aktivieren, um die Implementierung zu finden. Wenn sich diese JAR-Datei im Erstellungspfad befindet, können Sie das Plugin durch Aufrufen laden

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

Durch diesen Iterator erhalten Sie auch Zugriff auf alle Plugins, die von der ServiceLoader gefunden werden.

Aus irgendeinem Grund schließt Gradle Dateien standardmäßig nicht in das Verzeichnis META-INF ein. Gibt es eine Möglichkeit, die resultierende JAR-Datei eine solche Datei enthalten zu lassen?

Die Methode metaInf habe ich bereits in der Klasse Jar gefunden. Aber ich weiß nicht gut genug, um die Lösung alleine zu finden.

22
pvorb

Sie platzieren META-INF/services/org.example.plugins.PluginService in src/main/Java, aber es handelt sich nicht um eine Quelle, sondern um eine Ressourcendatei. Daher sollte sie gemäß der Maven-Verzeichnislayoutkonvention im Ressourcenordner abgelegt werden 

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

In diesem Fall sollte alles außerhalb der Box funktionieren.

34
axtavt

Inzwischen habe ich in einer (etwas) ähnlichen Frage eine Lösung für mein Problem gefunden.

Das Hinzufügen des Folgenden zur gradle.build-Datei behebt mein Problem

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

Nun sieht die JAR-Datei wie erwartet aus

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

Hoffentlich werden sie dies in der jar-Aufgabe genauso implementieren, wie es Ameise tut. Jemand hat bereits daran gearbeitet: http://fgaliegue.blogspot.fr/2013/06/gradle-serviceloader-support.html

0
gyorgyabraham

Wenn Sie zufällig antikenbasierten Code erhalten, der nicht den Maven-Konventionen entspricht, kann das Folgende hilfreich sein.

Definieren Sie Ihre Quellensätze entsprechend der alten Struktur und fügen Sie eine Zeile wie folgt ein:

include 'META-INF/services/**'

In Ihren Quellensätzen. Dieses Muster ist allgemein und nimmt alle Ihre Meta-Inf-Dienste auf.

Vollständiges Beispiel unten.

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' }
    }
}
0
Jeremy Bunn

Hi Kann dies versuchen: https://plugins.gradle.org/plugin/com.github.harbby.gradle.serviceloader

Verwendungszweck

serviceLoader {
    serviceInterface 'org.example.plugins.PluginService'
    serviceInterface 'org.example.plugins.PluginService2'
}
0
ideal