Vårhendelser
1. Oversikt
I denne artikkelen skal vi diskutere hvordan du bruker arrangementer om våren.
Arrangementer er en av de mer oversett funksjonalitetene i rammen, men også en av de mer nyttige. Og - som mange andre ting på våren - er publisering av hendelser en av funksjonene som tilbys av ApplicationContext.
Det er noen få enkle retningslinjer å følge:
- arrangementet skal utvides ApplicationEvent
- utgiveren bør injisere en ApplicationEventPublisher gjenstand
- lytteren skal implementere ApplicationListener grensesnitt
2. En tilpasset begivenhet
Våren lar oss lage og publisere tilpassede hendelser som - som standard - er synkrone. Dette har noen fordeler - som for eksempel at lytteren kan delta i forlagets transaksjonssammenheng.
2.1. En enkel applikasjonshendelse
La oss lage en enkel begivenhetsklasse - bare en plassholder for å lagre hendelsesdataene. I dette tilfellet har hendelsesklassen en strengmelding:
offentlig klasse CustomSpringEvent utvider ApplicationEvent {privat strengmelding; offentlig CustomSpringEvent (objektkilde, strengmelding) {super (kilde); denne meldingen = melding; } offentlig String getMessage () {returmelding; }}
2.2. En utgiver
La oss nå lage en utgiver av det arrangementet. Forlaget konstruerer hendelsesobjektet og publiserer det til alle som lytter.
For å publisere arrangementet kan forleggeren bare injisere ApplicationEventPublisher og bruk publishEvent () API:
@Komponent offentlig klasse CustomSpringEventPublisher {@Autowired private ApplicationEventPublisher applicationEventPublisher; public void publishCustomEvent (final String message) {System.out.println ("Publishing custom event."); CustomSpringEvent customSpringEvent = nytt CustomSpringEvent (dette, melding); applicationEventPublisher.publishEvent (customSpringEvent); }}
Alternativt kan forlagsklassen implementere ApplicationEventPublisherAware grensesnitt - dette vil også injisere utgiveren av programmet ved oppstart av applikasjonen. Vanligvis er det enklere å bare injisere utgiveren med @Autowire.
2.3. En lytter
Til slutt, la oss lage lytteren.
Det eneste kravet til lytteren er å være en bønne og implementere ApplicationListener grensesnitt:
@Komponent offentlig klasse CustomSpringEventListener implementerer ApplicationListener {@Override public void onApplicationEvent (CustomSpringEvent event) {System.out.println ("Mottatt våren tilpasset hendelse -" + event.getMessage ()); }}
Legg merke til hvordan den tilpassede lytteren vår parametriseres med den generiske typen tilpasset hendelse - noe som gjør onApplicationEvent () metodesikker. Dette unngår også å måtte sjekke om objektet er en forekomst av en bestemt hendelsesklasse og kaste det.
Og som allerede diskutert - som standard vårhendelser er synkrone - den doStuffAndPublishAnEvent () metoden blokkerer til alle lyttere er ferdig med å behandle arrangementet.
3. Opprette asynkrone hendelser
I noen tilfeller er publisering av hendelser synkront egentlig ikke det vi leter etter - vi kan trenge asynkronisering av hendelsene våre.
Du kan slå på det i konfigurasjonen ved å opprette en ApplicationEventMulticaster bønne med en eksekutor; for våre formål her SimpleAsyncTaskExecutor fungerer fint:
@Configuration public class AsynchronousSpringEventsConfig {@Bean (name = "applicationEventMulticaster") public ApplicationEventMulticaster simpleApplicationEventMulticaster () {SimpleApplicationEventMulticaster eventMulticaster = new SimpleApplicationEventMulticaster (); eventMulticaster.setTaskExecutor (ny SimpleAsyncTaskExecutor ()); returevent Multicaster; }}
Arrangementet, utgiveren og lytterimplementeringene forblir de samme som før - men nå, lytteren vil asynkront håndtere hendelsen i en egen tråd.
4. Eksisterende rammearrangementer
Våren selv publiserer en rekke arrangementer utenom boksen. For eksempel ApplicationContext vil avfire ulike rammearrangementer. F.eks. ContextRefreshedEvent, ContextStartedEvent, RequestHandledEvent etc.
Disse hendelsene gir applikasjonsutviklere mulighet til å koble seg til applikasjonens livssyklus og konteksten og legge til sin egen tilpassede logikk der det er nødvendig.
Her er et raskt eksempel på en lytter som lytter etter kontekstoppdateringer:
offentlig klasse ContextRefreshedListener implementerer ApplicationListener {@Override public void onApplicationEvent (ContextRefreshedEvent cse) {System.out.println ("Handling context re-freshed event."); }}
For å lære mer om eksisterende rammeverk, kan du ta en titt på vår neste opplæring her.
5. Annotasjonsdrevet hendelseslytter
Fra og med vår 4.2 kreves det at en lytter ikke er en bønne som implementerer ApplicationListener grensesnitt - det kan registreres på hvilket som helst offentlig metode for en administrert bønne via @EventListener kommentar:
@Component public class AnnotationDrivenEventListener {@EventListener public void handleContextStart (ContextStartedEvent cse) {System.out.println ("Håndtering av kontekst startet hendelse."); }}
Som tidligere erklærer metodesignaturen hendelsestypen den bruker.
Som standard påkalles lytteren synkront. Imidlertid kan vi enkelt gjøre det asynkront ved å legge til et @Async kommentar. Vi må huske å aktivere Asynkronisering støtte i applikasjonen, skjønt.
6. Generisk støtte
Det er også mulig å sende hendelser med generisk informasjon i hendelsestypen.
6.1. En generell applikasjonshendelse
La oss lage en generisk hendelsestype. I vårt eksempel inneholder arrangementsklassen alt innhold og en suksess statusindikator:
offentlig klasse GenericSpringEvent {privat T hva; beskyttet boolsk suksess; public GenericSpringEvent (T what, boolean suksess) {this.what = what; this.success = suksess; } // ... standard getters}
Legg merke til forskjellen mellom GenericSpringEvent og CustomSpringEvent. Vi har nå fleksibiliteten til å publisere vilkårlige hendelser, og det kreves ikke å utvide fra ApplicationEvent lenger.
6.2. En lytter
La oss nå lage en lytter til hendelsen. Vi kunne definere lytteren ved å implementere ApplicationListener grensesnitt som før:
@Component public class GenericSpringEventListener implementerer ApplicationListener {@Override public void onApplicationEvent (@NonNull GenericSpringEvent event) {System.out.println ("Mottatt vår generisk hendelse -" + event.getWhat ()); }}
Men dessverre krever denne definisjonen at vi skal arve GenericSpringEvent fra ApplicationEvent klasse. Så for denne opplæringen, la oss bruke en annotasjonsdrevet hendelseslytter som er diskutert tidligere.
Det er også mulig å gjør begivenhetslytteren betinget ved å definere et boolsk SpEL-uttrykk på @EventListener kommentar. I dette tilfellet blir hendelsesbehandleren kun påkalt for å lykkes GenericSpringEvent av String:
@Component public class AnnotationDrivenEventListener {@EventListener (condition = "# event.success") public void handleSuccessful (GenericSpringEvent event) {System.out.println ("Handling generic event (conditional)."); }}
Spring Expression Language (SpEL) er et kraftig uttrykksspråk som er dekket detaljert i en annen opplæring.
6.3. En utgiver
Arrangementsutgiveren er lik den som er beskrevet ovenfor. Men på grunn av type sletting, må vi publisere en hendelse som løser generiske parameteren vi vil filtrere på. For eksempel, klasse GenericStringSpringEvent utvider GenericSpringEvent.
Og det er det en alternativ måte å publisere begivenheter på. Hvis vi returnerer en ikke-null verdi fra en metode som er merket med @EventListener som et resultat vil Spring Framework sende resultatet som en ny begivenhet for oss. Videre kan vi publisere flere nye hendelser ved å returnere dem i en samling som et resultat av hendelsesbehandling.
7. Transaksjonsbundne hendelser
Dette avsnittet handler om å bruke @TransactionalEventListener kommentar. For å lære mer om transaksjonsadministrasjon, se Transactions with Spring og JPA tutorial.
Siden våren 4.2 gir rammeverket et nytt @TransactionalEventListener kommentar, som er en utvidelse av @EventListener, som gjør det mulig å binde lytteren til en hendelse til en fase av transaksjonen. Det er mulig å binde til følgende transaksjonsfaser:
- AFTER_COMMIT (standard) brukes til å utløse hendelsen hvis transaksjonen har gjort det fullført
- AFTER_ROLLBACK - hvis transaksjonen har det Rullet tilbake
- AFTER_COMPLETION - hvis transaksjonen har det fullført (et alias for AFTER_COMMIT og AFTER_ROLLBACK)
- FØR_KOMMITT brukes til å fyre av arrangementet riktig før transaksjon begå
Her er et raskt eksempel på lytter til transaksjonelle hendelser:
@TransactionalEventListener (phase = TransactionPhase.BEFORE_COMMIT) public void handleCustom (CustomSpringEvent event) {System.out.println ("Håndtering av hendelse i en transaksjon FØR ENGITT."); }
Denne lytteren vil bare bli påkalt hvis det er en transaksjon der produsenten av arrangementet kjører og den er i ferd med å bli begått.
Og hvis ingen transaksjoner kjører, sendes ikke hendelsen i det hele tatt, med mindre vi overstyrer dette ved å angi fallbackExecution tilskrive ekte.
8. Konklusjon
I denne raske opplæringen gikk vi over det grunnleggende om håndtere hendelser om våren - lage en enkel tilpasset hendelse, publisere den, og deretter håndtere den i en lytter.
Vi hadde også en kort titt på hvordan vi kan aktivere asynkron behandling av hendelser i konfigurasjonen.
Så lærte vi om forbedringer som ble introdusert våren 4.2, for eksempel merkedrevne lyttere, bedre generisk støtte og hendelser som er bindende for transaksjonsfaser.
Som alltid er koden presentert i denne artikkelen tilgjengelig på Github. Dette er et Maven-basert prosjekt, så det skal være enkelt å importere og kjøre som det er.