Ratpack Google Guice Integration

Ratpack Google Guice Integration

1. Überblick

In unseren früherenarticle haben wir gezeigt, wie das Erstellen skalierbarer Anwendungen mit Ratpack aussieht.

In diesem Tutorial werden wir weiter diskutieren, wieGoogle Guice mitRatpack als Abhängigkeitsmanagement-Engine verwendet werden.

2. Warum Google Guice?

Google Guice ist ein Open-Source-Software-Framework für die PlattformJava, das vonGoogle unterApache License veröffentlicht wird.

Es ist ein extrem leichtes Abhängigkeitsverwaltungsmodul, das einfach zu konfigurieren ist. Darüber hinaus erlaubt es nur das Einfügen von Abhängigkeiten auf Konstruktorebene, um die Benutzerfreundlichkeit zu verbessern.

Weitere Details zuGuice finden Sie unterhere.

3. Verwenden von Guice mit Ratpack

3.1. Maven-Abhängigkeit

Ratpack bietet erstklassige Unterstützung für die Abhängigkeit vonGuice. Daher müssen wir fürGuice;, die bereits mitRatpack vorgefertigt sind, keine externe Abhängigkeit manuell hinzufügen. Weitere Einzelheiten zur Unterstützung vonRatpackGuicefinden Sie unterhere.

Daher müssen wir nur die folgende Abhängigkeit von KernRatpackinpom.xml hinzufügen:


    io.ratpack
    ratpack-core
    1.4.5

Sie können die neueste Version aufMavenCentral überprüfen.

3.2. Gebäudetechnikmodule

Sobald die Konfiguration vonMavenabgeschlossen ist, erstellen wir einen Dienst und verwenden in unserem Beispiel hier eine einfache Abhängigkeitsinjektion.

Erstellen wir eine Serviceschnittstelle und eine Serviceklasse:

public interface DataPumpService {
    String generate();
}

Dies ist die Serviceschnittstelle, die als Injektor fungiert. Jetzt müssen wir die Serviceklasse erstellen, die sie implementiert und die Servicemethodegenerate(): definiert

public class DataPumpServiceImpl implements DataPumpService {

    @Override
    public String generate() {
        return UUID.randomUUID().toString();
    }

}

Ein wichtiger Punkt, der hier zu beachten ist, ist, dasswe don’t need to use Guice‘s @ImplementedBy or @Inject annotation to manually inject the service class. verwendet wird, da wir das ModulRatpack’s Guice verwenden

3.3. Abhängigkeitsmanagement

Es gibt zwei Möglichkeiten, das Abhängigkeitsmanagement mitGoogle Guice durchzuführen.

Die erste besteht darin,GuiceAbstractModule zu verwenden, und die andere darin, dieinstance binding-Mechanismusmethode von Guice zu verwenden:

public class DependencyModule extends AbstractModule {

    @Override
    public void configure() {
        bind(DataPumpService.class).to(DataPumpServiceImpl.class)
          .in(Scopes.SINGLETON);
    }

}

Einige Punkte, die Sie hier beachten sollten:

  • Durch die Erweiterung vonAbstractModule überschreiben wir die Standardmethodeconfigure()

  • Wir ordnen die Klasse vonDataPumpServiceImplder Schnittstelle vonDataPumpServicezu, die die zuvor erstellte Serviceschicht ist

  • Wir haben die Abhängigkeit auch alsSingletonWeise injiziert.

3.4. Integration mit der vorhandenen Anwendung

Da die Konfiguration des Abhängigkeitsmanagements fertig ist, integrieren wir sie jetzt:

public class Application {

    public static void main(String[] args) throws Exception {

      RatpackServer
          .start(server -> server.registry(Guice
            .registry(bindings -> bindings.module(DependencyModule.class)))
            .handlers(chain -> chain.get("randomString", ctx -> {
                DataPumpService dataPumpService = ctx.get(DataPumpService.class);
                ctx.render(dataPumpService.generate().length());
            })));
    }
}

Hier haben wir mitregistry() die KlasseDependencyModule gebunden, dieAbstractModule erweitert. Das ModulRatpack’s Guiceerledigt intern den Rest des Bedarfs und fügt den Dienst in die AnwendungContext ein.

Da es inapplication-context, verfügbar ist, können wir die Dienstinstanz jetzt von einer beliebigen Stelle in der Anwendung abrufen. Hier haben wir die Instanz vonDataPumpServiceaus dem aktuellen Kontext abgerufen und die URL von/randomStringmit dergenerate()-Methode des Dienstes zugeordnet.

Wenn die URL von/randomStringgetroffen wird, werden daher zufällige Zeichenfolgenfragmente zurückgegeben.

3.5. Laufzeitinstanzbindung

Wie bereits erwähnt, verwenden wir jetzt den Instanzbindungsmechanismus von Guice, um das Abhängigkeitsmanagement zur Laufzeit durchzuführen. Es ist fast das gleiche wie bei der vorherigen Technik, abgesehen von der Verwendung derbindInstance()-Methode von Guice anstelle vonAbstractModule, um die Abhängigkeit einzufügen:

public class Application {

    public static void main(String[] args) throws Exception {

      RatpackServer.start(server -> server
        .registry(Guice.registry(bindings -> bindings
        .bindInstance(DataPumpService.class, new DataPumpServiceImpl())))
        .handlers(chain -> chain.get("randomString", ctx -> {
            DataPumpService dataPumpService = ctx.get(DataPumpService.class);
            ctx.render(dataPumpService.generate());
        })));
    }
}

Hier führen wir unter Verwendung vonbindInstance() eine Instanzbindung durch, d. H. Injizieren derDataPumpService-Schnittstelle in dieDataPumpServiceImpl-Klasse.

Auf diese Weise können wir die Dienstinstanz wie im vorherigen Beispiel inapplication-context einfügen.

Obwohl wir eine der beiden Techniken für das Abhängigkeitsmanagement verwenden können, ist es immer besser,AbstractModule zu verwenden, da das Abhängigkeitsverwaltungsmodul vollständig vom Anwendungscode getrennt wird. Auf diese Weise wird der Code in Zukunft viel sauberer und einfacher zu warten sein.

3.6. Werksbindung

Es gibt auch eine weitere Möglichkeit für das Abhängigkeitsmanagement,factory binding. Es hängt nicht direkt mit der Implementierung vonGuice’szusammen, aber dies kann auch parallel zuGuicefunktionieren.

Eine Factory-Klasse entkoppelt den Client von der Implementierung. Eine einfache Factory verwendet statische Methoden, um Scheinimplementierungen für Schnittstellen abzurufen und festzulegen.

Wir können bereits erstellte Serviceklassen verwenden, um Factory-Bindungen zu aktivieren. Wir müssen nur eine Factory-Klasse wieDependencyModule (die die KlasseGuice’s AbstractModule erweitert) erstellen und die Instanzen über statische Methoden binden:

public class ServiceFactory {

    private static DataPumpService instance;

    public static void setInstance(DataPumpService dataPumpService) {
        instance = dataPumpService;
    }

    public static DataPumpService getInstance() {
        if (instance == null) {
            return new DataPumpServiceImpl();
        }
        return instance;
    }
}

Here, we’re statically injecting the service interface in the factory class. Daher wäre zu einem Zeitpunkt nur eine Instanz dieser Schnittstelle für diese Factory-Klasse verfügbar. Anschließend haben wir normalegetter/setter-Methoden zum Festlegen und Abrufen der Dienstinstanz erstellt.

Hierbei ist zu beachten, dass wir in dergetter-Methode eine explizite Überprüfung durchgeführt haben, um sicherzustellen, dass nur eine einzige Instanz des Dienstes vorhanden ist oder nicht. Wenn es null ist, haben nur wir die Instanz der Implementierungsdienstklasse erstellt und dieselbe zurückgegeben.

Danach können wir diese Factory-Instanz in der Anwendungskette verwenden:

.get("factory", ctx -> ctx.render(ServiceFactory.getInstance().generate()))

4. Testen

Wir werdenRatpackMainClassApplicationUnderTest verwenden, um unsere Anwendung mit Hilfe des internen JUnit-Testframeworks vonRatpackzu testen. Wir müssen die notwendige Abhängigkeit (ratpack-test) dafür hinzufügen.

Da der URL-Inhalt dynamisch ist, können wir ihn beim Schreiben des Testfalls nicht vorhersagen. Daher würden wir die Inhaltslänge des URL-Endpunkts von/randomStringim Testfall anpassen:

@RunWith(JUnit4.class)
public class ApplicationTest {

    MainClassApplicationUnderTest appUnderTest
      = new MainClassApplicationUnderTest(Application.class);

    @Test
    public void givenStaticUrl_getDynamicText() {
        assertEquals(21, appUnderTest.getHttpClient()
          .getText("/randomString").length());
    }

    @After
    public void shutdown() {
        appUnderTest.close();
    }
}

5. Fazit

In diesem kurzen Artikel haben wir gezeigt, wieGoogle Guice mitRatpack verwendet werden.

Wie immer ist der vollständige Quellcodeover on GitHub verfügbar.