ktor - JAX https://jax.de/tag/ktor/ Java, Architecture & Software Innovation Fri, 18 Oct 2024 13:04:11 +0000 de-DE hourly 1 https://wordpress.org/?v=6.5.2 Mit Ktor und Spring Boot Server- und Clientanwendungen entwickeln https://jax.de/blog/mit-ktor-und-spring-boot-server-und-clientanwendungen-entwickeln/ Wed, 15 Mar 2023 08:17:46 +0000 https://jax.de/?p=88428 Wie können mit Spring Boot und Ktor in Kotlin Server- und Clientanwendungen entwickelt werden? Dieser Artikel begleitet durch das Zusammenspiel von Spring Boot und Ktor. Kotlin eignet sich hervorragend, um Non-blocking-Server- und -Clientanwendungen zu entwickeln. Dafür gibt es mit Ktor sogar ein spezielles Framework. Doch auch der Platzhirsch für Anwendungen im JVM-Ökosystem, Spring Boot, muss sich hier nicht verstecken, sondern kann hervorragend im Zusammenspiel mit Kotlin verwendet werden.

The post Mit Ktor und Spring Boot Server- und Clientanwendungen entwickeln appeared first on JAX.

]]>
Das Kotlin-Ökosystem ist umfangreich. Entwickler JetBrains arbeitet nicht nur an der Sprache selbst, sondern veröffentlicht diverse Frameworks, die speziell für Kotlin entwickelt werden. Ktor [1] ist ein solches Framework, das die Entwicklung von Server- und Clientanwendungen in Kotlin ermöglicht. Ktor sticht vor allem dadurch hervor, dass es auch für native Builds mit Kotlin Native geeignet ist. Das zweite Hauptargument für Ktor ist, dass es ausschließlich non-blocking arbeitet und daher asynchrone Verarbeitung der Standard ist.

Ktor-Server

Der Anfang einer Entwicklung mit Ktor ist dabei so einfach wie bei den meisten anderen aktuellen Frameworks im Umfeld der Java Virtual Machine (JVM). Die Entwickler bieten einen Starter [2], mit dessen Hilfe ein Maven- oder Gradle-Projekt erstellt werden kann. Hierbei können der verwendete Webserver und benötigte Plug-ins direkt ausgewählt werden. Abhängigkeiten zwischen den verschiedenen Komponenten löst der Projektgenerator auf und fügt notwendige, abhängige Plug-ins hinzu, sodass ein lauffähiges Projekt entsteht.

Für ein einfaches „Hello World“-Beispiel verwenden wir Netty als Webserver und die Plug-ins Routing und kotlinx.serialization, um zum einen Routing anhand von Pfaden zu ermöglichen und zum anderen das Kotlin-eigene Serialisierungsmodul zu nutzen. Letzteres fügt als zusätzliches Plug-in noch ContentNegotiation hinzu, das es Ktor ermöglicht, ContentType- und Accept-Header auszuwerten und darauf zu reagieren. Ktor bietet weitere Plug-ins, die für fortgeschrittene Anwendungsfälle geeignet sind, wie zum Beispiel Authentifizierung, Session-Management, LDAP-Anbindung, Template-Engines und WebSocket-Unterstützung, um nur einige Beispiele zu nennen. Die vollständige „Hello World“-Anwendung zeigt Listing 1.

import io.ktor.server.engine.*
import io.ktor.server.netty.*
import io.ktor.serialization.kotlinx.json.*
import io.ktor.server.application.*
import io.ktor.server.plugins.contentnegotiation.*
import io.ktor.server.response.*
import io.ktor.server.routing.*
 
fun main() {
  embeddedServer(Netty, port = 8080, host = "0.0.0.0") {
    install(ContentNegotiation) {
      json()
    }
    configureRouting()
  }.start(wait = true)
}
 
fun Application.configureRouting() {
  routing {
    route("/hello") {
      get("/{name?}") {
        val name = call.parameters["name"] ?: "World"
 
        call.respond("Hello $name!")
      }
    }
  }
}

In der main-Methode wird über die Methode embeddedServer die Ktor-Anwendung erzeugt und mit der start-Methode gestartet. Der Parameter wait = true gibt dabei an, dass der Hauptanwendungs-Thread blockiert werden soll, die Anwendung also so lange läuft, bis sie beendet wird.

Stay tuned

Regelmäßig News zur Konferenz und der Java-Community erhalten

 

Über die embeddedServer-Methode werden die Server-Engine, der Port und auch die Ktor-Plug-ins konfiguriert. Das ContentNegotiation-Plug-in wird zur Anwendung hinzugefügt und für JSON konfiguriert. Die Konfiguration des Routings könnte ebenso inline erfolgen, wird hier aber in eine Extension Function ausgelagert. Generell kann das Routing in mehrere Extension Functions ausgelagert werden und so eine Gruppierung nach Funktionalität, Pfad oder Ähnlichem erfolgen.

Das Routing selbst geschieht über die Ktor-DSL. Das Beispiel aus Listing 1 konfiguriert die Route / hello/$name, wobei $name ein optionaler Path-Parameter (erkennbar am ?) ist. Mit call.parameters kann auf die Request-Parameter zugegriffen werden, mit call.respond wird die Serverantwort geschrieben. Ein Aufruf von /hello gibt „Hello World!“ zurück, ein Aufruf von / hello/Ktor gibt „Hello Ktor!“ zurück.

Damit ist eine erste, sehr einfache Ktor-Anwendung fertig. Der Non-blocking-Aspekt von Ktor scheint in diesem simplen Beispiel verborgen zu sein, ist aber tatsächlich schon vorhanden. Die Signaturen der Methoden call.parameters und call.respond haben jeweils das Schlüsselwort suspend in ihrer Deklaration, was bedeutet, dass sie auf besondere Weise ausgeführt werden. Zunächst jedoch ein Blick darauf, wofür Non-Blocking relevant ist.

Non-blocking Serveranwendungen

Webserver stellen eine Menge Threads zur Verfügung. Jeder dieser Threads verarbeitet dabei einen Request nach dem anderen. Die Anzahl paralleler Requests ist also durch die Zahl der Threads limitiert. Komplexere Anwendungen können jedoch eine Anfrage oftmals nicht ohne externe Kommunikation verarbeiten. Externe Zugriffe sind nötig, zum Beispiel auf eine Datenbank, das Dateisystem oder auf externe HTTP-APIs. Beim Warten auf diese externen Zugriffe wird der Webserver-Thread blockiert. Der Skalierung der Webserver-Threads sind dabei schnell Grenzen gesetzt, da Threads generell ressourcenintensiv sind und der Bedarf an Arbeitsspeicher schnell ansteigt. Optimierungen im Code selbst, die zum Beispiel Zugriffe auf Datenbanken oder externe APIs via Threads parallelisieren, bringen nicht nur das Ressourcenproblem mit, sondern erhöhen zusätzlich die Komplexität des Codes signifikant, da die Threads synchronisiert werden müssen. Auch wird dabei nicht das Problem gelöst, dass der Webserver-Thread blockiert werden muss, um auf das Beenden aller gestarteten Threads zu warten.

Ein häufig von Frameworks angebotener Lösungsansatz hierfür ist Reactive Programming. Dabei wird durch ein entsprechendes Framework, wie zum Beispiel Project Reactor [3], das Scheduling übernommen. Statt zu blockieren, wird dabei der Thread genutzt, um weitere Anfragen zu verarbeiten. So ist ein höherer Parallelisierungsgrad möglich, ohne zusätzliche Threads zu benötigen. Mit Reactive Programming ist jedoch eine steile Lernkurve verbunden. Das Programmiermodell unterscheidet sich grundlegend von der imperativen Programmierung, da es für fast jedes Problem spezielle Operatoren gibt.

Ktor nutzt für die parallelisierte Verarbeitung einen anderen Ansatz, der es erlaubt, den imperativen Programmierstil beizubehalten: Kotlin Coroutines.

Kotlin Coroutines

Koroutinen [4] sind spezielle Funktionen, die unterbrochen und wieder fortgesetzt werden können. Kotlin unterstützt Koroutinen über eine Core Library namens Kotlin Coroutines [5]. Den Kern von Kotlin Coroutines bilden suspendierbare Funktionen, die mit dem Schlüsselwort suspend fun deklariert werden. Diese können nur innerhalb eines Coroutine Scopes ausgeführt werden. Das einfache Beispiel in Listing 2 startet einen Coroutine Scope mit der Methode runBlocking. Durch diese Methode wird der Hauptthread pausiert, bis alle gestarteten Koroutinen abgeschlossen sind. Mittels launch werden innerhalb einer for-Schleife 1 000 000 Koroutinen gestartet, die jeweils zehn Sekunden pausieren und anschließend einen Wert ausgeben. Die Ausführung zeigt, dass nach einer initialen Verzögerung von zehn Sekunden alle Zahlen kurz nacheinander ausgegeben werden. Die Ausführung – und damit auch die zehn Sekunden Wartezeit – wird also parallelisiert.

fun main() {
  runBlocking {
    for (i in 0..1_000_000) {
      launch { printIn10Seconds(i) }
    }
  }
}
 
suspend fun printIn10Seconds(value: Int) {
  delay(10_000)
  println(value)
}

Listing 3 zeigt denselben Code mit Threads. Dieser läuft (auf durchschnittlicher Hardware) spürbar weniger performant, da er deutlich mehr Systemressourcen benötigt.

fun main() {
  val threads = mutableListOf<Thread>()
  for (i in 0..1_000_000) {
    val thread = Thread { printIn10Seconds(i) }
    threads.add(thread)
    thread.start()
  }
  threads.forEach { it.join() }
}
 
fun printIn10Seconds(value: Int) {
  Thread.sleep(10_000)
  println(value)
}

suspend funs können nur innerhalb eines Coroutine Scopes ausgeführt werden. Das bedeutet in unserem initialen Ktor-Beispiel, das bereits zwei suspend funs benutzt hat, dass Ktor den gesamten Code in einem Coroutine Scope ausführt. Konkret startet Ktor für jeden Request eine eigene Koroutine und ermöglicht somit eine deutlich höhere Parallelisierung, ohne dass der Entwickler sich umstellen oder irgendetwas beachten muss. Jedoch bleibt ihm die Flexibilität erhalten, selbst suspendierbare Funktionen aufzurufen.

NEUES AUS DER JAVA-ENTERPRISE-WELT

Serverside Java-Track entdecken

 

Ktor-Client

Ktor bietet nicht nur eine einfache Möglichkeit, eine non-blocking Serveranwendung zu implementieren. Auch non-blocking Clientanwendungen sind möglich. Dass hierbei auch die Clients konsequent mit Hilfe von Coroutines implementiert werden, bringt auch hier den Vorteil, dass der Thread, der die Requests ausführt, nicht blockiert werden muss, während auf den Server gewartet wird, sondern weiterverwendet werden kann.

Als Beispiel wollen wir unsere „Hello World“-Anwendung erweitern, sodass sie User, die bei einem anderen Service via ID abgefragt werden, mit Namen begrüßen kann.

Hierfür benötigen wir weitere Abhängigkeiten, die wir in unsere Build-Konfiguration (Maven oder Gradle) aufnehmen: io.ktor:ktor-client-core, io.ktor:ktor-client-cio und io.ktor:ktor-client-content-negotiation. Den Client implementieren wir so, wie in Listing 4 dargestellt.

import io.ktor.client.*
import io.ktor.client.call.*
import io.ktor.client.engine.cio.*
import io.ktor.client.plugins.contentnegotiation.*
import io.ktor.client.request.*
import io.ktor.serialization.kotlinx.json.*
import kotlinx.serialization.Serializable
 
class UserService(
  val client: HttpClient = HttpClient(CIO) {
    expectSuccess = true
    install(ContentNegotiation) {
      json()
    }
  }
) {
 
  suspend fun findUser(userId: String): User =
    client.get("http://localhost:8181/users/$userId").body<User>()
}
 
@Serializable
data class User(
  val id: String,
  val name: String,
)

Wir erzeugen zunächst einen HTTP-Client, der JSON Accept-Header verschickt und JSON-Antworten deserialisieren kann. Außerdem konfigurieren wir ihn via expectSuccess = true so, dass alle nicht 2xx Response Codes zu einer Exception führen.

Die Methode findUser ruft ein HTTP API auf und deserialisiert die JSON-Antwort in ein User-Objekt. Dieses wird mit @Serializeable für das Kotlin-Serialisierungsmodul (kotlinx.serializable) serialisierbar gemacht. client.get ist dabei eine suspend fun, also muss entweder die Methode findUser ebenfalls eine suspend fun sein oder explizit einen Coroutine Scope starten. Da wir die Methode aus dem Ktor-Server heraus nutzen wollen, der bereits einen Coroutine Scope zur Verfügung stellt, definieren wir die Methode als suspend fun. Listing 5 zeigt die Integration des Clients in den Server.

fun Application.configureRouting() {
  routing {
    route("/hello") {
      get("/{name?}") {
        val name = call.parameters["name"] ?: "World"
 
        call.respond("Hello $name!")
      }
      get("/user/{userId}") {
        try {
          val user = userService.findUser(call.parameters.getOrFail("userId"))
          call.respond("Hello ${user.name}!")
        } catch (e: ClientRequestException) {
          if (e.response.status == HttpStatusCode.NotFound) {
            call.respond(HttpStatusCode.BadRequest)
          } else {
            call.respond(HttpStatusCode.InternalServerError)
          }
        }
      }
    }
  }
}

Hierfür wird die Funktion configureRouting erweitert. Wir definieren eine zusätzliche Route als GET Request auf /hello/user/$userId. Ein Aufruf versucht, die übermittelte User-ID aufzulösen und den Namen auszulesen. Wird der User nicht gefunden, wird ein passender Fehler zurückgegeben. Der zugehörige Server ist in Listing 6 dargestellt.

val userService = UserService()
 
fun main() {
  embeddedServer(Netty, port = 8181, host = "0.0.0.0") {
    install(ContentNegotiation) {
      json()
    }
    configureRouting()
  }.start(wait = true)
}
 
fun Application.configureRouting() {
  routing {
    route("/users") {
      get() {
        call.respond(
          userService.users
            .map { User(id = it.key, name = it.value) }
        )
      }
      get("/{id}") {
        val id = call.parameters.getOrFail("id")
        try {
          val name = userService.users.getValue(id)
 
          call.respond(User(id = id, name = name))
        } catch (_: NoSuchElementException) {
          call.respond(HttpStatusCode.NotFound)
        }
 
      }
      post("/{name}") {
      call.respond(userService.createUser(call.parameters.getOrFail("name")))
        }
    }
  }
}
 
@Serializable
data class User(
  val id: String,
  val name: String,
)
 
class UserService(
  val users: MutableMap<String, String> = mutableMapOf(),
) {
  fun createUser(
    name: String,
  ): String {
    val id = "${UUID.randomUUID()}"
    users[id] = name
 
    return id
  }
}

Neben GET Requests wird auch ein POST Request definiert. Außerdem können @Serializable-Klassen von Ktor ebenfalls zu JSON serialisiert werden, wenn diese als Antwort zurückgegeben werden sollen.

Mit Ktor ist es, wie die Beispiele zeigen, sehr einfach möglich, HTTP-Kommunikation zu implementieren. Diese ist standardmäßig non-blocking und damit sehr ressourceneffizient umgesetzt.

Stay tuned

Regelmäßig News zur Konferenz und der Java-Community erhalten

 

Kotlin Coroutines und Spring Boot

Den großen Vorteil von Kotlin Coroutines, einfach parallelisierbaren Code zu entwickeln, nutzt auch das am weitesten verbreitete Framework für die JVM, Spring Boot. Mit Version 5 hat das Spring Framework Unterstützung für non-blocking Verarbeitung der Requests erhalten: Spring Webflux [6]. Während Java-Entwickler hier auf den Reactive Programming Stack von Project Reactor angewiesen sind und damit ihre Entwicklungspattern umstellen müssen, können Kotlin-Entwickler ihr gewohntes Entwicklungspattern beibehalten, da jegliche Parallelität auch über Kotlin Coroutines abgebildet werden kann. Verantwortlich hierfür ist das Kotlin-Modul org.jetbrains.kotlinx:kotlinx-coroutines-reactor. Es bindet Kotlin Coroutines an Project Reactor an.

Der Einstieg in die Entwicklung ist dabei genauso einfach wie bei jedem anderen Spring-Projekt. Über den Spring Boot Starter [7] wird das Projekt konfiguriert. Statt der Abhängigkeit Spring Web wird Spring Reactive Web verwendet. Die Anbindung von Kotlin Coroutines an Project Reactor wird für Kotlin-Projekte automatisch hinzugefügt.

Die Implementierung erfolgt dann fast wie gewohnt (Listing 7). Der einzige Unterschied ist die Methodensignatur der Methode hello. Diese ist als suspend fun, also als Koroutine deklariert. Ist eine Methode mit RequestMapping als suspend fun definiert, so startet Spring automatisch einen Coroutine Scope für die Ausführung des Requests.

@RestController
@RequestMapping("/hello")
class HelloController(
  val userService: UserService
) {
 
  @GetMapping(value = ["" ,"/{name}"])
  suspend fun hello(
    @PathVariable(required = false) name: String?
  ) =
    "Hello ${name ?: "World"}!"
}

Der Coroutine Scope ermöglicht es auch, weitere suspend funs aufzurufen. Das ist insbesondere dann von Vorteil, wenn auch die aufgerufenen Funktionen non-blocking implementiert sind. Das ist zum Beispiel beim Spring WebClient der Fall. Dieser basiert auf dem Reactive Stack von Project Reactor und kann auch mit Kotlin Coroutines verwendet werden. Der UserService aus dem Ktor-Beispiel (Listing 4) kann mit dem Spring WebClient implementiert werden, wie in Listing 8 gezeigt.

@Service
class UserService(
  val webClient: WebClient = WebClient.create()
) {
  suspend fun findUser(userId: String): User {
    return webClient.get().uri("http://localhost:8181/users/$userId")
      .accept(APPLICATION_JSON)
      .awaitExchange {
        if (it.statusCode() == HttpStatus.NOT_FOUND) {
          throw UserIdNotFoundException()
        }
        it.awaitBody<User>()
      }
  }
}
 
data class User(
  val id: String,
  val name: String,
)
 
class UserIdNotFoundException: Exception()

Der Controller aus Listing 7 kann dann um den Code aus Listing 9 erweitert werden, sodass dieselbe Funktionalität entsteht wie im Ktor-Beispiel aus Listing 5.

@GetMapping("/user/{userId}")
suspend fun helloUser(
  @PathVariable userId: String
) =
    "Hello ${userService.findUser(userId).name}!"
 
@ExceptionHandler(UserIdNotFoundException::class)
@ResponseStatus(HttpStatus.BAD_REQUEST)
suspend fun handleUserIdNotFoundException(e: UserIdNotFoundException) { }

Auch mit Spring Boot ist es sehr einfach möglich, die Vorteile von Kotlin Coroutines zur besseren Parallelisierung zu nutzen.

 

Fazit: Spring Boot und Ktor in Kotlin

Kotlin bietet mit Kotlin Coroutines eine sehr einfache Möglichkeit, parallelen Code zu schreiben, ohne die damit verbundene Komplexität explizit selbst verwalten zu müssen. Außerdem benötigen Kotlin Coroutines deutlich weniger Ressourcen als Threads. Coroutines haben außerdem eine sehr geringe Einstiegshürde, da die gewohnten Entwicklungspattern beibehalten werden können.

Basierend auf Kotlin Coroutines können Client- und Serveranwendungen sehr einfach entwickelt werden. Hierfür gibt es mit Ktor ein Kotlin-natives Framework, das einen unkomplizierten Einstieg ermöglicht. Ktor ist dabei ein kleines Framework dessen Funktionsumfang auf das limitiert ist, was zur Entwicklung eines Servers oder Clients benötigt wird. Dafür ist eine Einbindung in Kotlin Native möglich, die Build-Artefakte bleiben kompakt und es kann einfacher mit anderen Libraries oder Frameworks kombiniert werden. Außerdem gibt es die non-blocking Verwendung der Webserver-Threads automatisch dazu.

Non-blocking Anwendungen können aber auch über Spring Boot mit Kotlin Coroutines entwickelt werden. Hier muss man sich allerdings explizit für den Non-blocking-Ansatz entscheiden. Im Gegenzug gibt es das komplette Spring-Ökosystem dazu: Dependency Injection, Spring Data und vieles mehr.


Links & Literatur

[1] https://ktor.io/

[2] https://start.ktor.io/

[3] https://projectreactor.io/

[4] https://de.wikipedia.org/wiki/Koroutine

[5] https://kotlinlang.org/docs/coroutines-guide.html

[6] https://docs.spring.io/spring-framework/docs/current/reference/html/web-reactive.html

[7] https://start.spring.io

The post Mit Ktor und Spring Boot Server- und Clientanwendungen entwickeln appeared first on JAX.

]]>
Microframeworks unter der Lupe: Javalin vs. Ktor vs. Spring Fu vs. Micronaut https://jax.de/blog/core-java-jvm-languages/microframeworks-unter-der-lupe-javalin-vs-ktor-vs-spring-fu-vs-micronaut/ Wed, 17 Apr 2019 16:11:09 +0000 https://jax.de/?p=67665 In letzter Zeit gewinnen in der Java-Welt Microframeworks wie Javalin, Ktor, Spring Fu oder Micronaut an Bedeutung. Christian Schwörer (Novatec Consulting GmbH) stellt die Frameworks in seiner kommenden JAX-Session eingesetzt vor. Wir haben im Vorfeld um eine kurze Einschätzung gebeten.

The post Microframeworks unter der Lupe: Javalin vs. Ktor vs. Spring Fu vs. Micronaut appeared first on JAX.

]]>

Was sind Microframeworks eigentlich?

JAX: In der letzten Zeit kommen Microframeworks wieder in Mode. Beispiele in der Java-Welt sind Javalin, Ktor, Spring Fu und Micronaut. Worauf zielen diese Frameworks ab?

Christian Schwörer: Unter „Microframeworks“ versteht man minimalistische Web-Frameworks zum Bau von modularen Anwendungen. Wesentlicher Bestandteil ist die Möglichkeit, einen Webserver wie zum Beispiel Netty zu konfigurieren und zu starten. Darüber werden dann für gewöhnlich REST-Endpunkte bereitgestellt oder Webinhalte ausgeliefert.

Das Besondere bei Microframeworks ist, dass sie sich auf die zentralen Konzepte bei der Anwendungsentwicklung fokussieren. Durch diese Vereinfachung steht die Developer Experience klar im Vordergrund: Es ist möglich, sehr schnell eine Web-Anwendung zu erstellen.

Ebenso zeichnen sich alle genannten Frameworks durch ihre klare Cloud-Ausrichtung und die Eignung für die leichtgewichtige Erstellung von Microservices aus.

JAX: Für die Java-Plattform haben wir mit Spring Boot und dem Eclipse MicroProfile zwei prominente Frameworks für Microservices. Wie unterscheiden sich die Microframeworks von diesen beiden?

Christian Schwörer: Wie erwähnt, konzentrieren sich Microframeworks auf die wesentlichen Bestandteile zur Erstellung von Microservices. Daher haben sie üblicherweise einen geringeren Funktionsumfang als Fullstack-Frameworks wie Spring, MicroProfile oder Grails. Allerdings gibt es auch bei Microframeworks eine große Bandbreite: von Frameworks, die sich wirklich auf das Elementare beschränken, bis hin zu welchen, die so gut wie alle von anderen Frameworks bekannten Features bieten.

Verschaffen Sie sich den Zugang zur Java-Welt mit unserem kostenlosen Newsletter!

Unabhängig vom Funktionsumfang zeichnen sich jedoch alle Microframeworks durch einen schnellen Applikationsstart und einen kleinen Memory Footprint aus. Das ist vor allem beim Einsatz in geclusterten Docker-Containern oder in Serverless-Architekturen ein entscheidender Vorteil.

Das Besondere bei Microframeworks ist, dass sie sich auf die zentralen Konzepte bei der Entwicklung fokussieren.

 

Javalin, Ktor, Spring Fu, Micronaut

JAX: Bleiben wir einmal bei den vier genannten Microframeworks und beginnen bei Javalin. Wie kann man Javalin einordnen – wo liegen die Stärken?

Christian Schwörer: Die Stärke von Javalin liegt ganz klar in seiner Einfachheit. Es ist sehr leicht zu verstehen und handzuhaben, und dementsprechend einfach ist der Code zu lesen. Dies erreicht das Framework, indem es sich auf wenige wesentliche Konzepte beschränkt, die erlernt werden müssen. Daher eignet es sich auch am ehesten für die schnelle Erstellung von überschaubar kleinen (Micro-)Services.

JAX: Ktor beschreibt sich selbst als asynchrones Web Framework für Kotlin. Für welchen Einsatzzweck ist Ktor aus deiner Sicht besonders interessant?

Christian Schwörer: Hinter Ktor steht maßgeblich JetBrains, das Unternehmen, das die meisten vermutlich von der Entwicklungsumgebung IntelliJ und der JVM-Sprache Kotlin kennen.

Es verwundert daher wenig, dass Ktor – anders als die anderen genannten Microframeworks – ausschließlich Kotlin unterstützt. Diese Einschränkung ermöglicht es allerdings, die Kotlin-Sprachfeatures ideal zu nutzen. So setzt Ktor beispielsweise intensiv auf Coroutines, der leichtgewichtigen Kotlin-Lösung für nebenläufige Programmierung. Dadurch ergibt sich ein asynchrones Framework, das sich etwa für den Bau von API-Gateways eignet.

Nebenbei erwähnt, arbeite ich persönlich seit Längerem in der Backend-Entwicklung ausschließlich mit Kotlin, so dass ich eine gewisse Affinität zu verwandten Technologien habe.

Die Stärke von Javalin liegt ganz klar in seiner Einfachheit.

 

JAX: Relativ neu ist auch das Projekt Spring Fu. Damit lassen sich Spring Boot-Anwendungen mittels einer Kotlin DSL oder einer Java DSL konfigurieren. Kannst du das einmal anhand eines Beispiels demonstrieren?

Christian Schwörer: Spring Fu bietet eine funktionale Alternative zur Annotation-basierten, deklarativen Spring Boot-Konfiguration. In folgendem Kotlin-Beispiel wird anhand der @Bean-Annotation eine Spring-Bean definiert:

@Configuration
class MyConfiguration() {
    @Bean
    fun mySpringBean() = MySpringBean()
}

Mit der Kotlin-DSL von Spring Fu sieht dies wie folgt aus:

configuration {
    beans {
        bean< MySpringBean >()
    }
}

Durch die explizite, funktionale Konfiguration wird der Overhead auf ein Minimum reduziert, der sich bei der deklarativen Nutzung von Spring Boot durch Reflection und Classpath Scanning ergibt. Dies führt zu einem schnelleren Applikationsstart und weniger Speicherverbrauch.

Allerdings gibt es Spring Fu erst als Incubator in der Version 0.0.5. Das heißt, auch wenn es sich lohnt, das Projekt im Blick zu behalten, ist es für einen Einsatz in einem produktiven Szenario meines Erachtens noch zu früh.

JAX: Und schließlich Micronaut: Was sind die Eckdaten dieses Frameworks?

Christian Schwörer: Micronaut ist sicherlich das Feature-kompletteste der erwähnten Frameworks. Neben Dependency Injection, Anbindung unterschiedlichster Datenbanken und zahlreicher Security Features bietet es Cloud-native Module wie etwa Service Discovery, Circuit Breakers und Distributed Tracing. Es positioniert sich somit am klarsten als Alternative zu Spring Boot oder Eclipse MicroProfile.

Dennoch weist es Eigenschaften von Microframeworks auf, insbesondere kurze Startzeiten und geringer Speicherverbrauch. Dies wird erreicht, da weitestgehend auf Reflection, Proxies und Classpath Scanning zur Start- und Laufzeit verzichtet wird. Ermöglicht wird dies, indem die benötigten Informationen mittels Annotation Processing und Ahead-of-Time-Compilation bereits zur Compilezeit ermittelt werden.

Ich sollte mir im Vorfeld über den groben Scope meiner Anwendung bewusst sein.

 

Microframeworks in der Praxis

JAX: Du kennst die Microframeworks ja aus der Praxis. Wie kann man am besten loslegen? Hast du einen besonderen Tipp für die Leser, der für dich persönlich gut funktioniert hat?

Christian Schwörer: Einfach selbst ausprobieren! Für alle genannten Frameworks gibt es gute Tutorials, anhand derer man sehr schnell ein Gefühl für die Entwicklung damit bekommt und einen ersten Eindruck, ob das Framework für die angedachte Aufgabe geeignet ist.

Ich sollte mir im Vorfeld aber auch über den groben Scope meiner Anwendung bewusst sein. Gehe ich davon, dass sie in Zukunft stark erweitert werden muss? Brauche ich deshalb beispielweise Features wie Dependency Injection oder explizites Transaktionsmanagement? Dann eignen sich nicht alle der angesprochenen Frameworks, da sich einige – wie bereits erwähnt – zugunsten der schnellen Erlernbarkeit und Einfachheit bewusst auf Kernfunktionen beschränken.

JAX: Vielen Dank für dieses Interview!

Die Fragen stellte Hartmut Schlosser.

 

Quarkus-Spickzettel


Quarkus – das Supersonic Subatomic Java Framework. Wollen Sie zeitgemäße Anwendungen mit Quarkus entwickeln? In unserem brandaktuellen Quarkus-Spickzettel finden Sie alles, was Sie zum Loslegen brauchen.

 

Jetzt herunterladen!

The post Microframeworks unter der Lupe: Javalin vs. Ktor vs. Spring Fu vs. Micronaut appeared first on JAX.

]]>