Entwicklung & Code
Deep Dive Spring Modulith Teil 2: Event-Mechanismen und Teststrategien
Events sind in Spring Modulith ein zentrales Mittel zur losen Kopplung zwischen Modulen. Sie lassen sich zeitgesteuert auslösen, an externe Systeme weiterreichen und gezielt testen. Nachdem im ersten Teil die fachliche Zerlegung einer Spring Boot-Anwendung in klar abgegrenzte Module im Mittelpunkt stand, geht es nun um weitere Event-Mechanismen sowie um Teststrategien, mit denen sich einzelne Module isoliert und realitätsnah überprüfen lassen.
Weiterlesen nach der Anzeige

Nils Hartmann ist freiberuflicher Softwareentwickler und Coach mit den Schwerpunkten Java im Backend und React im Frontend, wozu er auch Workshops und Trainings gibt.
Wenn die Zeit vergeht – zeitgesteuerte Events
Das Beispiel des Portals zur Pflanzenpflege hat bislang Events demonstriert, die Aktionen durchführen, nachdem eine fachliche Verarbeitung („Pflanze registriert“) erfolgt ist. Daneben gibt es oft auch Aktionen, die zeitgesteuert ausgeführt werden sollen. Zum Beispiel sollen jeden Monat Rechnungen für alle Kunden erzeugt und verschickt werden. Zeitgesteuerte Aktionen lassen sich in Spring Boot mit der Annotation @Scheduled umsetzen. Dieser wird beispielsweise ein cron-Ausdruck übergeben, der festlegt, wann die annotierte Methode ausgeführt wird. Solche Methoden lassen sich jedoch schwer testen. Im beschriebenen Beispiel müsste der Test zum Erzeugen von Rechnungen die Zeit künstlich setzen, um dafür zu sorgen, dass Spring die zeitgesteuerte Methode aufruft. Zudem ist ein cron-Ausdruck weniger ausdrucksstark, da er Zeitpunkte („jeweils am Monatsersten um 3 Uhr“) aber keine Ereignisse („Monatswechsel ist erfolgt“) angibt.
Mit der Moments-API, als Bestandteil von Spring Modulith, gibt es einen weiteren Weg, wiederkehrende Aktionen auszuführen. Sie besteht aus einer Reihe von Events, die Spring Modulith am Ende eines Zeitraums (z. B. Stunden-, Tages- oder Quartalswechsel) auslöst und die von der Anwendung konsumiert werden können. So lässt sich beispielsweise beim Monatswechsel auf das Event MonthHasPassed reagieren. Die Verarbeitung erfolgt wie bei regulären Events, in einer mit @EventListener annotierten Methode, die als Argument den gewünschten Event-Typen entgegennimmt. Listing 1 zeigt die Verwendung exemplarisch für den InvoiceGenerator, der beim Monatswechsel die Rechnungen erzeugt.
Listing 1: Der InoviceGenerator wird beim Monatswechsel über das MomentHasPassed-Event getriggert
package nh.demo.plantify.billing.invoice;
import org.springframework.context.event.EventListener;
import org.springframework.modulith.moments.MonthHasPassed;
// ...
@Component
class InvoiceGenerator {
// ...
@EventListener
@Transactional
void generateInvoices(MonthHasPassed event) {
var month = event.getMonth();
// Rechnungen für den Monat month erzeugen
// ...
}
}
Vorteil an dieser Variante ist, dass der Code mit den Moments Events nicht nur verständlicher ist, als bei der Verwendung von @Scheduler, die Events liefern auch nützliche Informationen (z. B. welcher Monat abgelaufen ist). Das Bean TimeMaschine, das Spring Modulith automatisch im Application Context registriert, löst die Events aus. Für Tests lässt sich deren Zeit künstlich weiterstellen. Alle Events, die normalerweise in diesem vorgespulten Zeitraum ausgelöst würden, werden damit auch im Test ausgelöst.
Weiterlesen nach der Anzeige
Events für externe Systeme veröffentlichen
Die Anwendung nutzt den ApplicationEventPublisher, um fachliche Events innerhalb der Anwendung zu veröffentlichen. Mit Spring Modulith lassen sich darüber Events auch an externe Systeme wie Kafka, RabbitMQ oder einen JMS Server übergeben. Dafür stellt Spring Modulith Broker-spezifische Starter-Module zur Verfügung, die sich über die Maven- oder Gradle-Konfiguration der Anwendung einbinden lassen.
Die Annotation @Externalized an einer Event-Klasse drückt aus, dass das Event an ein externes System geschickt werden soll. Listing 2 zeigt das InvoiceCreatedEvent, das die Anwendung an Kafka schickt. Das target-Attribute enthält einen Broker-spezifischen Ausdruck, der angibt, wie das Event geroutet werden soll. Im Beispiel wird das Event an das Kafka-Topic invoices geschickt, wobei die im Event enthaltene ownerId den Message Key bildet.
Listing 2: Ein Application Event, das über Kafka veröffentlicht wird
package nh.demo.plantify.billing.invoice;
import org.springframework.modulith.events.Externalized;
// ...
@Externalized(target = "invoices::#{#this.ownerId()}")
public record InvoiceGeneratedEvent(
UUID ownerId,
YearMonth billingPeriod,
BigDecimal amount
) { }
In der kommenden Version 2.1 implementiert Spring Modulith das Outbox-Pattern für das Versenden von @Externalized-Events. Damit stellt es sicher, dass jedes Event mindestens einmal erfolgreich an das externe System übermittelt wurde. Dazu wird intern das Framework Namastack verwendet, das eine Implementierung des Outbox-Patterns für Spring Boot-Anwendungen bereitstellt. Um das Verhalten für die eigene Anwendung zu aktivieren, muss lediglich eine Spring Property gesetzt werden. Im Rahmen der Ankündigung dieses Features hat sich eine interessante Diskussion über die konkrete Implementierung durch Namastack und deren Konsequenzen zwischen Roland Beisel (Lead von Namastack Outbox) und Gunnar Morling (ehem. Tech-Lead von Debezium) entwickelt.
Eine Anwendung kann im Rahmen einer fachlichen Verarbeitung sowohl Daten in der eigenen Datenbank speichern als auch ein Event an ein externes System schicken (@Externalized). Allerdings ist der Versand eines externen Events nicht Bestandteil der Datenbank-Transaktion. Wenn die Transaktion also erfolgreich committed wurde, dann aber das Event nicht zugestellt werden kann (z. B. weil es Verbindungsprobleme zum Message Broker gibt), ist das Event verloren. Im Beispiel hätte die Anwendung eine Rechnung erzeugt und gespeichert, die aber nicht per Event zugestellt wurde.
Auch wenn man die Reihenfolge umdrehen würde, also erst auf die erfolgreiche Abgabe des Events wartet und die Anwendung danach die Transaktion committed, kann es zu einer Inkonsistenz kommen. In dieser Konstellation ist es möglich, dass das Event an das externe System abgegeben wird, danach die Anwendung aber ihre Transaktion nicht committen kann. Dann kann Spring das verschickte Event nicht zurückholen. In der Beispiel-Anwendung bedeutet dass, dass das externe System eine Rechnung erhält, die in der Anwendung gar nicht bekannt ist.
Um dieses Problem zu lösen, kann eine Anwendung das Outbox-Pattern verwenden. Dann sendet die Anwendung das Event nicht sofort, sondern speichert das Event beim Commit der Transaktion zunächst gemeinsam mit den anderen Daten in der Datenbank in einer eigenen Tabelle. Diese Tabelle dient als Postausgangskorb („Outbox“). Erst danach versucht die Anwendung in einer neuen Transaktion, das Event aus der Outbox-Tabelle zuzustellen. Wenn dabei ein Fehler auftritt, verbleibt das Event in der Tabelle, sodass die Anwendung später erneut dessen Zustellung versuchen kann. Sobald die Anwendung das Event erfolgreich versenden konnte, entfernt sie es aus der Datenbank und schließt die Transaktion ab. Kommt es dabei zu einem Fehler, sodass die Transaktion nicht committed werden kann, verbleibt das Event in der Outbox-Tabelle, obwohl es zuvor erfolgreich an das externe System gesendet wurde. Da das Event weiterhin in der Outbox-Tabelle liegt, wird die Anwendung beim nächsten Durchlauf erneut versuchen, es zu versenden. Dadurch erhält der Empfänger das Event zwar möglicherweise mehr als einmal, aber auf diese Weise kann die Anwendung garantieren, dass es mindestens einmal zugestellt wird und nicht gänzlich verloren geht („At least once“-Semantik). Der Empfänger muss also damit rechnen, ein Event mehrfach zu erhalten und bei der Verarbeitung doppelte Events beispielsweise ignorieren (Idempotenz). Dabei handelt es sich um ein typisches Muster in verteilten Systemen, in denen echte systemübergreifende Transaktionen nicht möglich oder nur sehr aufwendig sind.
Modularisierte Datenbankmigrationen
Bis hierhin lag der Fokus auf der Aufteilung des Java-Codes in abgeschlossene Application Modules. Oft gehören zu einer Anwendung aber auch Migrationsskripte für die Datenbank, die beispielsweise Flyway verwaltet. Spring Boot führt diese beim Starten der Anwendung automatisch aus und sorgt dafür, dass die Datenbank auf einem für die aktuelle Version der Anwendung passenden Stand ist. Typischerweise finden sich die Flyway-Skripte einer Anwendung in einem zentralen migration-Verzeichnis als Dateien mit einer Versionsnummer im Namen. Die zentrale Verwaltung und Versionierung der Migrationsskripte widersprechen allerdings der Idee der Modularisierung.
Aus diesem Grund bietet Spring Modulith die Möglichkeit, die Skripte nicht nur zentral, sondern pro Modul abzulegen und zu versionieren. So kann jedes Modul seine eigene Historie von Migrationsskripten pflegen. Die übergeordnete Reihenfolge ergibt sich aus den Modulabhängigkeiten. Die modulspezifischen Flyway-Dateien gilt es in einem Unterordner abzulegen, der genauso wie das entsprechende Modul heißt. Zusätzlich kommt das Verzeichnis __root zum Einsatz, in dem globale Migrationsskripte ihren Platz finden. Die Anwendung führt die Skripte in diesem Verzeichnis immer als Erstes aus. Abbildung 1 zeigt die Migrationsskripte von Plantify.

Modularisierte Flyway Migrationsskripte für die Datenbank (Abb. 1)
(Bild: Nils Hartmann)
Damit die Modulstruktur auch in der Datenbank eingehalten wird, definiert jedes Modul sein eigenes Datenbankschema in Postgres. Im __root-Ordner befinden sich die Skripte zum Anlegen der Tabellen für die Event Publication Registry. In einem Integrationstest führt Spring Modulith immer nur die Skripte aus, deren Modul gerade getestet wird, und stellt damit sicher, dass es keine unerwünschten Referenzen zwischen den Skripten gibt.
Entwicklung & Code
Gemini für Android wird agentisch: KI bestellt Essen oder einen Fahrdienst
Gemini für Android wird agentisch: Zunächst sollen Nutzer eines Pixel 10 oder Galaxy S26 – in den USA und in Korea – den Chatbot zum Bestellen von Fahrdiensten, Lebensmitteln oder anderen Einkäufen nutzen können. Laut Android-Chef Sameer Samat ist das nur der Anfang: Mit Android 17 plant Google eine Erweiterung der agentischen Funktionen.
Weiterlesen nach der Anzeige
Vorschau
Samat schreibt auf Linkedin vollmundig: „Wir bewegen uns weg von einem Betriebssystem hin zu einem intelligenten System, einer Plattform, die Sie wirklich versteht und für Sie arbeitet.“ Mit der Präsentation der agentischen Fähigkeiten zur Ausführung mehrstufiger Aufgaben hat Google lediglich „eine erste Vorschau auf eine dieser Funktionen vorgestellt“. Dabei arbeite Android mit dem KI-Assistenten zusammen, um Apps zu navigieren und Aufgaben zu erledigen.
Als Beispiel nennt Samat die Möglichkeit, eine lange Liste von Zutaten aus einem Rezept zu nehmen und diese in den Warenkorb in der bevorzugten Lebensmittel-Liefer-App zu legen. „Gemini 3 nutzt seine Denkfähigkeiten, um einen Plan zu erstellen, und seine multimodalen Fähigkeiten, um mit Android zu arbeiten und die App zu bedienen, um die Aufgabe zu erledigen“, erklärt er weiter. Im Android-Developer-Blog liefert Google das Beispiel einer Pizzabestellung: Gemini erfasst die in einem Chat gesammelten Bestellwünsche und öffnet die App des Lieferdienstes, um die Bestellung auszuführen.

Gemini bestellt Pizza.
(Bild: Google)
Die App werde anschließend in einem abgesicherten virtuellen Fenster geöffnet und laufe im Hintergrund, erklärt Google in einem Blogbeitrag. Das bedeutet, dass Gemini nur auf bestimmte Apps zugreifen kann, nicht aber auf das komplette Gerät. Nutzerinnen und Nutzer können ihr Smartphone während der Ausführung der Aufgabe für andere Dinge weiterverwenden. Da die Funktion mit „Blick auf Transparenz und Kontrolle entwickelt“ wurde, können Nutzer Gemini bei jedem Schritt beobachten und jederzeit pausieren, stoppen oder die Aufgabe übernehmen. Die Anwendung sei außerdem so konzipiert, dass Nutzer benachrichtigt werden, wenn die Bestellung zur Überprüfung bereitstehe, um sie sich abschließend anzusehen und zu bezahlen. Die Bezahlung erfolgt also noch vom Nutzer und ist nicht automatisiert.
AppFunctions
Weiterlesen nach der Anzeige
Laut Google kann die App-Automatisierung über zwei Wege durchgeführt werden: Zum einen mit AppFunctions, die schon im vergangenen Jahr mit Android 16 angekündigt wurden, nun aber offenbar erst Einzug hält. Wie das Unternehmen erklärt, werden die AppFunctions von einer Jetpack-Bibliothek begleitet, mit der Apps bestimmte Funktionen für Anrufer wie Agent-Apps verfügbar machen können, damit diese auf dem Gerät darauf zugreifen und sie ausführen können.
Als Beispiel nennt Google die Integration der AppFunctions in die Samsung-Gallery-App im Galaxy S26: Anstatt manuell durch Fotoalben zu scrollen, können Nutzerinnen und Nutzer Gemini einfach bitten: „Zeig mir Bilder meiner Katze aus der Samsung Gallery.“ Gemini aktiviert die entsprechende Funktion und präsentiert die gewünschten Fotos aus der Samsung Gallery direkt in der Gemini-App, sodass Nutzer diese nie verlassen müssen. Ähnliches will auch Samsung mit seinem Assistenten Bixby in Partnerschaft mit Perplexity erreichen.

Gemini sucht Bilder aus der Samsung-Gallery-App und zeigt sie in der Gemini-App.
(Bild: Google)
Die Funktion ist Teil von One UI 8.5 und soll nach dem Galaxy S26 auch auf weitere Samsung-Geräte kommen. Über AppFunctions soll Gemini schon Aufgaben in verschiedenen App-Kategorien wie Kalender, Notizen und Aufgaben auf Geräten verschiedener Hersteller automatisieren, so Google.
Der zweite Weg der Automation ist noch in der Entwicklung: Dabei handelt es sich um ein UI-Automatisierungsframework für KI-Agenten und -Assistenten. Dieses soll „allgemeine Aufgaben in den installierten Apps der Benutzer intelligent ausführen“ können – und wird im Galaxy S26 beziehungsweise Pixel 10 als Beta getestet. „Diese Plattform übernimmt die Schwerarbeit, sodass Entwickler ohne Programmieraufwand eine große Reichweite erzielen können“, erklärt das Unternehmen. T
Mit Android 17 soll das UI-Automatisierungsframework erweitert werden, „um noch mehr Nutzer, Entwickler und Gerätehersteller zu erreichen“. Derzeit arbeite Google mit einer kleinen Gruppe von App-Entwicklern daran. Dabei konzentriere man sich auf hochwertige Benutzererfahrungen, während sich das Ökosystem weiterentwickelt. Google will im Laufe dieses Jahres weitere Details darüber veröffentlichen, wie Entwicklerinnen und Entwickler AppFunctions und UI-Automatisierung nutzen können.
Android 17 ist derzeit noch in der Betaphase, die finale Version wird im Juni dieses Jahres erwartet. Vorher dürfte Google die hauseigene Entwicklerkonferenz Google I/O am 19. und 20. Mai nutzen, um weitere Details der agentischen Fähigkeiten zu demonstrieren. Erst dann dürften wir erfahren, ob diese Funktion auch zeitnah in Deutschland bereitgestellt wird.
(afl)
Entwicklung & Code
software-architektur.tv: Programmierung als Theoriebildung | heise online
Der Informatikpionier Peter Naur formulierte 1985 in seinem Aufsatz „Programming as Theory Building“ die These, dass Programmieren im Kern bedeutet, eine Theorie zu entwickeln – als tiefes Verständnis eines Problems und als seine Lösung. Diese Perspektive erklärt, warum Änderungen an bestehenden Systemen so schwierig sind, wie Legacy-Software entsteht, und weshalb iterative Softwareentwicklung so wirkungsvoll sein kann.
Weiterlesen nach der Anzeige
In dieser Episode von software-architektur.tv diskutiert Eberhard Wolff Naurs Überlegungen und bezieht sie zu aktuellen Herausforderungen der Softwareentwicklung – etwa zur verbreiteten Vorstellung im Kontext generativer KI, Programmieren bestehe primär lediglich im Erzeugen von Code.
Livestream am 27. Februar
Die Ausstrahlung findet am Freitag, 27. Februar 2026, live ab 13 Uhr statt. Die Folge steht im Anschluss als Aufzeichnung bereit. Während des Livestreams können Interessierte Fragen via Twitch-Chat, YouTube-Chat oder anonym über das Formular auf der Videocast-Seite einbringen.
software-architektur.tv ist ein Videocast von Eberhard Wolff, iX-Blogger und bekannter Softwarearchitekt, der als Head of Architecture bei SWAGLab arbeitet. Zum Team gehören außerdem Lisa Maria Schäfer (Socreatory) und Ralf D. Müller (DB Systel). Seit Juni 2020 sind über 250 Folgen entstanden, die unterschiedliche Bereiche der Softwarearchitektur beleuchten – mal mit Gästen, mal Wolff, Schäfer oder Müller solo. Seit mittlerweile mehr als zwei Jahren berichtet heise Developer über die Episoden.
(map)
Entwicklung & Code
Deno 2.7 schärft Node.js-Kompatibilität und stabilisiert Temporal
Mit Deno 2.7 veröffentlicht das Team ein Update, das sowohl Web-Standards als auch die Node.js-Kompatibilität weiter voranbringt. Im Mittelpunkt stehen die Stabilisierung der Temporal API und eine erweiterte Kontrolle über Abhängigkeiten in package.json. Daneben liefert das Release offizielle Builds für Windows on ARM, zahlreiche Node.js-Fixes sowie ein Upgrade auf V8 14.5.
Weiterlesen nach der Anzeige
Temporal API jetzt ohne Flag nutzbar
Mit Deno 2.7 verlässt die Temporal-API den experimentellen Status. Das bisher notwendige Flag --unstable-temporal entfällt. Damit folgt Deno der Entwicklung im V8-Ökosystem: Seit Chrome 144 (Januar 2026) ist die Temporal API ebenfalls standardmäßig verfügbar, nun holt Deno im Zuge des Upgrades auf V8 14.5 auf.
Ein Beispiel aus dem Ankündigungsbeitrag soll die Neuerung verdeutlichen:
const today = Temporal.Now.plainDateISO();
const nextMonth = today.add({ months: 1 }); // immutable - today unchanged
const meeting = Temporal.ZonedDateTime.from(
"2026-03-15T14:30[America/New_York]",
);
const inTokyo = meeting.withTimeZone("Asia/Tokyo"); // same instant
Die Temporal-API soll die bekannten Schwächen des Date-Objekts beheben und bietet klar definierte Typen für Zeitpunkte, Datumsangaben, Zeitspannen und Zeitzonen. Entwicklerinnen und Entwickler erhalten damit präzisere Werkzeuge für komplexe Datums- und Zeitberechnungen – etwa bei wiederkehrenden Terminen, internationalen Anwendungen oder der Verarbeitung von Zeitstempeln mit Zeitzonenbezug.
Für Deno-Projekte bedeutet die Stabilisierung vor allem Planungssicherheit: Anwendungen können die Temporal-API produktiv einsetzen, ohne mit API-Änderungen rechnen zu müssen. Gleichzeitig soll sich die Interoperabilität mit modernen Browser-Umgebungen verbessern.
(Bild: jaboy/123rf.com)

Tools und Trends in der JavaScript-Welt: Die enterJS 2026 wird am 16. und 17. Juni in Mannheim stattfinden. Das Programm dreht sich rund um JavaScript und TypeScript, Frameworks, Tools und Bibliotheken, Security, UX und mehr. Frühbuchertickets sind im Online-Ticketshop erhältlich.
Feingranulare Kontrolle mit package.json-Overrides
Weiterlesen nach der Anzeige
Ein zweites zentrales Feature ist die Unterstützung des overrides-Felds in der package.json. Deno baut damit seine Unterstützung für Node.js-Projekte weiter aus. Ziel bleibt laut Ankündigungsbeitrag, bestehende Node.js-Anwendungen mit möglichst wenigen Anpassungen unter Deno lauffähig zu machen.
Mit overrides lassen sich Versionen transitiver Abhängigkeiten gezielt überschreiben. Entwickler können so etwa eine verwundbare Unterabhängigkeit global auf eine sichere Version festnageln oder eine bestimmte Version erzwingen, wenn es Inkompatibilitäten gibt. Auch das vollständige Ersetzen einzelner Pakete innerhalb des Abhängigkeitsbaums ist möglich.
Gerade in größeren Projekten mit tief verschachtelten Dependency-Trees soll das die Kontrolle erheblich erhöhen. Sicherheits-Patches lassen sich schneller durchsetzen, ohne auf Upstream-Updates warten zu müssen. Für Teams mit strengen Compliance-Vorgaben ist das ein wichtiger Baustein.
Windows on ARM und mehr Node.js-Kompatibilität
Neben den beiden Kernneuerungen liefert Deno 2.7 erstmals offizielle Builds für Windows on ARM (aarch64-pc-windows-msvc). Auf Geräten wie dem Surface Pro X oder Snapdragon-basierten Notebooks läuft Deno damit nativ – ohne Emulationsschicht und die damit verbundenen Performance-Einbußen.
Auch bei der Node.js-Kompatibilität legt das Team deutlich nach. Zahlreiche Anpassungen in node:worker_threads, node:child_process, node:zlib oder node:sqlite schließen Lücken zum Node.js-Verhalten. Ergänzt wird das durch neue oder angepasste APIs wie navigator.platform, SHA3-Unterstützung in der Web Crypto API oder Brotli-Support in CompressionStream und DecompressionStream.
Nähere Informationen bietet der Blogbeitrag. Wer Deno bereits nutzt, aktualisiert wie gewohnt per deno upgrade. Erst Anfang Februar hatte Deno zudem seine Serverless-Plattform Deno Deploy allgemein verfügbar gemacht und damit das Ökosystem rund um die Runtime strategisch ausgebaut.
(mdo)
-
Künstliche Intelligenzvor 2 MonatenSchnelles Boot statt Bus und Bahn: Was sich von London und New York lernen lässt
-
Social Mediavor 2 WochenCommunity Management zwischen Reichweite und Verantwortung
-
Apps & Mobile Entwicklungvor 3 MonatenHuawei Mate 80 Pro Max: Tandem-OLED mit 8.000 cd/m² für das Flaggschiff-Smartphone
-
Datenschutz & Sicherheitvor 3 MonatenSyncthing‑Fork unter fremder Kontrolle? Community schluckt das nicht
-
Entwicklung & Codevor 3 MonatenKommentar: Anthropic verschenkt MCP – mit fragwürdigen Hintertüren
-
Künstliche Intelligenzvor 1 Woche
Top 10: Die beste kabellose Überwachungskamera im Test – Akku, WLAN, LTE & Solar
-
Künstliche Intelligenzvor 3 MonatenGame Over: JetBrains beendet Fleet und startet mit KI‑Plattform neu
-
Social Mediavor 2 MonatenDie meistgehörten Gastfolgen 2025 im Feed & Fudder Podcast – Social Media, Recruiting und Karriere-Insights
