spring boot - JAX https://jax.de/tag/spring-boot/ Java, Architecture & Software Innovation Fri, 18 Oct 2024 13:21:32 +0000 de-DE hourly 1 https://wordpress.org/?v=6.5.2 Ein Liebesbrief an die Java-Community https://jax.de/blog/ein-liebesbrief-an-die-java-community/ Fri, 01 Sep 2023 06:14:04 +0000 https://jax.de/?p=88940 Ich möchte diesen Artikel nutzen, um vielen Menschen und Unternehmen zu danken. Ein solches Projekt mit meinem Sohn ist nur möglich, weil sie fantastische Bibliotheken und Werkzeuge geschaffen haben, mit denen wir Anwendungen schnell entwickeln können.

The post Ein Liebesbrief an die Java-Community appeared first on JAX.

]]>
In meinem vorherigen Artikel [1] habe ich gezeigt, wie ich Java Enums verwende, um die Kategorien für Videos auf der Website https://4drums.media [2] zu definieren. Diese Website ist ein Lieblingsprojekt, das ich zusammen mit meinem dreizehnjährigen Sohn entwickelt habe.

Ich werde hier nicht das gesamte Projekt mit Ihnen teilen und Ihnen den kompletten Code zeigen. Nein, ich möchte die Gelegenheit vielmehr nutzen, um allen zu danken, die es uns ermöglicht haben, diese Website zu erstellen!

Abb. 1: Die verfügbaren Video- und Tutorialkategorien auf der Website 4drums.media

Stay tuned

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

 

Über 4drums.media

Wie viele Jugendliche heutzutage möchte auch mein Sohn „im Internet berühmt“ werden – er spielt Schlagzeug, seitdem er ein kleiner Junge ist. Um seine Ambitionen zu unterstützen, haben wir gemeinsam eine Website erstellt, auf der er Schlagzeugvideos veröffentlichen und eine Community aufbauen kann, die sich für das Schlagzeugspielen interessiert. Da er kein Budget hat, ist das Hosten und Bearbeiten von Videos keine Option. Glücklicherweise bieten YouTube und Vimeo APIs an, um mit ihren Diensten zu interagieren. In Kombination mit meinen Erfahrungen mit Spring Boot, Vaadin usw. konnten wir schnell loslegen und hatten bald die erste Version, die jetzt verfügbar ist. Werfen wir einen Blick auf die von uns verwendeten Tools, die Sie für Ihr nächstes persönliches oder berufliches Projekt inspirieren könnten.

IntelliJ IDEA

Visual Studio Code, Eclipse, NetBeans – alles großartige und kostenlose IDEs zur Erstellung von Java-Code. Aber die am häufigsten verwendete IDE ist seit vielen Jahren IntelliJ IDEA [3]. Ich benutze die (kostenpflichtige) Ultimate Edition, aber die kostenlose Community Edition ist genauso gut. Und ja, mein Sohn benutzt diese Version auf seinem Schul-PC! Am Code selbst hat er nicht mitgewirkt, aber ich konnte ihn einfach die neueste Version ziehen lassen, ein paar Farben und Symbole hinzufügen, lokal testen und sie dann wieder in das Repository einspeisen. Und dank des automatisierten Builds (siehe GitHub weiter unten) kann er die Änderungen innerhalb weniger Minuten live sehen. Ist es nicht großartig, dass jeder, vom Anfänger bis zum erfahrenen Benutzer, ein solch fantastisches Tool frei nutzen kann? Vielen Dank, JetBrains!

Spring Boot und Bibliotheken

Ich liebe Quarkus, Micronaut und andere, weil sie viel Evolution in die Java-Welt gebracht haben. Da ich jedoch bereits viel Erfahrung mit Spring Boot [4] hatte, habe ich diesen Weg weiterverfolgt. Aber es ist nicht nur Spring selbst, das dieses System zu einem fantastischen Framework macht. Es ist die Kombination mit Flyway zur Erweiterung der Datenbankstruktur, H2 für lokale Tests, Jsoup zur Validierung von Texteingaben, JUnit für Tests usw. Ich bin also nicht nur Spring dankbar, sondern auch den vielen Unternehmen und Entwicklern, die großartige Java-Bibliotheken und -Tools entwickeln!

YouTube und Vimeo

Einen Videodienst selbst zu hosten, würde den Rahmen eines Vater-Sohn-Projekts bei Weitem sprengen. Aber zum Glück müssen wir das nicht tun, denn viele Videodienste erlauben eine vollständige Integration. So können sie auf einfache Weise mehr Zuschauer anziehen, da ihre Videos in andere Websites integriert werden. Der Player unterliegt jedoch vollständig der Kontrolle des Anbieters, sodass jede Ansicht eines Videos (und der Werbung …) eine zusätzliche Ansicht für seine jeweilige Plattform darstellt.

Mit dem WebClient von Spring ist es mühelos möglich, die Beschreibung, den Kanal, das Vorschaubild und weitere Informationen z. B. von jedem YouTube-Video abzurufen. In Kombination mit Datensätzen, die der YouTube-API-Antwort-JSON [5] entsprechen, und der FasterXML-Bibliothek von Jackson ist nur minimaler Code erforderlich, um Daten anzufordern und das Ergebnis zu parsen (Listing 1).

public Optional<YouTubeApiResponse> getYouTubeVideoApi(String id) {
  String url = "https://www.googleapis.com/youtube/v3/videos"
  + "?id=" + id + 
  + "&part=snippet%2CcontentDetails%2Cstatistics"
  + "&key=" + apiKeyYouTube;
  YouTubeApiResponse video = webClient.get()
    .uri(URI.create(url))
    .retrieve()
    .bodyToMono(YouTubeApiResponse.class)
    .block();
  if (video == null) {
    logger.error("Could not get info from YouTube for {}", id);
    return Optional.empty();
  }
  logger.info("Video info from YouTube: {}", video.title());
  return Optional.of(video);
}

@JsonIgnoreProperties(ignoreUnknown = true)
@JsonInclude(JsonInclude.Include.NON_NULL)
public record YouTubeApiResponse(
  String kind,
  String etag,
  List<Item> items) {}

@JsonIgnoreProperties(ignoreUnknown = true)
@JsonInclude(JsonInclude.Include.NON_NULL)
public record Item(
  String kind,
  String etag,
  String id,
  Snippet snippet,
  ContentDetails contentDetails,
  Statistics statistics
) {
}

Vimeo bietet die gleiche Art von API [6], daher haben wir beide Dienste integriert. Mit dem Aufstieg des Fediverse werden Alternativen wie PeerTube [7] an Bedeutung gewinnen, und wir werden definitiv versuchen, die unterstützten Videoplattformen später zu erweitern.

SIE LIEBEN JAVA?

Den Core-Java-Track entdecken

 

Vaadin

Ich habe JavaFX schon oft für grafische Benutzeroberflächen auf dem Desktop verwendet. Mit Vaadin habe ich ein ähnlich leistungsfähiges und Java-basiertes Framework für die Websiteentwicklung gefunden. Mit reinem Java-Code können Sie sowohl das Backend als auch das Frontend innerhalb eines Maven-Projekts erstellen, das einfach zu paketieren und zu verteilen ist. Auf start.vaadin.com [8] können Sie die verschiedenen Seiten konfigurieren, die Sie benötigen (Abb. 2), das Theme gestalten (Abb. 3) und die Java- und Vaadin-Version auswählen, die Sie verwenden möchten. Wenn Sie fertig sind, können Sie ein vollständig vorbereitetes Maven-Projekt auf Basis von Spring Boot mit einem Mausklick herunterladen, entpacken und in der IDE öffnen und ausführen, um es weiter zu bearbeiten.

Abb. 2: Sie können die verschiedenen Seiten konfigurieren …

Abb. 3: … und das Theme gestalten

Jede Komponente ist auf der Vaadin-Website [9] sehr gut dokumentiert und mit viel Beispielcode versehen. Das Hinzufügen einer solchen Komponente zu den HTML-Seiten und das Verknüpfen mit einer Backend-Methode ist sehr einfach, wie Sie im Beispielcode für den Like-Button in Listing 2 sehen.

var like = new Button();
like.setIcon(VaadinIcon.THUMBS_UP_O.create());
like.setText(String.valueOf(numberOfLikes));
like.addClickListener(e -> {
  videoService.addLike(video, user);
});
add(like);

Abb. 4: Der Output von Listing 2

Vaadin bietet eine lizenzierte Version mit zusätzlichen erweiterten Komponenten (Charts, GridPro …) und Support. Dennoch bietet die freie und quelloffene Version selbst für viele Geschäftsfälle alle Tools, um eine vollständige Webanwendung zu erstellen. Ich habe sie in meinen früheren Jobs für Back-Office-Anwendungen verwendet, und die Entwicklungsgeschwindigkeit, die sich aus einer einzigen Codebasis für APIs und UI ergibt, ist enorm!

 

PostgreSQL

Gibt es heute noch Websites, die keine Datenbank verwenden? Mein Weg zur Datenbank begann vor vielen Jahren mit Microsoft Access. Obwohl es nicht für die Verwendung im Web gedacht war, konnte ich viele dynamische Websites mit einer Access-Datenbank als Kern erstellen. Später habe ich SQL Server, MySQL, NoSQL-Datenbanken und andere verwendet. Aber ich denke, wir können festhalten, dass PostgreSQL [10] den größten Teil der Welt der Onlinedatenbanken erobert hat. Ich liebe Tools, die einfach da sind, um die man sich nicht kümmern muss und die das tun, was sie tun sollen. Genau das hat PostgreSQL für mich seit vielen Jahren getan. Und auch hier ist die Kombination mit Spring Boot erstaunlich einfach und unkompliziert.

GitHub-Repository und Aktionen

Da ich nun schon seit einiger Zeit in dieser Branche tätig bin, habe ich viele Entwicklungen in der Art und Weise gesehen, wie Quelldateien verwaltet und gemeinsam genutzt werden. Von einem normalen Dateiserver mit ständigen Konflikten, über CVS, SVN bis hin zu Git. Im Foojay-Podcast „The Future of Source Control and CI/CD“ [11] sind wir zu dem Schluss gekommen, dass das aktuelle Git wahrscheinlich kein Endpunkt ist und wir weitere Entwicklungen sehen werden. Ist es nicht seltsam, dass nur die Softwareindustrie einen solchen Workflow angenommen hat? Warum verwendet z. B. der Gesetzgeber nicht denselben Ansatz, während die Erweiterung und Verbesserung von Gesetzen eigentlich sehr ähnlich ist und auf einem System von „Patches“ basiert? Könnte es sein, dass Trunks, Merge-Konflikte und zu viele mögliche Befehle Git zu kompliziert machen? Und dass nur Softwareentwickler in der Lage zu sein scheinen, mit diesen Herausforderungen fertigzuwerden?

Die Beantwortung dieser Fragen würde den Rahmen dieses Artikels sprengen, aber ich bin auf jeden Fall sehr dankbar für das, was GitLab, GitHub und Co. als kostenlosen Service für Open-Source- und Pet-Projekte anbieten. Ein zuverlässiges Versionskontrollsystem zu haben, ohne sich um Serverkosten, Back-ups, Upgrades usw. kümmern zu müssen, ist die erste Hürde, die diese Anbieter nehmen. Aber für mich ist der wichtigste Grund, sie zu lieben, die CI/CD, die sie bieten. Dank GitHub Actions führt jeder Commit in das Repository dazu, dass eine neue Websiteversion innerhalb von Minuten bereitgestellt wird, und zwar vollständig automatisiert, dank einer einzigen .yml-Datei. Ja, wir sind uns alle einig, dass YAML ätzend ist und das Erreichen einer funktionierenden Aktionsdatei nervt, aber wenn man eine funktionierende Lösung hat und sich nicht mehr um den Build- und Deployment-Prozess kümmern muss, ist das ein echter Meilenstein in jedem Projekt!

Stay tuned

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

 

Uberspace

Bis jetzt habe ich die meisten der Tools aufgelistet, die ich für die 4drums.media-Website verwendet habe und die alle kostenlos erhältlich sind! Jetzt bleibt nur noch ein letzter Schritt für jede Website: ein Onlinezuhause finden. Die Möglichkeiten sind endlos, von Shared Hosting über VPS bis hin zu kompletten Netzwerkumgebungen bei AWS, Azure oder jedem anderen Anbieter. Von nicht so günstig bis sehr teuer …

Da unser Budget für dieses Projekt sehr begrenzt ist (eigentlich nichtexistent), habe ich in Deutschland eine schöne Lösung bei uberspace.de [12] gefunden. Mit einem Pay-as-you-want-Modell ab 5 Euro/Monat bekommt man einen VPS, den man nach Bedarf konfigurieren kann. In unserem Fall bedeutete das, die richtige Java-Version und PostgreSQL zu installieren. Mit einer sehr detaillierten Dokumentation [13] war jeder Schritt in diesem Prozess eine schnelle und angenehme Erfahrung. Und wenn man nicht weiterkommt, antwortet der Support schnell und hilft einem oder verweist auf die richtige Dokumentation.

Das Hosting der Website (und des Domänennamens) ist also der einzige Teil dieses Projekts, bei dem „Herr Visa“ uns helfen musste, aber der Betrag ist trotzdem minimal.

Fazit

Java ist nicht nur eine Sprache und eine Laufzeitumgebung. Es ist auch eine große Gemeinschaft von Menschen und Unternehmen, die erstaunliche Dinge entwickelt, die in den meisten Fällen kostenlos genutzt werden können. Teil dieser Gemeinschaft zu sein, ist eine tägliche Freude, und ich bin wirklich dankbar, dass all das verfügbar ist! Deshalb sage ich allen, die einen Beitrag leisten und all dies möglich machen: Danke! Aus tiefstem Herzen!


Links & Literatur

[1] Delporte, Frank: „Verborgene Schönheiten“; in Java Magazin 9.2023

[2] https://4drums.media

[3] https://www.jetbrains.com/idea/

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

[5] https://developers.google.com/youtube/v3/

[6] https://developer.vimeo.com

[7] https://joinpeertube.org

[8] https://start.vaadin.com

[9] https://vaadin.com/docs/latest/components

[10] https://www.postgresql.org

[11] https://foojay.io/today/foojay-podcast-26/

[12] https://uberspace.de

[13] https://manual.uberspace.de

[14] https://webtechie.be/books

The post Ein Liebesbrief an die Java-Community appeared first on JAX.

]]>
Chaos Monkey für Spring Boot https://jax.de/blog/chaos-monkey-fuer-spring-boot-chaos-engineering/ Tue, 15 Aug 2023 07:04:38 +0000 https://jax.de/?p=88898 Mit Chaos Engineering wird bewusst Chaos in ein System eingeführt, um dessen Reaktion auf unvorhergesehene Ereignisse zu testen und Schwachstellen aufzudecken. Der „Chaos Monkey for Spring Boot“ ist eine populäre Implementierung für Chaos Engineering in Spring-Boot-Anwendungen. Es ist ein leistungsfähiges Werkzeug, das die Robustheit von Spring-Boot-Anwendungen durch die gezielte Einführung von Chaostests verbessert.

The post Chaos Monkey für Spring Boot appeared first on JAX.

]]>
Chaos Monkey for Spring Boot [1] ermöglicht es Entwicklern, Ausfallszenarien zu simulieren und die Reaktion ihres Systems darauf zu überwachen. Dadurch können potenzielle Schwachstellen identifiziert und Engpässe aufgedeckt werden, um die Stabilität und Ausfallsicherheit der Anwendung zu verbessern. Beispielsweise ermöglicht Chaos Monkey den Entwicklern das plötzliche Abschalten eines Dienstes, Netzwerkstörungen oder die Simulation hoher Lasten auf das System. Durch diese gezielte Einführung von Chaostests und die Behebung der Schwachstellen ist sichergestellt, dass ihre Anwendung auch unter schwierigen Bedingungen zuverlässig funktioniert. Der Chaos Monkey for Spring Boot bietet zahlreiche Funktionalitäten und Konfigurationsoptionen, um den Testprozess zu steuern und die gewünschten Szenarien zu simulieren. Dieser Artikel bietet einen detaillierten Einblick in den Chaos Monkey for Spring Boot. Darüber hinaus werden seine Einsatzszenarien, Best Practices und Implementierungsmöglichkeiten diskutiert.

NEUES AUS DER JAVA-ENTERPRISE-WELT

Serverside Java-Track entdecken

 

Vorstellung

Das Projekt Chaos Monkey for Spring Boot wurde ursprünglich anno 2017 von Benjamin Wilms bei codecentric ins Leben gerufen und über die Jahre von ihm und seinen Kollegen weiterentwickelt. Das Projekt wird aktiv gepflegt und an neue Spring-Boot-Versionen angepasst. Inspiriert von den Principles of Chaos Engineering [2] und mit einem Fokus auf Spring Boot bietet das Chaos-Monkey-Projekt eine Möglichkeit, Anwendungen besser zur Laufzeit zu testen. Das kann lokal, aber auch in der Cloud geschehen. Die Fragen, die sich jeder Entwickler stellt, egal wie viele Unit- und Integrationstests existieren: Wie verhält sich unsere Anwendung im Betrieb? Was passiert bei langsamen Datenbankabfragen? Wie verhält sich die Anwendung bei langsamen Antworten oder Fehlern anderer Services? Was passiert, wenn Discovery Service oder Discovery Client Fehler produzieren? Oder sogar zu viel Speicher oder CPU verbrauchen? Um all diese Probleme zu simulieren und Störungen zu injizieren, unterstützt uns nun der Chaos Monkey.

Implementierung und Konfiguration

Es gibt zwei Möglichkeiten, Chaos Monkey for Spring Boot in einer bestehenden Spring-Boot-Anwendung zu aktivieren. Entweder fügt man ihn zu den regulären Anwendungsabhängigkeiten im Build- und Dependency-Management-Tool hinzu (Listing 1) oder man bindet ihn als externe Abhängigkeit beim Start der Spring-Boot-Anwendung ein. Da sich das Tool nicht im offiziellen Release-Train von Spring Boot befindet, muss die passende Version selbst definiert werden.

// Maven
<dependency>
  <groupId>de.codecentric</groupId>
  <artifactId>chaos-monkey-spring-boot</artifactId>
  <version>3.0.1</version>
</dependency>
 
// Gradle
plugins {
  id 'java'
  id 'org.springframework.boot' version '3.0.1'
  id 'io.spring.dependency-management' version '1.1.0'
}

Beim Start der Spring-Boot-Anwendung mit aktiviertem „chaos-monkey“-Profil wird die Funktionalität für die ausgewählten Watchers aktiv. Die Eigenschaften können über Umgebungsvariablen, System Properties oder Application Properties konfiguriert werden (Listing 2). Die Konfiguration über Properties bietet alle verfügbaren Optionen, erfordert aber einen Neustart, um Änderungen zu übernehmen. Um das zu vermeiden, können die Konfiguration über Actuator REST API vorgenommen werden.

spring.profiles.active=chaos-monkey
chaos.monkey.enabled=true
management.endpoints.web.exposure.include=health,info,chaosmonkey
 
chaos.monkey.watcher.service=true
chaos.monkey.assaults.latencyActive=true

Stay tuned

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

 

Chaos Monkey Watchers und Assaults

Ein Watcher ist eine Komponente von Chaos Monkey for Spring Boot, die die Anwendung nach Spring Beans durchsucht. Je nach Konfiguration werden Annotation Watchers (Abb. 1) z. B. für @Component, Actuator Watchers und Outgoing Request Watchers z. B. für RestTemplate und WebClient registriert. Der Alternative Bean Watcher verwendet im Gegensatz zu den anderen Watchers ausschließlich den Bean-Namen. Mit Hilfe von Spring AOP wird ein Proxy für die Watcher-Funktionalität zur Verfügung gestellt. Beim Aufruf einer öffentlichen Methode auf einer Watched Bean entscheidet dann der Chaos Monkey, ob ein Angriff oder eben keine Aktion ausgeführt wird. Dieses Verhalten kann durch die Konfiguration beeinflusst werden.

Abb. 1: Annotation Watchers und Assaults

Assaults sind das Kernelement von Chaos Monkey und ihre Anwendung erfolgt je nach Konfiguration. Es gibt verschiedene Arten von Assaults: Request Assaults greifen spezifische Punkte der Anwendung an und können Latenz oder Exceptions verursachen. Runtime Assaults hingegen greifen die gesamte Anwendung an und können diese sogar zum Absturz bringen (AppKiller Assault). Möglich ist auch, nur den Speicher (Memory Assault) oder die CPU (CPU Assault) der Java Virtual Machine anzugreifen. Dank Chaos Monkey for Spring Boot können alle Arten von Runtime Exceptions geworfen und die benötigten Exceptions zur Laufzeit konfiguriert werden. Die Runtime Assaults können entweder durch Scheduling oder durch Chaos Monkey Endpoints ausgelöst werden.

Konfiguration des Chaos Monkey

Essenziell im Umgang ist, dass eine Änderung der Watcher-Konfiguration stets einen Neustart der Anwendung zur Folge hat. Das liegt an der Proxy-basierten Implementierung des Tools. Daher muss die gewünschte Konfiguration folglich bereits beim Start der Anwendung festgelegt werden. Jedoch können Watchers via Spring Boot Actuators auch später noch zur Laufzeit umkonfiguriert werden. Da es Spring Boot mittels des Actuators ferner ermöglicht, diese über JMX auszulesen bzw. anzupassen, bietet der Chaos Monkey diese Funktionalität auch für die Konfiguration an.

Welche Spring Beans benötigen nun gegenwärtig einen Watcher? In vielen Fällen ist ein Watcher für Service-Komponenten ausreichend. Runtime Exceptions werden z. B. durch die Spring-Data-Implementierung geworfen und erst im Web-Layer als Fehler an den Aufrufer zurückgegeben. Ob nun die Data Access Exception im Repository oder im Service durch den Assault erzeugt wird, ist in diesem Fall nicht relevant. Sollte der Service jedoch Fallback-Strategien implementieren, wäre die Repository-Schicht vorzuziehen (Listing 3).

#spring.profiles.active=chaos-monkey
 
management.endpoint.chaosmonkey.enabled=true
management.endpoint.chaosmonkeyjmx.enabled=false
 
chaos.monkey.watcher.controller=false
chaos.monkey.watcher.restController=false
chaos.monkey.watcher.service=true
chaos.monkey.watcher.repository=false
chaos.monkey.watcher.component=false
chaos.monkey.watcher.beans=<List of bean names>
chaos.monkey.watcher.exclude=<List of class names>

Wie zuvor erwähnt, erfolgt die Konfiguration der Assaults fortan über den Actuator Endpoint. Dies ermöglicht auch die Ausführung von Chaostests in einer CI/CD Pipeline. Folgende Beispiele zeigen mögliche Problemfälle. Die in Listing 4 gezeigte Konfiguration erzeugt zufällige Runtime Exceptions mit dem Exception Assault. Der Assault-Level in der Konfiguration definiert, wie viele Requests angegriffen werden sollen. In unserem Beispiel ist das jeder fünfte. Ob nun eine normale Runtime Exception oder eine andere ausgelöst werden soll, kann konfiguriert werden.

curl -X POST http://localhost:8080/actuator/chaosmonkey/assaults \
-H 'Content-Type: application/json' \
-d \
‘
{
  "level": 5,
  "latencyActive": false,
  "exceptionsActive": true,
  "killApplicationActive": false
}’

Im nächsten Beispiel (Listing 5) wird der AppKill Assault konfiguriert. Dieser kann über eine CronExpression oder einen Actuator-Aufruf ausgelöst werden.

curl -X POST http://localhost:8080/actuator/chaosmonkey/assaults \
-H 'Content-Type: application/json' \
-d \
‘
{
  "latencyActive": false,
  "exceptionsActive": false,
  "killApplicationActive": true,
  "killApplicationExpression": "*/1 * * * * ?"
}'

Im letzten Beispiel (Listing 6) sollen hängende Threads simuliert werden. Das Hinzufügen einer zusätzlichen Latenz von 100 s bei jeder Antwort (Level 1) führt dazu, dass die Anwendung nicht mehr reagiert.

curl -X POST http://localhost:8080/actuator/chaosmonkey/assaults \
-H ‘Content-Type: application/json’ \
-d \
‘
{
  "level": 1,
  "latencyRangeStart": 99999,
  "latencyRangeEnd": 100000,
  "latencyActive": true,
  "killApplicationActive": false,
  "exceptionsActive": false
}

Das sind nur drei Beispiele, die verschiedene Konfigurationen aufzeigen. Darüber hinaus existieren noch unzählige weitere Möglichkeiten – der Kreativität sind keine Grenzen gesetzt. Sind die Experimente einmal definiert und konfiguriert, kann man mit einem Tool wie Gatling [3] oder dem Chaos Toolkit [4] Tests durchführen und die Reports und Metriken analysieren.

SIE LIEBEN JAVA?

Den Core-Java-Track entdecken

 

Metriken der Attacken

Die Chaos-Monkey-Metriken sind über das Spring Boot Actuator API und Micrometer [5] verfügbar. Damit können die gesammelten Metriken für die Chaostests aus der Anwendung extrahiert werden (Listing 7). Diese Metriken bieten wertvolle Einblicke in das Verhalten der Anwendung während der Chaostests. Sie ermöglichen es Entwicklern, die Auswirkungen der verschiedenen Angriffe auf Performance, Latenz, Speicherverbrauch und andere wichtige Aspekte zu überwachen und zu analysieren. Der Einsatz von Chaos-Monkey-Metriken ermöglicht es Entwicklern, die Auswirkungen von Störungen und Unregelmäßigkeiten auf die Anwendung besser zu verstehen und gezielte Optimierungen vorzunehmen. Außerdem ist es möglich, die Metriken einzusetzen, um die Effektivität der implementierten Resilienz-Patterns zu bewerten und potenzielle Schwachstellen zu identifizieren.

curl -X GET http://localhost:8080/actuator/metrics \
-H 'Content-Type: application/json'
 
#Application Metrics
chaos_monkey_application_request_count_total
chaos_monkey_application_request_count_assaulted
#Assault Exception
chaos_monkey_assault_exception_count
#Assault Latency
chaos_monkey_assault_latency_count_gauge
chaos_monkey_assault_latency_count_total
#Assault KillApp
chaos_monkey_assault_killapp_count
#Watcher Metrics
chaos_monkey_assault_component_watcher_total
chaos_monkey_assault_controller_watcher_total

Patterns für die Behebung der Schwachstellen

In einer verteilten Architektur, in der verschiedene Services miteinander kommunizieren, treten oftmals unvermeidbare Fehler und Störungen auf. Resilience Patterns [6] dienen dazu, diese Fehler abzufangen, abzuschwächen und die Gesamtstabilität des Systems zu gewährleisten. Ein häufig verwendetes Pattern ist das Circuit Breaker Pattern. Dieses unterbricht die Kommunikation mit einem Dienst, falls dieser nicht ordnungsgemäß funktioniert, und stattdessen Fehlerbehandlungsmechanismen einsetzt. Das Fallback Pattern stellt alternativ Funktionalität oder Daten bereit, sofern ein Dienst nicht verfügbar ist. Retry Patterns ermöglichen das erneute Senden von Anfragen, wenn diese aufgrund von temporären Netzwerkproblemen fehlschlagen. Das Timeout Pattern definiert maximale Zeitlimits für Anfragen, um lange Wartezeiten zu vermeiden und die Reaktionsfähigkeit des Systems zu gewährleisten. Das Bulkhead Pattern und das Rate-Limiter Pattern sind weitere wichtige Resilience Patterns. Sie zielen darauf ab, die Auswirkungen von Fehlern in einem Dienst zu begrenzen. Daneben schützen sie andere Teile des Systems vor Ausfällen, indem sie Ressourcen isolieren und in separate Pools aufteilen. Durch den Einsatz dieser und weiterer Resilience Patterns können Microservices optimaler auf unvorhergesehene Situationen reagieren, Ausfälle isolieren und eine höhere Verfügbarkeit und Ausfallsicherheit erreichen. Die effektive Anwendung dieser Patterns ist entscheidend, um die Zuverlässigkeit des gesamten Microservices-Ökosystems zu gewährleisten.

Die Bibliothek Resilience4j [7] bietet umfassende Unterstützung für die Implementierung von Resilience Patterns in Microservices und lässt sich nahtlos in Spring-Boot-Anwendungen integrieren. Durch die Integration mit Spring Boot können Entwickler die Funktionalität von Resilience4j nutzen, indem sie kurzerhand die entsprechenden Abhängigkeiten und Konfigurationen hinzufügen. Die Resilience4j Annotations und Wrapper erleichtern die Anwendung der Resilience Patterns auf Spring-Boot-Komponenten wie Services, Controller oder Repository-Klassen. Ferner ermöglicht die Integration mit Spring Boot die Verwendung von Spring Boot Actuator zur Überwachung und Erfassung von Metriken für die Resilience Patterns. Infolgedessen können Entwickler das Verhalten ihrer Microservices in Bezug auf Fehlertoleranz und Resilienz effektiv überwachen und analysieren. Die nahtlose Integration erleichtert Entwicklern die Implementierung einer robusten und widerstandsfähigen Architektur in ihren Microservices.

Stay tuned

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

 

Fazit

Chaos Monkey for Spring Boot ist ein sehr nützliches Werkzeug für alle Softwareentwickler, die sich mit Chaos Engineering beschäftigen möchten. Durch die Implementierung mit Spring AOP Proxies können Seiteneffekte innerhalb der Anwendung simuliert werden, ohne die reale Infrastruktur zu beeinflussen. Dies ermöglicht es Entwicklern, Probleme auf einfache Weise zu simulieren und zu reproduzieren, sogar auf ihren eigenen Computern. Sobald man damit beginnt, Chaosexperimente zu definieren, wird deutlich, dass zunächst normalerweise das Monitoring verbessert werden muss, um die auftretenden Probleme zu identifizieren. Anschließend werden typische Resilienz-Patterns verwendet, um die entdeckten Schwachstellen zu beheben. Chaos Monkey for Spring Boot erleichtert also nicht nur das Experimentieren mit Chaos, sondern unterstützt auch die Entwicklung resilienter Anwendungen.


Links & Literatur

[1] Chaos Engineering for Spring Boot: https://github.com/codecentric/chaos-monkey-spring-boot

[2] Principles of Chaos Engineering: https://principlesofchaos.org

[3] Gatling: https://gatling.io

[4] Chaos Toolkit: https://chaostoolkit.org

[5] Micrometer: https://micrometer.io

[6] Resilience Patterns: https://github.com/lucasnscr/Resilience-Patterns

[7] https://resilience4j.readme.io/docs

The post Chaos Monkey für Spring Boot appeared first on JAX.

]]>
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.

]]>
Spring Native Hands-on https://jax.de/blog/spring-native-hands-on/ Mon, 05 Jul 2021 07:18:10 +0000 https://jax.de/?p=83728 Mit dem neuen Projekt Spring Native können Spring-Boot-Anwendungen von der GraalVM-Native-Image-Technologie Gebrauch machen und auch für existierende Spring-Boot-Anwendungen Start-up-Zeiten im Millisekundenbereich erzielen. Der Artikel zeigt, wie das funktioniert, wie weit Spring Native schon ist, und wie man die Technologie für eigene Spring-Boot-Anwendungen einsetzen kann.

The post Spring Native Hands-on appeared first on JAX.

]]>
Die Vorteile der GraalVM-Native-Image-Technologie klingen verlockend: Start-up-Zeiten im Millisekundenbereich und ein deutlich reduzierter Verbrauch an Ressourcen (vor allem Speicher) – wer möchte das nicht?

Jedoch kommt diese Technologie mit einer Reihe von Einschränkungen daher. Reflection funktioniert beispielsweise in einem Native Image nur, wenn der Compiler darüber informiert wird, für welche Elemente (Klassen, Methoden, Attribute) er die Reflection-Informationen zur Compile-Zeit erzeugen und im Binary hinterlegen muss. Ähnliches gilt für Proxys, zusätzliche Ressourcen, JNI-Aufrufe und Dynamic Class Loading. Andere Techniken, wie zum Beispiel invokedynamic, funktionieren in einem Native Image grundsätzlich nicht.

Insofern kann es eine erhebliche Herausforderung sein, eine existierende Java-Anwendung in ein Native Image zu kompilieren. Zum einen muss der Code der eigenen Anwendung frei von nicht unterstützten Techniken sein, und zum anderen müssen passende Konfigurationsdateien erstellt werden, um beispielsweise Reflection zu ermöglichen. Gleiches gilt natürlich auch für alle von der eigenen Anwendung genutzten Libraries.

Was ist mit Spring-Boot-Anwendungen?

Auch für Spring-Boot-Anwendungen gilt: Sie lassen sich mit der GraalVM-Native-Image-Technologie in native Anwendungen kompilieren. Allerdings verwendet das Spring Framework viele der eben genannten Technologien relativ ausgiebig, sodass es mitunter mühsam werden kann, die nötigen Konfigurationen für den Compiler manuell zu erstellen. Grundsätzlich ist das aber möglich.

Was ist Spring Native?

Das Spring-Native-Projekt [1] ermöglicht es Entwicklern, Spring-Boot-Anwendungen mit der GraalVM-Native-Image-Technologie in Executable Binaries zu kompilieren, ohne dass die nötigen Konfigurationsdateien manuell erstellt werden müssen oder die Anwendung speziell angepasst werden muss. Im Idealfall lassen sich also bestehende Spring-Boot-Anwendungen ausschließlich durch wenige zusätzliche Build-Instruktionen zu Native Executables kompilieren (Kasten: „In drei einfachen Schritten zur fertigen Anwendung“).

In drei einfachen Schritten zur fertigen Anwendung


  • Projekt auf https://start.spring.io erzeugen (Spring Web | Spring Native) und auspacken.

  • ./mvnw spring-boot:build-image (Build ausführen, Native Image wird kompiliert, Container-Image wird erzeugt, benötigt nur Docker)

  • docker run –rm -p 8080:8080 demo:0.0.1-SNAPSHOT (Beispielanwendung starten)

Ob es Sinn ergibt, jede Spring-Boot-Anwendung zu einem Native Executable zu kompilieren, anstatt die Anwendung in einer JVM laufen zu lassen, sei einmal dahingestellt. Diese Entscheidung hat weniger mit Spring Boot selbst zu tun als vielmehr mit dem Einsatzkontext der Anwendung.

Erste Schritte mit Spring Native

Wie beginnt man neue Spring-Boot-Projekte? Natürlich auf https://start.spring.io (bzw. den entsprechenden Wizards in der eigenen Lieblings-IDE).

<dependency>
  <groupId>org.springframework.experimental</groupId>
  <artifactId>spring-native</artifactId>
  <version>0.9.2</version>
</dependency>
<plugin>
  <groupId>org.springframework.experimental</groupId>
  <artifactId>spring-aot-maven-plugin</artifactId>
  <version>0.9.2</version>
  <executions>
    <execution>
      <id>test-generate</id>
      <goals>
        <goal>test-generate</goal>
      </goals>
    </execution>
    <execution>
      <id>generate</id>
      <goals>
        <goal>generate</goal>
      </goals>
    </execution>
  </executions>
</plugin>
<plugin>
  <groupId>org.springframework.boot</groupId>
  <artifactId>spring-boot-maven-plugin</artifactId>
  <configuration>
    <image>
      <builder>paketobuildpacks/builder:tiny</builder>
      <env>
        <BP_NATIVE_IMAGE>true</BP_NATIVE_IMAGE>
      </env>
    </image>
  </configuration>
</plugin>

Als Beispiel wähle ich hier die Starter Spring Web, Spring Boot Actuator und eben Spring Native aus. Das generierte Projekt hat dann drei verschiedene Komponenten in der pom.xml-Datei, die speziell für Spring Native hinzugefügt wurden:

  1. eine zusätzliche Dependency (Listing 1)

  2. ein Build-Plug-in, das zusätzliche Informationen zur Build-Zeit erzeugt (Listing 2)

  3. ein Build-Plug-in, um ein Container-Image zu erzeugen (Listing 3)

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

Konfigurationen automatisch erzeugen

Die zusätzliche Dependency spring-native (aus Listing 1) beinhaltet vor allem die Spring-spezifische Erweiterung für den GraalVM-Native-Image-Compiler. Diese Erweiterung wird automatisch vom GraalVM-Native-Image-Compiler als Teil des Native-Image-Build-Prozesses ausgeführt.

Das neuartige Spring-AOT-Plug-in für den Build erzeugt die für das Native Image nötigen Konfigurationen automatisch während des Build-Vorgangs. Inhaltlich analysiert diese Build-Erweiterung die zu kompilierende Anwendung auf verwendete Spring-Komponenten und -Annotationen. Je nachdem, welche Spring-Bibliotheken und -Annotationen in der Anwendung verwendet werden, erzeugt Spring Native die passenden Konfigurationsdateien für den GraalVM-Native-Image-Compiler, sodass diese nicht manuell erstellt werden müssen.

Darüber hinaus kann die Spring-AOT-Erweiterung auch mit vielen Schaltern konfiguriert werden, um das Native Image noch genauer auf die eigenen Bedürfnisse zuzuschneiden. Beispielsweise lassen sich diverse Features von Spring komplett ausschalten und somit der dafür benötigte Code komplett aus dem Native Image entfernen.

Der etwas in die Jahre gekommene Support für Spring-XML-Config-Dateien ist ein gutes Beispiel dafür. Verwendet die Anwendung überhaupt keine Spring-XML-Config-Dateien, kann mit dieser Option der komplette XML-Support von Spring inkl. der dazu benötigten Dependencies gar nicht erst in das Native Image hineinkompiliert werden.

Die Spring-AOT-Erweiterung erlaubt es darüber hinaus, dem Native-Image-Support eigene sogenannte Hints mitzugeben. Diese „Hinweise“ geben dem Spring-Native-Support genaue Informationen darüber mit, welche Zusatzinformationen (beispielsweise zu Reflection) benötigt werden – sollten diese nicht automatisch identifiziert werden können.

Ein Beispiel dafür sind eigene Klassen, auf die zum Beispiel eine Library per Reflection zugreift, um sie in JSON zu transformieren.

Container-Images mit Native Executables

Spring Boot bringt schon seit einigen Versionen ein Maven-Build-Plug-in mit, welches automatisch ein Container-Image für die gebaute Spring-Anwendung erzeugt. Dieses Maven-Build-Plug-in nutzt im Hintergrund die Paketo Buildpacks [2], um aus kompilierten Spring-Boot-Anwendungen fertige Container-Images zu erzeugen.

Dieses Maven-Build-Plug-in (spring-boot-maven-plugin) kann so konfiguriert werden, dass vollautomatisch der GraalVM-Native-Image-Compiler verwendet und ein Native Executable erzeugt wird, welches dann in das Container-Image gelegt wird (anstatt eines JREs und den JAR-Dateien der Dependencys und der Anwendung selbst) – siehe Listing 3.

Ein großer Vorteil dieser Buildpack-basierten Methode ist, dass auf der lokalen Maschine kein passendes GraalVM SDK und keine Native-Image-Erweiterung installiert werden muss. Es reicht aus, die entsprechende Konfiguration (Listing 3) in die pom.xml-Datei zu integrieren und den Build auszuführen:

./mvnw spring-boot:build-image

Das Buildpack bringt das nötige GraalVM SDK automatisch mit. Das Resultat ist ein relativ kleines Container-Image. Es enthält weder ein vollständiges JRE noch die kompletten JAR-Dateien, sondern hauptsächlich das Binary der Anwendung.

Die eigentliche Größe des Binarys und dessen Speicherverbrauch im Betrieb hängt stark davon ab, wie gut und exakt zugeschnitten der Native-Image-Compiler konfiguriert wird. Je mehr Reflection-Informationen man beispielsweise konfiguriert, desto größer wird auch das Binary und desto mehr Speicher verbraucht es. Es kann sich also durchaus lohnen, möglichst wenig und möglichst genaue Reflection-Informationen zu konfigurieren, anstatt pauschal einfach alles.

Das gleiche gilt auch für die Erreichbarkeit von Code. Je genauer der Native-Image-Compiler analysieren kann, welcher Code nicht gebraucht wird, desto mehr Code wird er bei der Kompilierung des Binarys entfernen und desto weniger Ressourcen wird das Binary im Betrieb verbrauchen.

Sobald der Build das Container-Image mit dem Native Binary erzeugt hat, können wir den Container per Docker starten:

docker run --rm -p 8080:8080 rest-service:0.0.1-SNAPSHOT

Im Logoutput werden wir sehen: Die Spring-Boot-Anwendung startet innerhalb des Containers in wenigen Millisekunden.

Native Images lokal erzeugen

Ein Native Executable für eine Spring-Boot-Anwendung lässt sich auch ohne Buildpacks erzeugen. Wie im Artikel über die Native-Image-Technologie beschrieben, benötigt man dazu ein GraalVM SDK mit installierter Native Image Extension.

Anschließend lässt sich das GraalVM-Maven-Plug-in dem Build hinzufügen und passend für den Native-Image-Compiler konfigurieren (Listing 4). Zusätzlich sollte man in diesem Profil das Standardverhalten des Spring-Boot-Maven-Plug-ins leicht verändern (Listing 5), um einen Konflikt mit dem Repackaged JAR des Standard-Spring-Boot-Maven-Plug-ins zu vermeiden.

<profiles>
  <profile>
    <id>native-image</id>
    <build>
      <plugins>
        <plugin>
          <groupId>org.graalvm.nativeimage</groupId>
          <artifactId>native-image-maven-plugin</artifactId>
          <version>21.0.0.2</version>
          <configuration>
            <!-- The native image build needs to know the entry point to your application -->
            <mainClass>com.example.restservice.RestServiceApplication</mainClass>
          </configuration>
          <executions>
            <execution>
              <goals>
                <goal>native-image</goal>
              </goals>
              <phase>package</phase>
            </execution>
          </executions>
        </plugin>
      </plugins>
    </build>
  </profile>
</profiles>
<plugins>
  <!-- ... -->
  <plugin>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-maven-plugin</artifactId>
    <configuration>
      <classifier>exec</classifier>
    </configuration>
  </plugin>
</plugins>

Auch für das lokal erzeugte Native Image muss die bereits erwähnte Spring Native Dependency ergänzt werden (Listing 1) sowie die Spring-AOT-Erweiterung (Listing 2). Diese beiden Erweiterungen im Build sind also für beide Varianten (Buildpack und lokaler Build) wichtig und sinnvoll.

Der Build wird dann (im hier beschriebenen Beispiel) ausgeführt mit:

./mvnw -Pnative-image package

Daraufhin wird im target-Directory das Native Executable abgelegt, das direkt ausgeführt werden kann:

./target/demo

Dieser lokale Native-Image-Compile-Schritt läuft direkt auf der eigenen Maschine ab und verwendet das native-image-Kommando des lokal installierten GraalVM-SDKs. Führt man diesen Build also beispielsweise auf einer Windows-Maschine aus, wird ein Windows Binary erzeugt. Das ist ein bedeutender Unterschied zur Buildpack-basierten Native-Image-Kompilierung. Das Buildpack erzeugt ein Linux-basiertes Container-Image, in dem das Native Image erzeugt wird und per Docker-Runtime ausgeführt werden kann.

Die Roadmap

Die nächsten Schritte für das Spring-Native-Projekt sind zum einen, stetig weiter den Ressourcenverbrauch über die unterschiedlichsten Projekte und Bibliotheken zu reduzieren. Aktuell lassen sich zwar schon recht viele Spring-Boot-Starter-Module mit Spring Native verwenden, aber nicht alle sind schon komplett auf Speicherverbrauch und Performance optimiert. Hier liegt noch einige Arbeit vor dem Spring-Team.

Darüber hinaus arbeitet eine Reihe von Projekten daran, möglichst viel von Spring Native zu unterstützen und automatisch zur Build-Zeit zu erzeugen. Auch hier sind viele Verbesserungen zu erwarten.

Nicht zuletzt werden mit den nächsten Releases auch kontinuierlich mehr Spring-Boot-Starter-Module und deren Dependencys unterstützt werden. Die aktuelle Liste der unterstützten Module kann man in der Dokumentation einsehen [3].

Fazit

Spring Native kann für Spring-Boot-Entwickler zu einem echten Gamechanger werden. Mit Spring Native werden Entwickler von Spring-Boot-Anwendungen in die Lage versetzt, alle Vorteile der GraalVM-Native-Image-Technologie zu nutzen, ohne die Spring-Boot-Anwendungen speziell dafür zu modifizieren oder gar auf ein anderes Framework zu portieren. Existierende und bereits seit Jahren in der Entwicklung und im Einsatz befindliche Spring-Boot-Anwendungen können mit Spring Native von der neuen GraalVM-Native-Image-Technologie profitieren – und so unter Umständen erhebliche Ressourcen einsparen.

Ohne Frage, das Spring-Native-Projekt steht noch ziemlich am Anfang. Es lassen sich noch nicht alle Spring Boot Starter damit nutzen und auch von den unterstützten Projekten sind noch nicht alle komplett für diesen Einsatz optimiert. Aber die Arbeit an dem Projekt geht mit großen Schritten voran und das Ziel ist extrem vielversprechend.

Links & Literatur

[1] Spring Native: https://github.com/spring-projects-experimental/spring-native

[2] Paketo Buildpacks und Spring Boot: https://spring.io/blog/2021/01/04/ymnnalft-easy-docker-image-creation-with-the-spring-boot-maven-plugin-and-buildpacks + https://docs.spring.io/spring-boot/docs/current/reference/htmlsingle/#boot-features-container-images-buildpacks

[3] https://docs.spring.io/spring-native/docs/current/reference/htmlsingle/#support-spring-boot

The post Spring Native Hands-on appeared first on JAX.

]]>
Spring Boot vs. Eclipse MicroProfile: Microservices-Frameworks im Vergleich https://jax.de/blog/microservices/spring-boot-vs-eclipse-microprofile-microservices-frameworks-im-vergleich/ Mon, 08 Apr 2019 10:51:54 +0000 https://jax.de/?p=67592 Microservices werden im Java-Umfeld immer öfter mit Spring Boot gebaut. Wer aus dem Java-EE- bzw. Jakarta-EE-Lager kommt, hat mit dem Eclipse MicroProfile eine Alternative zur Hand. Wo liegen die Gemeinsamkeiten, wo die Unterschiede?

The post Spring Boot vs. Eclipse MicroProfile: Microservices-Frameworks im Vergleich appeared first on JAX.

]]>

Wir haben mit Tim Zöller, Entwickler bei der ilum:e informatik ag und Sprecher auf der JAX 2019, über den alten Gegensatz „Spring versus Java EE“ gesprochen. Kommt es im Zeichen der Microservices zu einer Neuauflage unter dem Banner „MicroProfile versus Spring Boot“?

Spring Boot oder Eclipse MicroProfile: Microservices-Frameworks im Vergleich

JAX: Hallo Tim, vielen Dank, dass du dir die Zeit für dieses Interview genommen hast! Im Enterprise-Bereich war die Java-Welt ja viele Jahre lang von zwei Frameworks dominiert: Spring und Java EE. Beide hatten den möglichst kompletten Java-Application-Server als zentrale Metapher. Hat diese Metapher in Zeiten von Microservices & Serverless ausgedient?

Tim Zöller: Ich glaube nicht, dass wir die Application Server in näherer Zukunft verschwinden sehen werden. Sie vereinen eine Vielzahl erprobter APIs und Implementierungen in sich, die man aus sehr schlank gebauten WARs heraus benutzen kann. Das ermöglicht beispielsweise auf effiziente Art und Weise, Docker Images aufzubauen und zu pushen, was einigen Unternehmen wichtig ist.

JAX: Wie bewertest du die jüngsten Entwicklungen um Java EE, d.h. den Umzug zur Eclipse Foundation unter dem neuen Namen Jakarta EE? Wird der Java-Enterprise-Standard dadurch beflügelt? Oder handelt es sich eher um ein Auslaufmodell?

Tim Zöller: Ich sehe es als einen positiven Schritt, und die meisten Menschen, mit denen ich bisher darüber gesprochen habe, ebenfalls. Es ist momentan sehr spannend zu sehen, wie die Spezifikation in die Hände der Community übergeht. Die rechtlichen Probleme, die mit der Übertragung von Oracle an die Eclipse Foundation einhergehen, werfen momentan einen Schatten auf den Umzug.

Es gibt beispielsweise immer noch Unklarheiten, wenn es um Namensrechte geht. Offensichtlich wurde das durch die notwendige Umbenennung von Java EE zu Jakarta EE. Im Detail stellt es aber auch ein Problem dar, dass Klassen im Package javax.* von der Übergabe an die Eclipse Foundation betroffen sind. Diese Unsicherheiten sorgen dafür, dass sich einige Mitglieder der Community noch nicht trauen, ihre Mitarbeit zu starten.

Ich glaube nicht, dass die Application Server in näherer Zukunft verschwinden werden.

 

Microservices: Spring Boot versus Eclipse MicroProfile

JAX: Wer neue Java-Anwendungen im Cloud- und Microservices-Kontext baut, greift heute immer mehr zu Spring Boot. Weshalb eigentlich? Wo liegen die Stärken von Spring Boot im Vergleich zum Ansatz des klassischen Spring Frameworks und Java EE?

Tim Zöller: Mit dem Konzept der Spring Boot Starter und dem einfachen Aufsetzen einer neuen Anwendung wurde zunächst einmal ein gewaltiger Konfigurations-Overhead abgeschafft. Die Möglichkeit, ein einzelnes, ausführbares JAR zu erzeugen und die Applikation extern zu konfigurieren, erhöht die Flexibilität in der Entwicklung und im Deployment. Eingebaute Health-Checks und Metriken machen den Betrieb leichter.

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

JAX: Mit dem Eclipse MicroProfile hat sich ein eher wieder an Java EE bzw. Jakarta EE angelehnter Konkurrent zu Spring Boot herausgebildet. Was haben die beiden Projekte gemeinsam?

Tim Zöller: Enorm viel. Zum einen versucht MicroProfile, genau die Konzepte abzudecken, die Spring Boot erfolgreich machen: geringe Konfiguration, Health Checks, Metriken, Resilience-Maßnahmen – viele Features, die den Betrieb von mehreren, vernetzten Services in der Cloud vereinfachen. Wenn man die gleichen Dinge mit beiden Frameworks umsetzt, fällt sehr schnell auf, dass auch die Konzepte ähnlich umgesetzt sind: REST Clients in MicroProfile sehen beispielsweise OpenFeign REST Clients aus Spring Boot sehr ähnlich, Spring REST Controller werden fast gleich aufgebaut wie REST Services mit JAX-RS. Das setzt sich in den meisten Konzepten fort.

Eclipse MicroProfile und Spring Boot haben enorm viel gemeinsam.

 

JAX: Und wo liegen die Unterschiede?

Tim Zöller: Technisch liegen die Unterschiede darin, dass MicroProfile lediglich das API definiert, welches von den verschiedenen Herstellern umgesetzt wird, etwa von OpenLiberty, Thorntail oder Payara Micro. Das API versucht, hierbei sämtliche Themen zu erfassen: REST Clients, REST Services, Fault Tolerance, Configuration, Health, Metrics, usw. Bei Spring Boot existieren diese Konzepte auch, aber als Bibliotheken im Spring-Boot- oder Spring-Cloud-Umfeld, die Entwickler bei Bedarf in die Anwendung einbinden können. Ein weiterer Unterschied ist, dass MicroProfile komplett im Besitz einer offenen Community ist, welche den Standard vorantreibt.

Spring oder Java EE – der alte Kampf?

JAX: Zurück zum alten Gegensatz Spring versus Java EE: Läuft es aus deiner Sicht nun auf eine Neuauflage unter dem Banner Spring Boot versus Eclipse MicroProfile hinaus?

Tim Zöller: Ich glaube nicht, dass diese Diskussion wieder so grundsätzlich aufkommt. Anwendungslandschaften sind heute homogener als damals. Wenn man 25 Services in Produktion laufen hat, spricht nichts dagegen, die einen in Spring Boot und die anderen mit MicroProfile umzusetzen. Die Kommunikation erfolgt ohnehin über definierte Protokolle.

Spring Boot hat bereits ein gigantisches Ökosystem, welches fertige Lösungen für viele Anwendungsfälle, gerade in der Cloud, bereitstellt. Diese haben sich oft schon in ganz großen Maßstäben bewiesen, z.B. im Einsatz bei Netflix. Wenn Service Discovery, clientseitiges Loadbalancing und eine Einbindung in spezielle Monitoring-Systeme gefragt sind, ist Spring Boot nahezu konkurrenzlos.

Allerdings verlagern sich ebendiese Funktionen zunehmend in die Infrastruktur und werden, z.B. bei einem Einsatz auf Kubernetes, seltener in die Applikation eingebaut. Die Stärke von MicroProfile liegt darin, dass es nur einen Standard beschreibt, keine Implementierung. Neben den „üblichen Verdächtigen“ wie OpenLiberty, Thorntail oder Payara Micro ist es auch möglich, eine Applikation, die gegen diesen Standard entwickelt wurde, auf Implementierungen ausführen zu lassen, die speziell für kleine und schnelle Programme entwickelt wurden. Beispiele sind hier KumuluzEE oder Quarkus.

Sowohl Spring Boot als auch Eclipse MicroProfile stellen großartige Tools bereit.

 

JAX: In deiner JAX-Session Eclipse MicroProfile vs. Spring Boot: getting back in the Ring! nimmst du beide Frameworks genauer unter die Lupe. Was ist die zentrale Botschaft, die du den Teilnehmern mit auf den Weg geben möchtest?

Tim Zöller: Sowohl Spring Boot als auch Eclipse MicroProfile stellen großartige Tools bereit, um die Entwicklung von schlanken, leicht konfigurier- und wartbaren Anwendungen zu ermöglichen. Es ist eher eine Geschmacksfrage als ein „richtig“ oder „falsch“.

JAX: Vielen Dank für dieses Interview!

Die Fragen stellte Hartmut Schlosser

Java-Dossier für Software-Architekten 2019


Mit diesem Dossier sind Sie auf alle Neuerungen in der Java-Community vorbereitet. Die Artikel liefern Ihnen Wissenswertes zu Java Microservices, Req4Arcs, Geschichten des DevOps, Angular-Abenteuer und die neuen Valuetypen in Java 12.

Java-Wissen sichern!

The post Spring Boot vs. Eclipse MicroProfile: Microservices-Frameworks im Vergleich appeared first on JAX.

]]>
Spring Boot als Beispiel für DDD Strategic Design https://jax.de/blog/software-architecture-design/spring-boot-ddd-strategic-design/ Tue, 18 Jul 2017 15:41:21 +0000 https://jax.de/?p=48946 Einer der wertvollsten Bereiche von Domain-driven Design ist zweifelsohne das Strategic Design mit seinen Context-Mapping-Patterns. Finden Sie auch, dass die meisten Beschreibungen der Patterns etwas abstrakt und schwer verdaulich sind?
Michael Plöd hilft weiter!

The post Spring Boot als Beispiel für DDD Strategic Design appeared first on JAX.

]]>
Spring Boot als Beispiel für DDD Strategic Design

Im Rahmen dieses Vortrags von der JAX 2017 stellt Michael Plöd die Patterns auf Basis einer einfachen Spring-Boot-basierten Anwendungslandschaft vor. Hierbei geht er unter anderem auf folgende Patterns ein: Customer/Supplier, Open Host Language, Anti-Corruption Layer, Conformist oder Separate Ways.

Spring Boot als Beispiel für DDD Strategic Design from JAX TV on Vimeo.

 

The post Spring Boot als Beispiel für DDD Strategic Design appeared first on JAX.

]]>