Warum ArC DI? Nun, mein Freund, ArC (ArC steht für "CDI in ArC") ist Quarkus' eigenes Dependency-Injection-Framework, das speziell dafür entwickelt wurde, leichtgewichtig und blitzschnell zu sein. Es ist wie CDI auf Steroiden, aber ohne die unangenehmen Nebenwirkungen.
Hier ist, warum ArC DI dein neuer bester Freund für asynchrone EDAs ist:
- Kompilierungszeit-Optimierung: ArC verarbeitet die meisten seiner Magie zur Build-Zeit, was die Laufzeitbelastung reduziert.
- Optimiert für Quarkus: Es ist maßgeschneidert für Quarkus, was nahtlose Integration und optimale Leistung gewährleistet.
- Verbesserte Ereignisverarbeitung: ArC bietet spezialisierte Funktionen für ereignisgesteuerte Architekturen, die über das Standard-CDI hinausgehen.
Einrichten Ihres Quarkus-Projekts
Zuallererst, lassen Sie uns ein Quarkus-Projekt mit ArC DI einrichten. Wenn Sie von Grund auf neu beginnen, verwenden Sie die Quarkus-CLI:
quarkus create app org.acme:async-eda-demo
cd async-eda-demo
ArC DI ist in Quarkus enthalten, sodass Sie keine zusätzlichen Abhängigkeiten hinzufügen müssen. Für unser asynchrones EDA benötigen wir jedoch die reaktive Messaging-Erweiterung:
./mvnw quarkus:add-extension -Dextensions="quarkus-smallrye-reactive-messaging"
Verkabelung von Ereignissen mit ArC DI
Nun, lassen Sie uns mit etwas Ereignisverkabelung loslegen. ArC DI macht es einfach, Ereignisse asynchron zu erstellen und zu verarbeiten. Hier ist ein einfaches Beispiel:
import io.quarkus.arc.Arc;
import javax.enterprise.event.Event;
import javax.inject.Inject;
public class OrderService {
@Inject
Event orderCreatedEvent;
public void createOrder(Order order) {
// Bestellung verarbeiten
orderCreatedEvent.fire(new OrderCreatedEvent(order));
}
}
public class OrderEventHandler {
public void onOrderCreated(@Observes OrderCreatedEvent event) {
// Ereignis asynchron verarbeiten
CompletableFuture.runAsync(() -> {
// Asynchrone Operationen durchführen
System.out.println("Bestellung erstellt: " + event.getOrder().getId());
});
}
}
In diesem Beispiel verwenden wir das Ereignissystem von ArC, um die Auftragserstellung von ihren Nebeneffekten zu entkoppeln. Der OrderService
löst ein Ereignis aus, und der OrderEventHandler
verarbeitet es asynchron.
Verwalten von Kontext in asynchronen Operationen
Einer der kniffligsten Teile von asynchronen EDAs ist das Verwalten von Kontexten über verschiedene Threads hinweg. ArC DI kommt mit seinen leistungsstarken Kontextübertragungsfunktionen zur Rettung. Schauen wir uns an, wie wir dies nutzen können:
import io.quarkus.arc.Arc;
import io.quarkus.arc.ArcContainer;
public class ContextAwareAsyncService {
public CompletableFuture performAsyncOperation() {
ArcContainer container = Arc.container();
return CompletableFuture.runAsync(() -> {
try {
container.requestContext().activate();
// Ihre asynchrone Logik hier
} finally {
container.requestContext().terminate();
}
});
}
}
Dieses Snippet zeigt, wie man den Anfragekontext innerhalb einer asynchronen Operation aktiviert und beendet, um sicherzustellen, dass Ihre CDI-Beans und deren Abhängigkeiten korrekt über Threads hinweg funktionieren.
Minimierung des Overheads mit ArC-Optimierungen
ArC DI dreht sich alles um Leistung und bietet mehrere Möglichkeiten, den Overhead in Ihrem asynchronen EDA zu minimieren. Hier sind einige Tipps, um Ihre Anwendung schlank und effizient zu halten:
1. Verwenden Sie @Singleton für zustandslose Dienste
@Singleton
public class HighPerformanceService {
// Zustandslose Logik hier
}
Der @Singleton
-Bereich stellt sicher, dass nur eine Instanz der Bean erstellt wird, was den Speicherverbrauch und die Instanziierungszeit reduziert.
2. Nutzen Sie @Unremovable für wesentliche Beans
@Unremovable
@Singleton
public class CriticalAsyncService {
// Diese Bean wird während der Optimierung nicht entfernt
}
Die @Unremovable
-Annotation verhindert, dass ArC die Bean während der Build-Zeit-Optimierungen entfernt, was entscheidend für Beans ist, die dynamisch nachgeschlagen oder in reflektionsintensiven Szenarien verwendet werden.
3. Nutzen Sie das reaktive Programmiermodell
Quarkus und ArC harmonieren gut mit reaktiver Programmierung. Erwägen Sie die Verwendung reaktiver Typen für Ihre asynchronen Operationen:
import io.smallrye.mutiny.Uni;
@Singleton
public class ReactiveOrderService {
public Uni createOrderReactively(Order order) {
return Uni.createFrom().item(() -> {
// Asynchrone Auftragserstellungslogik
return order;
});
}
}
Dieser Ansatz nutzt den reaktiven Kern von Quarkus und bietet eine bessere Ressourcennutzung und Skalierbarkeit für Ihr asynchrones EDA.
Alles zusammenfügen: Ein vollständiges asynchrones EDA-Beispiel
Lassen Sie uns all diese Konzepte in einem umfassenderen Beispiel kombinieren:
import io.quarkus.arc.Arc;
import io.smallrye.mutiny.Uni;
import javax.enterprise.context.ApplicationScoped;
import javax.enterprise.event.Event;
import javax.enterprise.event.Observes;
import javax.inject.Inject;
@ApplicationScoped
public class AsyncOrderSystem {
@Inject
Event orderEvent;
public Uni processOrder(Order order) {
return Uni.createFrom().item(() -> {
// Verarbeitung simulieren
order.setStatus("PROCESSING");
return order;
}).onItem().invoke(processed -> {
orderEvent.fire(new OrderEvent("PROCESSED", processed));
});
}
public void onOrderEvent(@Observes OrderEvent event) {
Uni.createFrom().item(() -> {
System.out.println("Bestellung " + event.getStatus() + ": " + event.getOrder().getId());
// Zusätzliche asynchrone Operationen durchführen
return event;
}).subscribe().with(
item -> System.out.println("Ereignis erfolgreich verarbeitet"),
failure -> System.err.println("Fehler bei der Ereignisverarbeitung: " + failure.getMessage())
);
}
}
@ApplicationScoped
public class OrderRepository {
public Uni save(Order order) {
return Uni.createFrom().item(() -> {
// Datenbankspeicherung simulieren
System.out.println("Bestellung gespeichert: " + order.getId());
return null;
});
}
}
// Hauptanwendungsklasse
@QuarkusMain
public class AsyncEDAApplication {
@Inject
AsyncOrderSystem orderSystem;
@Inject
OrderRepository orderRepository;
public static void main(String[] args) {
Quarkus.run(AsyncEDAApplication.class, args);
}
@QuarkusMain
public void run() {
Order order = new Order("ORD-001");
orderSystem.processOrder(order)
.chain(processed -> orderRepository.save(processed))
.subscribe().with(
success -> System.out.println("Bestellung erfolgreich verarbeitet und gespeichert"),
failure -> System.err.println("Fehler bei der Bestellverarbeitung: " + failure.getMessage())
);
}
}
Dieses Beispiel zeigt:
- Asynchrone Ereignisverarbeitung mit ArC DI
- Reaktive Programmierung mit Mutiny
- Kontextverwaltung in asynchronen Operationen
- Effiziente Nutzung der Dependency-Injection-Funktionen von ArC
Fazit: Die asynchrone Zukunft mit ArC DI umarmen
Wir haben gerade die Oberfläche dessen angekratzt, was mit ArC DI in Quarkus für die Implementierung asynchroner EDAs möglich ist. Durch die Nutzung der spezialisierten Funktionen von ArC können Sie hoch effiziente, skalierbare und wartbare ereignisgesteuerte Architekturen erstellen, die weit über das hinausgehen, was Standard-CDI bietet.
Denken Sie an diese wichtigen Erkenntnisse:
- ArC DI ist für Quarkus optimiert und bietet überlegene Leistung für asynchrone Operationen.
- Richtige Kontextverwaltung ist entscheidend für asynchrone EDAs – nutzen Sie die Kontextübertragungsfunktionen von ArC.
- Kombinieren Sie ArC DI mit dem reaktiven Programmiermodell von Quarkus für beste Ergebnisse.
- Optimieren Sie Ihre Beans und nutzen Sie die Build-Zeit-Verarbeitung von ArC, um die Laufzeitbelastung zu minimieren.
Gehen Sie nun hinaus und bauen Sie einige großartige asynchrone EDAs mit Quarkus und ArC DI! Ihre Anwendungen werden es Ihnen danken, und auch Ihre Benutzer, wenn sie diese blitzschnelle Reaktionsfähigkeit erleben.
"Der beste Weg, die Zukunft vorherzusagen, ist, sie zu implementieren." – Alan Kay
Viel Spaß beim Programmieren, und mögen Ihre Ereignisse reibungslos durch die asynchronen Ströme Ihrer Quarkus-Anwendungen fließen!