Einführung in das Micronaut Framework

1. Was ist Mikronaut?

Micronaut ist ein JVM-basiertes Framework zum Erstellen leichter, modularer Anwendungen. Micronaut wurde von OCI entwickelt, dem gleichen Unternehmen, das Grails entwickelt hat. Es ist das neueste Framework, mit dem die Erstellung von Microservices schnell und einfach durchgeführt werden kann .

Während Micronaut einige Funktionen enthält, die bestehenden Frameworks wie Spring ähneln, verfügt es auch über einige neue Funktionen, die es von anderen abheben. Mit der Unterstützung von Java, Groovy und Kotlin bietet es eine Vielzahl von Möglichkeiten zum Erstellen von Anwendungen.

2. Hauptmerkmale

Eine der aufregendsten Funktionen von Micronaut ist der Mechanismus zur Injektion der Abhängigkeit von der Kompilierungszeit. Die meisten Frameworks verwenden Reflection und Proxys, um zur Laufzeit eine Abhängigkeitsinjektion durchzuführen. Micronaut erstellt jedoch seine Abhängigkeitsinjektionsdaten zur Kompilierungszeit. Das Ergebnis ist ein schnellerer Start der Anwendung und ein geringerer Speicherbedarf.

Ein weiteres Merkmal ist die erstklassige Unterstützung für reaktive Programmierung sowohl für Clients als auch für Server. Die Auswahl einer bestimmten reaktiven Implementierung bleibt dem Entwickler überlassen, da sowohl RxJava als auch Project Reactor unterstützt werden.

Micronaut verfügt außerdem über mehrere Funktionen, die es zu einem hervorragenden Framework für die Entwicklung von Cloud-nativen Anwendungen machen. Es unterstützt mehrere Service Discovery-Tools wie Eureka und Consul und funktioniert auch mit verschiedenen verteilten Tracing-Systemen wie Zipkin und Jaeger.

Es bietet auch Unterstützung für das Erstellen von AWS-Lambda-Funktionen, wodurch das Erstellen von Anwendungen ohne Server vereinfacht wird.

3. Erste Schritte

Der einfachste Weg, um loszulegen, ist die Verwendung von SDKMAN:

> sdk install micronaut 1.0.0.RC2

Dadurch werden alle Binärdateien installiert, die zum Erstellen, Testen und Bereitstellen von Micronaut-Anwendungen erforderlich sind. Es bietet auch das Micronaut CLI-Tool, mit dem wir problemlos neue Projekte starten können.

Die binären Artefakte sind auch auf Sonatype und GitHub verfügbar.

In den folgenden Abschnitten werden einige Funktionen des Frameworks vorgestellt.

4. Abhängigkeitsinjektion

Wie bereits erwähnt, übernimmt Micronaut die Abhängigkeitsinjektion zur Kompilierungszeit, was sich von den meisten IoC-Containern unterscheidet.

JSR-330-Annotationen werden jedoch weiterhin vollständig unterstützt, sodass die Arbeit mit Beans anderen IoC-Frameworks ähnelt.

Um eine Bean automatisch in unseren Code zu verdrahten, verwenden wir @Inject:

@Inject private EmployeeService service;

Die Annotation @Inject funktioniert genau wie @Autowired und kann für Felder, Methoden, Konstruktoren und Parameter verwendet werden.

Standardmäßig sind alle Beans als Prototyp festgelegt. Mit @Singleton können wir schnell Singleton-Beans erstellen. Wenn mehrere Klassen dieselbe Bean-Schnittstelle implementieren, können sie mit @Primary dekonfliktiert werden:

@Primary @Singleton public class BlueCar implements Car {}

Die Annotation @Requires kann verwendet werden, wenn Beans optional sind, oder um das automatische Verdrahten nur durchzuführen, wenn bestimmte Bedingungen erfüllt sind.

In dieser Hinsicht verhält es sich ähnlich wie die Spring Boot @ Conditional- Annotationen:

@Singleton @Requires(beans = DataSource.class) @Requires(property = "enabled") @Requires(missingBeans = EmployeeService) @Requires(sdk = Sdk.JAVA, value = "1.8") public class JdbcEmployeeService implements EmployeeService {}

5. Erstellen eines HTTP-Servers

Schauen wir uns nun die Erstellung einer einfachen HTTP-Serveranwendung an. Zu Beginn erstellen wir mit SDKMAN ein Projekt:

> mn create-app hello-world-server -build maven

Dadurch wird mit Maven ein neues Java-Projekt in einem Verzeichnis namens hello-world-server erstellt. In diesem Verzeichnis finden Sie unseren Hauptanwendungsquellcode, die Maven POM-Datei und andere Unterstützungsdateien für das Projekt.

Die Standardanwendung, die sehr einfach ist:

public class ServerApplication { public static void main(String[] args) { Micronaut.run(ServerApplication.class); } }

5.1. HTTP blockieren

Diese Anwendung allein macht nicht viel. Fügen wir einen Controller mit zwei Endpunkten hinzu. Beide geben eine Begrüßung zurück, aber einer verwendet das GET- HTTP-Verb und der andere verwendet POST:

@Controller("/greet") public class GreetController { @Inject private GreetingService greetingService; @Get("/{name}") public String greet(String name) { return greetingService.getGreeting() + name; } @Post(value = "/{name}", consumes = MediaType.TEXT_PLAIN) public String setGreeting(@Body String name) { return greetingService.getGreeting() + name; } }

5.2. Reaktives IO

Standardmäßig implementiert Micronaut diese Endpunkte mithilfe herkömmlicher blockierender E / A. Allerdings können wir schnell implementieren nicht blockierenden Endpunkte , indem lediglich den Rückgabetyp zu jeder reaktiven nicht-blockierenden Art zu ändern .

Mit RxJava können wir beispielsweise Observable verwenden . Ebenso können wir bei Verwendung von Reactor Mono- oder Flux -Datentypen zurückgeben:

@Get("/{name}") public Mono greet(String name) { return Mono.just(greetingService.getGreeting() + name); }

Sowohl für blockierende als auch für nicht blockierende Endpunkte ist Netty der zugrunde liegende Server, der zur Verarbeitung von HTTP-Anforderungen verwendet wird.

Normalerweise werden die Anforderungen im Haupt-E / A-Thread-Pool verarbeitet, der beim Start erstellt wird, sodass sie blockiert werden.

Wenn jedoch ein nicht blockierender Datentyp von einem Controller-Endpunkt zurückgegeben wird, verwendet Micronaut den Netty-Ereignisschleifenthread, wodurch die gesamte Anforderung nicht blockiert wird.

6. Erstellen eines HTTP-Clients

Erstellen wir nun einen Client, der die soeben erstellten Endpunkte verwendet. Micronaut bietet zwei Möglichkeiten zum Erstellen von HTTP-Clients:

  • Ein deklarativer HTTP-Client
  • Ein programmatischer HTTP-Client

6.1 Deklarativer HTTP-Client

Der erste und schnellste Weg zum Erstellen ist die Verwendung eines deklarativen Ansatzes:

@Client("/greet") public interface GreetingClient { @Get("/{name}") String greet(String name); }

Beachten Sie, dass wir keinen Code implementieren, um unseren Service aufzurufen . Stattdessen versteht Micronaut, wie der Dienst anhand der von uns bereitgestellten Methodensignatur und Anmerkungen aufgerufen wird.

To test this client, we can create a JUnit test that uses the embedded server API to run an embedded instance of our server:

public class GreetingClientTest { private EmbeddedServer server; private GreetingClient client; @Before public void setup() { server = ApplicationContext.run(EmbeddedServer.class); client = server.getApplicationContext().getBean(GreetingClient.class); } @After public void cleanup() { server.stop(); } @Test public void testGreeting() { assertEquals(client.greet("Mike"), "Hello Mike"); } }

6.2. Programmatic HTTP Client

We also have the option of writing a more traditional client if we need more control over its behavior and implementation:

@Singleton public class ConcreteGreetingClient { private RxHttpClient httpClient; public ConcreteGreetingClient(@Client("/") RxHttpClient httpClient) { this.httpClient = httpClient; } public String greet(String name) { HttpRequest req = HttpRequest.GET("/greet/" + name); return httpClient.retrieve(req).blockingFirst(); } public Single greetAsync(String name) { HttpRequest req = HttpRequest.GET("/async/greet/" + name); return httpClient.retrieve(req).first("An error as occurred"); } }

The default HTTP client uses RxJava, so can easily work with blocking or non-blocking calls.

7. Micronaut CLI

We've already seen the Micronaut CLI tool in action above when we used it to create our sample project.

In our case, we created a standalone application, but it has several other capabilities as well.

7.1. Federation Projects

In Micronaut, a federation is just a group of standalone applications that live under the same directory. By using federations, we can easily manage them together and ensure they get the same defaults and settings.

When we use the CLI tool to generate a federation, it takes all the same arguments as the create-app command. It will create a top-level project structure, and each standalone app will be created in its sub-directory from there.

7.2. Features

When creating a standalone application or federation, we can decide which features our app needs. This helps ensure the minimal set of dependencies is included in the project.

We specify features using the -features argument and supplying a comma-separated list of feature names.

We can find a list of available features by running the following command:

> mn profile-info service Provided Features: -------------------- * annotation-api - Adds Java annotation API * config-consul - Adds support for Distributed Configuration with Consul * discovery-consul - Adds support for Service Discovery with Consul * discovery-eureka - Adds support for Service Discovery with Eureka * groovy - Creates a Groovy application [...] More features available

7.3. Existing Projects

We can also use the CLI tool to modify existing projects. Enabling us to create beans, clients, controllers, and more. When we run the mn command from inside an existing project, we'll have a new set of commands available:

> mn help | Command Name Command Description ----------------------------------------------- create-bean Creates a singleton bean create-client Creates a client interface create-controller Creates a controller and associated test create-job Creates a job with scheduled method

8. Conclusion

In this brief introduction to Micronaut, we've seen how easy it is to build both blocking and non-blocking HTTP servers and clients. Also, we explored some features of its CLI.

But this is just a small taste of the features it offers. There is also full support for serverless functions, service discovery, distributed tracing, monitoring and metrics, a distributed configuration, and much more.

And while many of its features are derived from existing frameworks such as Grails and Spring, it also has plenty of unique features that help it stand out on its own.

Wie immer finden wir den obigen Beispielcode in unserem GitHub-Repo.