Introduktion til Event Notification Model i CDI 2.0

1. Oversigt

CDI (Contexts and Dependency Injection) er standardafhængighedsinjektionsrammen for Jakarta EE-platformen.

I denne tutorial tager vi et kig på CDI 2.0, og hvordan det bygger på den kraftfulde, typesikre injektionsmekanisme af CDI 1.x af tilføjelse af en forbedret, fuldt udstyret meddelelsesmodel for begivenheder.

2. Maven-afhængighederne

For at komme i gang bygger vi et simpelt Maven-projekt.

Vi har brug for en CDI 2.0-kompatibel container, og Weld, referenceimplementeringen af ​​CDI, passer godt:

  javax.enterprise cdi-api 2.0.SP1 org.jboss.weld.se weld-se-core 3.0.5.Final 

Som sædvanligt kan vi trække de nyeste versioner af cdi-api og svejse-se-kerne fra Maven Central.

3. Observation og håndtering af brugerdefinerede begivenheder

Kort fortalt, CDI 2.0-hændelsesmeddelelsesmodellen er en klassisk implementering af Observer-mønsteret, baseret på @Observerer metode-parameter anmærkning. Derfor tillader det os let at definere observatørmetoder, som automatisk kan kaldes som reaktion på en eller flere begivenheder.

For eksempel kunne vi definere en eller flere bønner, som ville udløse en eller flere specifikke begivenheder, mens andre bønner ville blive underrettet om begivenhederne og ville reagere i overensstemmelse hermed.

For at demonstrere mere klart, hvordan dette fungerer, bygger vi et simpelt eksempel, herunder en grundlæggende serviceklasse, en brugerdefineret begivenhedsklasse og en observatørmetode, der reagerer på vores brugerdefinerede begivenheder.

3.1. En grundlæggende serviceklasse

Lad os starte med at oprette en simpel TextService klasse:

offentlig klasse TextService {public String parseText (String text) {return text.toUpperCase (); }} 

3.2. En brugerdefineret begivenhedsklasse

Lad os derefter definere en prøvehændelsesklasse, der tager en Snor argument i sin konstruktør:

public class EksempelEvent {privat final String eventMessage; public ExampleEvent (String eventMessage) {this.eventMessage = eventMessage; } // getter}

3.3. Definition af en observatørmetode med @Observerer Kommentar

Nu hvor vi har defineret vores service- og begivenhedsklasser, lad os bruge @Observerer kommentar for at skabe en observatørmetode til vores EksempelEvent klasse:

public class ExampleEventObserver {public String onEvent (@Observes ExampleEvent event, TextService textService) {return textService.parseText (event.getEventMessage ()); }}

Mens ved første øjekast gennemførelsen af onEvent () metode ser ret trivielt ud, den indkapsler faktisk en masse funktionalitet gennem @Observerer kommentar.

Som vi kan se, er onEvent () metode er en begivenhedshåndterer, der tager EksempelEvent og TextService objekter som argumenter.

Lad os huske på, at alle de argumenter, der er angivet efter @Observerer annotering er standardindsprøjtningspunkter. Som et resultat vil CDI oprette fuldt initialiserede forekomster for os og injicere dem i observatørmetoden.

3.4. Initialisering af vores CDI 2.0-container

På dette tidspunkt har vi oprettet vores service- og begivenhedsklasser, og vi har defineret en simpel observatørmetode til at reagere på vores begivenheder. Men hvordan instruerer vi CDI om at indsprøjte disse forekomster ved kørsel?

Her er hvor begivenhedsmeddelelsesmodellen viser sin funktionalitet fuldt ud. Vi initialiserer simpelthen det nye SeContainer implementering og fyr en eller flere begivenheder gennem fireEvent () metode:

SeContainerInitializer containerInitializer = SeContainerInitializer.newInstance (); prøv (SeContainer container = containerInitializer.initialize ()) {container.getBeanManager (). fireEvent (nyt eksempelEvent ("Velkommen til Baeldung!")); }

Bemærk, at vi bruger SeContainerInitializer og SeContainer objekter, fordi vi bruger CDI i et Java SE-miljø snarere end i Jakarta EE.

Alle vedhæftede observatørmetoder underrettes, når EksempelEvent fyres ved at udbrede selve begivenheden.

Da alle objekter passerede som argumenter efter @Observerer annotering initialiseres fuldt ud, CDI tager sig af ledningsføring af hele TextService objektgraf for os, inden den injiceres i onEvent () metode.

I en nøddeskal, Vi har fordelene ved en typesikker IoC-container sammen med en funktionsrig begivenhedsmeddelelsesmodel.

4. Den ContainerInitialiseret Begivenhed

I det foregående eksempel brugte vi en brugerdefineret begivenhed til at videregive en begivenhed til en observatørmetode og få en fuldt initialiseret TextService objekt.

Selvfølgelig er dette nyttigt, når vi virkelig har brug for at udbrede en eller flere begivenheder på tværs af flere punkter i vores ansøgning.

Nogle gange er vi simpelthen nødt til at få en masse fuldt initialiserede objekter, der er klar til brug inden for vores applikationsklasseruden at skulle gennemføre implementeringen af ​​yderligere begivenheder.

Til denne ende, CDI 2.0 leverer ContainerInitialiseret begivenhedsklasse, som automatisk fyres, når svejsebeholderen initialiseres.

Lad os se på, hvordan vi kan bruge ContainerInitialiseret begivenhed til overførsel af kontrol til EksempelEventObserver klasse:

public class ExampleEventObserver {public String onEvent (@Observes ContainerInitialized event, TextService textService) {return textService.parseText (event.getEventMessage ()); }} 

Og husk det det ContainerInitialiseret begivenhedsklasse er svejsespecifik. Så vi bliver nødt til at omlægge vores observatørmetoder, hvis vi bruger en anden CDI-implementering.

5. Betingede observatørmetoder

I sin nuværende implementering har vores EksempelEventObserver klasse definerer som standard en ubetinget observatørmetode. Det betyder at observatørmetoden vil altid blive underrettet om den leverede begivenhed, uanset om der findes en forekomst af klassen i den aktuelle sammenhæng eller ej.

Ligeledes kan vi definere en betinget observatørmetode ved at specificere notifyObserver = IF_EXISTS som et argument til @Observerer kommentar:

public String onEvent (@Observes (notifyObserver = IF_EXISTS) ExampleEvent event, TextService textService) {return textService.parseText (event.getEventMessage ()); } 

Når vi bruger en betinget observatørmetode, metoden vil kun blive underrettet om den matchende begivenhed, hvis der findes en forekomst af klassen, der definerer observatørmetoden i den aktuelle kontekst.

6. Transaktionsobservationsmetoder

Vi kan også affyre begivenheder inden for en transaktion, såsom en databaseopdatering eller fjernelse. For at gøre dette kan vi definere transaktionsobservatørmetoder ved at tilføje i løbet af argument til @Observerer kommentar.

Hver mulige værdi af i løbet af argument svarer til en bestemt fase af en transaktion:

  • FØR_KOMPLETION
  • AFTER_COMPLETION
  • AFTER_SUCCESS
  • AFTER_FAILURE

Hvis vi fyrer EksempelEvent hændelse inden for en transaktion, skal vi omlægge onEvent () metode i overensstemmelse hermed til at håndtere begivenheden i den krævede fase:

public String onEvent (@Observes (under = AFTER_COMPLETION) EksempelEvent begivenhed, TextService textService) {returner textService.parseText (event.getEventMessage ()); }

En transaktionsobservationsmetode vil kun blive underrettet om den leverede begivenhed i matchningsfasen for en given transaktion.

7. Bestilling af observatørmetoder

En anden god forbedring inkluderet i CDI 2.0s begivenhedsmeddelelsesmodel er evnen til at oprette en bestilling eller prioritet til at ringe til observatører af en given begivenhed.

Vi kan let definere den rækkefølge, som observatørmetoderne kaldes i, ved at specificere @Prioritet kommentar efter @Observerer.

For at forstå, hvordan denne funktion fungerer, lad os definere en anden observatørmetode bortset fra den, der EksempelEventObserver redskaber:

offentlig klasse AnotherExampleEventObserver {public String onEvent (@Observes ExampleEvent event) {return event.getEventMessage (); }}

I dette tilfælde har begge observatørmetoder som standard den samme prioritet. Den rækkefølge, som CDI vil påberåbe sig, er således simpelthen uforudsigelig.

Vi kan nemt løse dette ved at tildele hver metode en indkaldelsesprioritet gennem @Prioritet kommentar:

public String onEvent (@Observes @Priority (1) ExampleEvent event, TextService textService) {// ... implementering} 
public String onEvent (@Observes @Priority (2) ExampleEvent event) {// ... implementering}

Prioriterede niveauer følger en naturlig rækkefølge. Derfor kalder CDI først observatørmetoden med et prioritetsniveau på 1 og påkalder anden metoden med et prioritetsniveau på 2.

Ligeledes, hvis vi bruger det samme prioritetsniveau på tværs af to eller flere metoder, er rækkefølgen igen udefineret.

8. Asynkrone begivenheder

I alle de eksempler, vi hidtil har lært, fyrede vi begivenheder synkront. CDI 2.0 tillader os dog også let at affyre asynkrone begivenheder. Asynkrone observatørmetoder kan derefter håndtere disse asynkrone begivenheder i forskellige tråde.

Vi kan affyre en begivenhed asynkront med fireAsync () metode:

offentlig klasse ExampleEventSource {@Inject Event exampleEvent; public void fireEvent () {exampleEvent.fireAsync (nyt ExampleEvent ("Velkommen til Baeldung!")); }}

Bønner affyrer begivenheder, som er implementeringer af Begivenhed interface. Derfor kan vi injicere dem som enhver anden konventionel bønne.

For at håndtere vores asynkrone begivenhed er vi nødt til at definere en eller flere asynkrone observatørmetoder med @ObservesAsync kommentar:

offentlig klasse AsynchronousExampleEventObserver {public void onEvent (@ObservesAsync ExampleEvent event) {// ... implementering}}

9. Konklusion

I denne artikel vi lærte at komme i gang ved hjælp af den forbedrede begivenhedsmeddelelsesmodel, der følger med CDI 2.0.

Som normalt er alle kodeeksempler vist i denne vejledning tilgængelige på GitHub.


$config[zx-auto] not found$config[zx-overlay] not found