Introduksjon til Event Notification Model i CDI 2.0

1. Oversikt

CDI (Contexts and Dependency Injection) er standardavhengighetsinjeksjonsrammen for Jakarta EE-plattformen.

I denne veiledningen tar vi en titt på CDI 2.0 og hvordan den bygger på den kraftige, typesikre injeksjonsmekanismen til CDI 1.x av legge til en forbedret, fullverdig hendelsesvarslingsmodell.

2. Maven-avhengighetene

For å komme i gang, bygger vi et enkelt Maven-prosjekt.

Vi trenger en CDI 2.0-kompatibel container, og Weld, referanseimplementeringen av CDI, passer godt:

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

Som vanlig kan vi hente de nyeste versjonene av cdi-api og sveis-se-kjerne fra Maven Central.

3. Observere og håndtere egendefinerte hendelser

For å si det enkelt, CDI 2.0 hendelsesvarslingsmodellen er en klassisk implementering av Observer-mønsteret, basert på @Observerer metode-parameter kommentar. Derfor lar det oss enkelt definere observatørmetoder, som automatisk kan kalles som svar på en eller flere hendelser.

For eksempel kunne vi definere en eller flere bønner, som ville utløse en eller flere spesifikke hendelser, mens andre bønner ville bli varslet om hendelsene og ville reagere tilsvarende.

For å demonstrere tydeligere hvordan dette fungerer, bygger vi et enkelt eksempel, inkludert en grunnleggende serviceklasse, en tilpasset hendelsesklasse og en observatørmetode som reagerer på våre tilpassede hendelser.

3.1. En grunnleggende serviceklasse

La oss starte med å lage en enkel TextService klasse:

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

3.2. En tilpasset arrangementsklasse

Deretter la oss definere et eksempel på hendelsesklasse, som tar en String argument i sin konstruktør:

offentlig klasse ExampleEvent {private final String eventMessage; public ExampleEvent (String eventMessage) {this.eventMessage = eventMessage; } // getter}

3.3. Definere en observatørmetode med @Observerer Kommentar

Nå som vi har definert våre service- og arrangementsklasser, la oss bruke @Observerer kommentar for å lage en observatørmetode for vår EksempelEvent klasse:

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

Mens ved første blikk, implementeringen av onEvent () metoden ser ganske triviell ut, den innkapsler faktisk mye funksjonalitet gjennom @Observerer kommentar.

Som vi kan se, er onEvent () metoden er en hendelsesbehandler som tar EksempelEvent og TextService objekter som argumenter.

La oss huske at alle argumentene som er spesifisert etter @Observerer merknader er standard injeksjonspunkter. Som et resultat vil CDI lage fullinitialiserte forekomster for oss og injisere dem i observatørmetoden.

3.4. Initialiserer CDI 2.0 Container

På dette punktet har vi opprettet service- og arrangementsklasser, og vi har definert en enkel observatørmetode for å reagere på hendelsene våre. Men hvordan instruerer vi CDI om å injisere disse forekomsten under kjøretid?

Her viser hendelsesvarslingsmodellen sin funksjonalitet til det fulle. Vi initialiserer ganske enkelt det nye SeContainer implementering og fyr av en eller flere hendelser gjennom fireEvent () metode:

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

Merk at vi bruker SeContainerInitializer og SeContainer objekter fordi vi bruker CDI i et Java SE-miljø, snarere enn i Jakarta EE.

Alle vedlagte observatørmetoder vil bli varslet når EksempelEvent blir sparket ved å forplante selve hendelsen.

Siden alle objektene passerte som argumenter etter @Observerer merknader vil bli fullstendig initialisert, CDI vil ta seg av ledninger TextService objektgraf for oss før du injiserer den i onEvent () metode.

I et nøtteskall, Vi har fordelene med en typesikker IoC-container, sammen med en funksjonsrik hendelsesvarslingsmodell.

4. Den ContainerInitialisert Begivenhet

I det forrige eksemplet brukte vi en tilpasset hendelse for å overføre en hendelse til en observatørmetode og få en fullinitialisert TextService gjenstand.

Selvfølgelig er dette nyttig når vi virkelig trenger å formidle en eller flere hendelser på tvers av flere punkter i applikasjonen vår.

Noen ganger trenger vi rett og slett å få en haug med fullinitialiserte objekter som er klare til å brukes i våre applikasjonsklasser, uten å måtte gjennomføre implementeringen av flere arrangementer.

For dette formål CDI 2.0 gir ContainerInitialisert hendelsesklasse, som automatisk avfyres når sveisebeholderen initialiseres.

La oss ta en titt på hvordan vi kan bruke ContainerInitialisert hendelse for overføring av kontroll til EksempelEventObserver klasse:

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

Og husk det de ContainerInitialisert arrangementsklasse er sveisespesifikk. Så vi må omorganisere observatørmetodene våre hvis vi bruker en annen CDI-implementering.

5. Betingede observasjonsmetoder

I sin nåværende implementering, vår EksempelEventObserver klasse definerer som standard en ubetinget observatørmetode. Dette betyr at observatørmetoden vil alltid bli varslet om den leverte hendelsen, uansett om en forekomst av klassen eksisterer i gjeldende sammenheng.

På samme måte kan vi definere en betinget observatørmetode ved å spesifisere 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 bruker en betinget observatørmetode, metoden blir kun varslet om den samsvarende hendelsen hvis en forekomst av klassen som definerer observatørmetoden eksisterer i gjeldende sammenheng.

6. Transaksjonelle observatørmetoder

Vi kan også skyte hendelser i en transaksjon, for eksempel en databaseoppdatering eller fjerning. For å gjøre dette kan vi definere transaksjonsmetoder for observatører ved å legge til i løpet av argument til @Observerer kommentar.

Hver mulige verdi av i løpet av argumentet tilsvarer en bestemt fase av en transaksjon:

  • FØR_KOMPLETTING
  • AFTER_COMPLETION
  • AFTER_SUCCESS
  • AFTER_FAILURE

Hvis vi fyrer opp EksempelEvent hendelse i en transaksjon, må vi omlegge onEvent () metode for å håndtere hendelsen i den nødvendige fasen:

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

En transaksjonsobservatørmetode vil kun bli varslet om den leverte hendelsen i samsvarende fase av en gitt transaksjon.

7. Bestilling av observatørmetoder

En annen fin forbedring inkludert i CDI 2.0s hendelsesvarslingsmodell er muligheten for å sette opp en bestilling eller prioritet for å ringe observatører av en gitt hendelse.

Vi kan enkelt definere i hvilken rekkefølge observatørmetodene skal kalles ved å spesifisere @Prioritet kommentar etter @Observerer.

For å forstå hvordan denne funksjonen fungerer, la oss definere en annen observatørmetode, bortsett fra den som EksempelEventObserver redskaper:

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

I dette tilfellet vil begge observatørmetodene som standard ha samme prioritet. Dermed er rekkefølgen CDI vil påberope dem rett og slett uforutsigbar.

Vi kan enkelt fikse dette ved å tildele hver metode en påkallingsprioritet gjennom @Prioritet kommentar:

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

Prioritetsnivåer følger en naturlig rekkefølge. Derfor vil CDI først kalle observatørmetoden med et prioritetsnivå på 1 og vil påkalle andre metoden med et prioritetsnivå på 2.

Like måte, hvis vi bruker det samme prioritetsnivået på tvers av to eller flere metoder, er rekkefølgen igjen udefinert.

8. Asynkrone hendelser

I alle eksemplene vi har lært så langt, avfyrte vi hendelser synkront. Imidlertid lar CDI 2.0 oss også enkelt skyte på asynkrone hendelser. Asynkrone observatørmetoder kan da håndtere disse asynkrone hendelsene i forskjellige tråder.

Vi kan skyte en hendelse asynkront med fireAsync () metode:

offentlig klasse ExampleEventSource {@Inject Event exampleEvent; offentlig ugyldig fireEvent () {eksempelEvent.fireAsync (nytt eksempelEvent ("Velkommen til Baeldung!")); }}

Bønner fyrer opp hendelser, som er implementeringer av Begivenhet grensesnitt. Derfor kan vi injisere dem som alle andre konvensjonelle bønner.

For å håndtere den asynkrone hendelsen vår, må vi definere en eller flere asynkrone observatørmetoder med @ObservesAsync kommentar:

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

9. Konklusjon

I denne artikkelen, vi lærte hvordan vi kommer i gang med den forbedrede hendelsesvarslingsmodellen som følger med CDI 2.0.

Som vanlig er alle kodeeksemplene som vises i denne opplæringen tilgjengelig på GitHub.


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