Einführung in Bootique
1. Überblick
Bootique ist ein sehr leichtes Open-Source-JVM-Framework voncontainer-less, mit dem skalierbare Mikrodienste der nächsten Generation erstellt werden sollen. Es basiert auf dem eingebetteten Jetty-Server und unterstützt die Handler vonRESTmitjax-rs vollständig.
In diesem Artikel zeigen wir, wie Sie mitBootique eine einfache Webanwendung erstellen.
2. Maven-Abhängigkeiten
Beginnen wir mit der Verwendung vonBootique, indem wir die folgenden Abhängigkeiten zupom.xml: hinzufügen
io.bootique.jersey
bootique-jersey
compile
io.bootique
bootique-test
test
FürBootique müssen jedoch auch einigeBOM (“Bill of Material”) Importe deklariert werden. Aus diesem Grund muss der folgende Abschnitt von<dependencyManagement>inpom.xml:hinzugefügt werden
io.bootique.bom
bootique-bom
0.23
pom
import
Die neueste Version vonBootique ist inCentral Maven Repository verfügbar.
Um ein lauffähiges Glas zu erstellen, istBootique aufmaven-shade-plugin angewiesen. Aus diesem Grund müssen wir auch folgende Konfiguration hinzufügen:
org.apache.maven.plugins
maven-shade-plugin
3. Starten einer Anwendung
Der einfachste Weg, eineBootique-Anwendung zu starten, besteht darin, dieBootiqueexec()-Methode von der Hauptmethode aus aufzurufen:
public class App {
public static void main(String[] args) {
Bootique.app(args)
.autoLoadModules()
.exec();
}
}
However, this won’t start the embedded server. Sobald der obige Code ausgeführt wurde, sollte das folgende Protokoll angezeigt werden:
NAME
com.example.bootique.App
OPTIONS
-c yaml_location, --config=yaml_location
Specifies YAML config location, which can be a file path
or a URL.
-h, --help
Prints this message.
-H, --help-config
Prints information about application modules and their
configuration options.
-s, --server
Starts Jetty server.
Dies sind nichts anderes als die verfügbaren Programmargumente, die mitBootique vorgebündelt sind.
Die Namen sind selbsterklärend; Um den Server zu starten, müssen wir entweder das Argument–s oder–server übergeben, und der Server ist auf demdefault port 8080 betriebsbereit.
4. Module
Bootique Anwendungen werden mit Sammlungen von „Modulen“ erstellt. InBootique Term“A module is a Java library that contains some code”, was bedeutet, dass jeder Dienst als Modul behandelt wird. Es verwendetGoogle Guice für die Abhängigkeitsinjektion.
Um zu sehen, wie es funktioniert, erstellen wir eine Schnittstelle:
public interface HelloService {
boolean save();
}
Nun müssen wir eine Implementierung erstellen:
public class HelloServiceImpl implements HelloService {
@Override
public boolean save() {
return true;
}
}
Es gibt zwei Möglichkeiten, wie wir das Modul laden können. Die erste besteht darin, dieGuiceModule-Schnittstelle zu verwenden, und die andere besteht darin,BootiqueBQModuleProvider zu verwenden, was auch alsauto-loading bezeichnet wird.
4.1. Guice-Modul
Hier können wir dieGuice-Schnittstelle vonGuiceverwenden, um Instanzen zu binden:
public class ModuleBinder implements Module {
@Override
public void configure(Binder binder) {
binder
.bind(HelloService.class)
.to(HelloServiceImpl.class);
}
}
Sobald das Modul definiert ist, müssen wir dieses benutzerdefinierte Modul der Instanz vonBootiquezuordnen:
Bootique
.app(args)
.module(module)
.module(ModuleBinder.class)
.autoLoadModules()
.exec();
4.2. BQModuleProvider (automatisches Laden)
Hier müssen wir nur den zuvor erstellten Modulbinder mitBQModuleProvider definieren:
public class ModuleProvider implements BQModuleProvider {
@Override
public Module module() {
return new ModuleBinder();
}
}
Der Vorteil dieser Technik besteht darin, dass wir der Instanz vonBootiquekeine Modulinformationen zuordnen müssen.
Wir müssen nur eine Datei in/resources/META-INF/services/io.bootique.BQModuleProvider erstellen und den vollständigen Namen derModuleProvider einschließlich des Paketnamens schreiben, undBootique erledigt den Rest:
com.example.bootique.module.ModuleProvider
Jetzt können wir die Annotation@Injectverwenden, um die Dienstinstanzen zur Laufzeit zu verwenden:
@Inject
HelloService helloService;
Eine wichtige Sache, die hier zu beachten ist, ist, dass wir, da wir den eigenen DI-Mechanismus vonBootiqueverwenden, die Annotation vonGuice @ImplementedBynicht zum Binden der Dienstinstanzen verwenden müssen.
5. REST-Endpunkt
Es ist einfach, REST-Endpunkte mithilfe der JAX-RS-API zu erstellen:
@Path("/")
public class IndexController {
@GET
public String index() {
return "Hello, example!";
}
@POST
public String save() {
return "Data Saved!";
}
}
Um die Endpunkte der eigenenJersey-Instanz vonBootiquezuzuordnen, müssen wirJerseyModuledefinieren:
Module module = binder -> JerseyModule
.extend(binder)
.addResource(IndexController.class);
6. Aufbau
Wir können eingebaute oder benutzerdefinierte Konfigurationsinformationen in einer YAML-basierten Eigenschaftendatei bereitstellen.
Wenn wir beispielsweise die Anwendung auf einem benutzerdefinierten Port starten und einen Standard-URI-Kontext "Hallo" hinzufügen möchten, können wir die folgende YAML-Konfiguration verwenden:
jetty:
context: /hello
connector:
port: 10001
Nun müssen wir beim Starten der Anwendung den Speicherort dieser Datei im Konfigurationsparameter angeben:
--config=/home/example/bootique/config.yml
7. Protokollierung
Out-of-the-BoxBootique wird mit einembootique-logback-Modul geliefert. Um dieses Modul zu verwenden, müssen wir die folgenden Abhängigkeiten inpom.xml hinzufügen:
io.bootique.logback
bootique-logback
Dieses Modul verfügt über eineBootLogger-Schnittstelle, die wir überschreiben können, um die benutzerdefinierte Protokollierung zu implementieren:
Bootique.app(args)
.module(module)
.module(ModuleBinder.class)
.bootLogger( new BootLogger() {
@Override
public void trace( Supplier args ) {
// ...
}
@Override
public void stdout( String args ) {
// ...
}
@Override
public void stderr( String args, Throwable thw ) {
// ...
}
@Override
public void stderr( String args ) {
// ...
}
}).autoLoadModules().exec();
Außerdem können wir Informationen zur Protokollierungskonfiguration in der Dateiconfig.yamldefinieren:
log:
level: warn
appenders:
- type: file
logFormat: '%c{20}: %m%n'
file: /path/to/logging/dir/logger.log
8. Testen
Zum Testen wirdBootique mit dem Modulbootique-test geliefert. Es gibt zwei Möglichkeiten, wie wir die Anwendung vonBootiquetesten können.
Der erste Ansatz ist der Ansatz von‘foreground', bei dem alle Testfälle auf dem Haupttest-Thread ausgeführt werden.
Der andere ist der Ansatz von‘background', bei dem die Testfälle in einem isolierten Thread-Pool ausgeführt werden.
Die Vordergrundumgebung kann mitBQTestFactory initialisiert werden:
@Rule
public BQTestFactory bqTestFactory = new BQTestFactory();
Die Hintergrundumgebung kann mitBQDaemonTestFactory initialisiert werden:
@Rule
public BQDaemonTestFactory bqDaemonTestFactory = new BQDaemonTestFactory();
Sobald die Umgebungsfabrik fertig ist, können wir einfache Testfälle schreiben, um die Dienste zu testen:
@Test
public void givenService_expectBoolen() {
BQRuntime runtime = bqTestFactory
.app("--server").autoLoadModules()
.createRuntime();
HelloService service = runtime.getInstance( HelloService.class );
assertEquals( true, service.save() );
}
9. Fazit
In diesem Artikel haben wir gezeigt, wie eine Anwendung mit den Kernmodulen vonBootiqueerstellt wird. Es sind mehrere andereBootique-Module verfügbar, z. B.bootique-jooq,bootique-kotlin,bootique-job usw. Die vollständige Liste der verfügbaren Module ist inhere verfügbar.
Wie immer ist der vollständige Quellcodeover on GitHub. verfügbar