Blog

MultiSPI - Nutzung der Schnittstellen von Dienstanbietern im Jahr 2011

Andrew Phillips

Aktualisiert Oktober 22, 2025
3 Minuten

Die Implementierung eines Java SPI ist nicht gerade ein Erlebnis des Jahres 20111. Eine Textdatei mit dem richtigen Namen in META-INF/services zu erstellen, dafür zu sorgen, dass sie korrekt verpackt ist, und daran zu denken, sie auf dem neuesten Stand zu halten, wenn Sie ein Refactoring vornehmen, ist so lästig und fehleranfällig, dass es zumindest ein paar Hilfsprogramme gibt, die diese Aufgabe erleichtern sollen.Bei XebiaLabs sind wir jedoch nicht nur die Implementierer unserer Plugin-SPI. Wir schreiben auch die Deployment-Engine, die diese Plugins nutzt. Und leider gibt es nicht viel, was Ihnen beim Lesen, Laden und Überprüfen von Diensten hilft. Daher MultiSPI.

Was ist mit ServiceLoader?

Offensichtlich haben die Ingenieure von SunOracle- als prominente SPI-Konsumenten - diese Frustration geteilt. In Java 6 führten sie ServiceLoader ein, um zumindest die Nutzung von "Vanilla" SPI zu vereinfachen. MultiSPI ist jedoch nicht nur eine vollständig kompatible Alternative für diejenigen, die noch mit Java 5 arbeiten. Es unterstützt auch eine Reihe gängiger zusätzlicher Anwendungsfälle:

  1. Überprüfung der Liste der Klassennamen, bevor sie geladen werden, z.B. um einige Elemente zu entfernen oder zu ersetzen (z.B. benutzerdefinierte Überschreibungen), um verschiedene Klassenlader für verschiedene Pakete zu verwenden (z.B. OSGi) usw.
  2. Inspektion der Klassen vor ihrer Instanziierung, z. B. um zu prüfen, ob Annotationen oder implementierte Schnittstellen erforderlich sind, um die Erstellung von Instanzen zu verzögern usw.
  3. Verwendung von Nicht-Vanilla-Instanzierungsstrategien, zum Beispiel zur Unterstützung von Factory-Methoden oder in Verbindung mit Dependency Injection usw.

Erbringung von Dienstleistungen 2011

Noch wichtiger ist jedoch, dass MultiSPI nicht nur das Lesen von Service-Implementierungen aus META-INF/Services-Dateien unterstützt. Denn seien wir ehrlich, wenn Sie heute einen Komponenten-Provider-Mechanismus entwerfen, wird dieser wahrscheinlich nicht auf der Vanilla-SPI-Spezifikation basieren.MultiSPI unterstützt das Scannen von Annotationen und Manifesten, aber Sie können Provider für jedes Schema Ihrer Wahl hinzufügen, seien es XML-Deskriptoren, Systemeigenschaften, Umgebungsvariablen oder was auch immer. Natürlich können Sie auch verschiedene Anbieter kombinieren, was besonders nützlich ist, wenn Sie (wie in unserem Fall mit Labs) mehrere Versionen eines SPI unterstützen.

SPIs und Injektion von Abhängigkeiten

Letztendlich sind SPIs natürlich nur Service-Fabriken, und wenn Sie in einem Dependency-Injection-Kontext arbeiten, wollen Sie wahrscheinlich nicht explizit einen SPI-Loader aufrufen, sondern nur, dass die resultierenden Services für die Injektion in Ihre Geschäftslogik "verfügbar" sind. In der Tat hat Spring in Version 2.5 eine ServiceLoader-gestützte Fabrik hinzugefügt, und natürlich können Sie dasselbe mit MultiSPI tun, egal ob Sie die Namen der Implementierungsklassen, die Klassen oder die Instanzen selbst wollen. Es gibt Beispiele für Spring und Guice. Hier ist zum Beispiel der Spring-Kontext, der eine Reihe von Klassennamen, Klassen und Instanzen vorbereitet:

[xml]
<bean id="multiSpi" class="com.qrmedia.commons.multispi.MultiSpi">
<constructor-arg>
<set>
<bean class="com.qrmedia.commons.multispi.provider.MetaInfServicesProvider" />
<bean class="com.qrmedia.commons.multispi.provider.AnnotationScanningProvider">
<constructor-arg value="uk.gov.mi6.LicenseToKill" />
<constructor-arg value="uk.gov" />
</bean>
</set>
</constructor-arg>
</bean>
<bean id="agentNames" factory-bean="multiSpi" factory-method="findImplementationNames">
<constructor-arg value="uk.gov.mi6.Agent" />
</bean>
<bean id="agentClasses" factory-bean="multiSpi" factory-method="findImplementations">
<constructor-arg value="uk.gov.mi6.Agent" />
</bean>
<bean id="agents" factory-bean="multiSpi" factory-method="loadImplementations">
<constructor-arg value="uk.gov.mi6.Agent" />
</bean>
[/xml]

Natürlich können Sie viele verschiedene MultiSpi-Instanzen mit unterschiedlichen Provider-Konfigurationen gleichzeitig in Ihrer Anwendung verwenden.

MultiSPI verwenden

Um MultiSPI zu verwenden, fügen Sie einfach die folgenden Abhängigkeiten und Repositories zu Ihrem POM hinzu:

[xml]
<dependency>
<groupId>com.qrmedia.commons</groupId>
<artifactId>multi-spi</artifactId>
<version>1.0-SNAPSHOT</version>
</dependency>
<repository>
<id>qrmedia-releases</id>
<url> https://aphillips.googlecode.com/svn/maven-repository/releases </url>
<releases>
<enabled>true</enabled>
</releases>
<snapshots>
<enabled>false</enabled>
</snapshots>
</repository>
<repository>
<id>qrmedia-snapshots</id>
<url> https://aphillips.googlecode.com/svn/maven-repository/snapshots </url>
<releases>
<enabled>false</enabled>
</releases>
<snapshots>
<enabled>true</enabled>
</snapshots>
</repository>
[/xml]

Wenn Sie glauben, dass Sie auf widersprüchliche Abhängigkeiten stoßen könnten und etwas wollen, das einfach funktioniert, ohne sich mit <excludes> auseinandersetzen zu müssen, können Sie verwenden:

[xml]
<dependency>
<groupId>com.qrmedia.commons</groupId>
<artifactId>multi-spi</artifactId>
<version>1.0-SNAPSHOT</version>
<classifier>jar-with-dependencies</classifier>
</dependency>
[/xml]

statt. Die Maven-Site und die Projektberichte finden Sie unter aphillips.googlecode.com/svn/maven-sites/multi-spi/1.0-SNAPSHOT/project-info.html.

Fußnoten
  1. Ich überlasse die Debatte darüber, ob selbst das Schreiben von Java noch als Erfahrung des Jahres 2011 angesehen werden kann, den Fans von Clojure, Scala usw. ;-)

Verfasst von

Andrew Phillips

Contact

Let’s discuss how we can support your journey.