Introduksjon til våren med Akka

1. Introduksjon

I denne artikkelen vil vi fokusere på å integrere Akka med Spring Framework - for å tillate injeksjon av vårbaserte tjenester i Akka-aktører.

Før du leser denne artikkelen, anbefales en forkunnskap om Akkas grunnleggende informasjon.

2. Avhengighetsinjeksjon i Akka

Akka er et kraftig applikasjonsrammeverk basert på Actor concurrency-modellen. Rammeverket er skrevet i Scala som selvfølgelig gjør det fullt brukbart også i Java-baserte applikasjoner. Og så det er veldig ofte vi vil integrere Akka med en eksisterende vårbasert applikasjon eller bruk Spring for å koble bønner til skuespillere.

Problemet med vår / Akka-integrasjon ligger i forskjellen mellom håndtering av bønner om våren og ledelsen av aktører i Akka: skuespillere har en bestemt livssyklus som skiller seg fra den typiske vårbønns livssyklus.

Videre er skuespillere delt inn i en skuespiller i seg selv (som er en intern implementeringsdetalj og som ikke kan administreres av Spring) og en skuespillerreferanse, som er tilgjengelig med en klientkode, samt seriøs og bærbar mellom forskjellige Akka-driftstider.

Heldigvis gir Akka en mekanisme, nemlig Akka-utvidelser, som gjør bruk av eksterne avhengighetsinjeksjonsrammer til en ganske enkel oppgave.

3. Maven-avhengigheter

For å demonstrere bruken av Akka i vårprosjektet, trenger vi et minimum av våravhengighet - vår-kontekst biblioteket, og også akka-skuespiller bibliotek. Biblioteksversjonene kan hentes ut til delen av pom:

 4.3.1.RELEASE 2.4.8 org.springframework spring-context $ {spring.version} com.typesafe.akka akka-actor_2.11 $ {akka.version} 

Sørg for å sjekke Maven Central for de nyeste versjonene av vår-kontekst og akka-skuespiller avhengigheter.

Og legg merke til hvordan det akka-skuespiller avhengighet har en _2.11 postfix i navnet, noe som betyr at denne versjonen av Akka framework ble bygget mot Scala versjon 2.11. Den tilsvarende versjonen av Scala-biblioteket vil bli inkludert i bygningen din.

4. Injisering av vårbønner i Akka Actors

La oss lage en enkel Spring / Akka-applikasjon som består av en enkelt aktør som kan svare på en persons navn ved å gi en hilsen til denne personen. Hilsenlogikken blir hentet ut til en egen tjeneste. Vi vil ønske å koble denne tjenesten til en aktørinstans. Vårintegrasjon vil hjelpe oss i denne oppgaven.

4.1. Definere en skuespiller og en tjeneste

For å demonstrere injeksjon av en tjeneste i en skuespiller, lager vi en enkel klasse Hilsen Skuespiller definert som en utypet skuespiller (utvide Akkas UntypedActor baseklasse). Hovedmetoden til hver Akka-skuespiller er påMotta metode som mottar en melding og behandler den i henhold til en spesifikk logikk.

I vårt tilfelle er Hilsen Skuespiller implementering sjekker om meldingen er av en forhåndsdefinert type Hilse på, tar deretter navnet på personen fra Hilse på for eksempel bruker deretter HilsenService for å motta en hilsen til denne personen og svarer avsenderen med mottatt hilsenstreng. Hvis meldingen er av en annen ukjent type, blir den overført til skuespillerens forhåndsdefinerte uhåndtert metode.

La oss se:

@Component @Scope (ConfigurableBeanFactory.SCOPE_PROTOTYPE) offentlig klasse GreetingActor utvider UntypedActor {private GreetingService greetingService; // constructor @ Override public void onReceive (Objektmelding) kaster Throwable {if (message instanceof Greet) {String name = ((Greet) message) .getName (); getSender (). tell (greetingService.greet (name), getSelf ()); } annet {ubehandlet (melding); }} offentlig statisk klasse Hilsen {private String name; // standard konstruktører / getters}}

Legg merke til at Hilse på meldingstype er definert som en statisk indre klasse inne i denne skuespilleren, noe som anses som en god praksis. Aksepterte meldingstyper bør defineres så nær en aktør som mulig for å unngå forvirring om hvilke meldingstyper denne aktøren kan behandle.

Legg også merke til vårkommentarene @Komponent og @Omfang - disse definerer klassen som en vårstyrt bønne med prototype omfang.

Omfanget er veldig viktig, fordi hver forespørsel om henting av bønner skal resultere i en nylig opprettet forekomst, ettersom denne oppførselen samsvarer med Akkas skuespillersyklus. Hvis du implementerer denne bønner med noe annet omfang, vil det typiske tilfellet med å starte skuespillere i Akka mest sannsynlig fungere feil.

Til slutt, legg merke til at vi ikke måtte eksplisitt @Autowire de HilsenService forekomst - dette er mulig på grunn av den nye funksjonen i vår 4.3 kalt Implisitt konstruktørinjeksjon.

Gjennomføringen av GreeterService er ganske grei, legg merke til at vi definerte det som en vårstyrt bønne ved å legge til @Komponent kommentar til den (med standard singleton omfang):

@Component public class GreetingService {public String greet (String name) {return "Hello," + name; }}

4.2. Legge til vårstøtte via Akka Extension

Den enkleste måten å integrere våren med Akka på er gjennom en Akka-utvidelse.

En utvidelse er en singleton-forekomst opprettet per skuespillersystem. Den består av en utvidelsesklasse som implementerer markørgrensesnittet Utvidelse, og en utvidelses-id-klasse som vanligvis arver AbstractExtensionId.

Ettersom disse to klassene er tett koblet, er det fornuftig å implementere Utvidelse klasse nestet i ExtensionId klasse:

offentlig klasse SpringExtension utvider AbstractExtensionId {offentlig statisk slutt SpringExtension SPRING_EXTENSION_PROVIDER = ny SpringExtension (); @Override public SpringExt createExtension (ExtendedActorSystem system) {return new SpringExt (); } offentlig statisk klasse SpringExt implementerer utvidelse {private flyktige ApplicationContext applicationContext; offentlig tomrom initialiseres (ApplicationContext applicationContext) {this.applicationContext = applicationContext; } offentlige rekvisitter (String actorBeanName) {return Props.create (SpringActorProducer.class, applicationContext, actorBeanName); }}}

FørstSpringExtension implementerer en singel createExtension metoden fra AbstractExtensionId klasse - som står for opprettelsen av en utvidelsesforekomst, SpringExt gjenstand.

De SpringExtension klasse har også et statisk felt SPRING_EXTENSION_PROVIDER som har en referanse til sin eneste forekomst. Det er ofte fornuftig å legge til en privat konstruktør for å eksplisitt si det SpringExtention skal være en singleton-klasse, men vi vil utelate den for klarhetens skyld.

for det andre, den statiske indre klassen SpringExt er selve utvidelsen. Som Utvidelse er ganske enkelt et markørgrensesnitt, vi kan definere innholdet i denne klassen slik vi ønsker det.

I vårt tilfelle trenger vi initialisere metode for å holde en vår ApplicationContext forekomst - denne metoden vil bare kalles en gang per initialisering av utvidelsen.

Vi vil også kreve Rekvisitter metode for å lage en Rekvisitter gjenstand. Rekvisitter eksempel er en plan for en skuespiller, og i vårt tilfelle Rekvisitter. Lag metoden mottar en SpringActorProducer klasse- og konstruktørargumenter for denne klassen. Dette er argumentene som denne klassens konstruktør vil bli kalt til.

De Rekvisitter metoden vil bli utført hver gang vi trenger en referanse fra vårstyrt skuespiller.

Den tredje og siste brikke i puslespillet er SpringActorProducer klasse. Den implementerer Akka’s IndirectActorProducer grensesnitt som gjør det mulig å overstyre instantiasjonsprosessen for en aktør ved å implementere produsere og skuespillerKlasse metoder.

Som du sikkert allerede har gjettet, i stedet for direkte instantiering, vil den alltid hente en skuespillerinstans fra vårens ApplicationContext. Som vi har gjort skuespilleren til prototype- skopet bønne, hver samtale til produsere metoden vil returnere en ny forekomst av skuespilleren:

offentlig klasse SpringActorProducer implementerer IndirectActorProducer {private ApplicationContext applicationContext; private String beanActorName; public SpringActorProducer (ApplicationContext applicationContext, String beanActorName) {this.applicationContext = applicationContext; this.beanActorName = beanActorName; } @ Override public Actor produce () {return (Actor) applicationContext.getBean (beanActorName); } @ Override public Class actorClass () {return (Class) applicationContext .getType (beanActorName); }}

4.3. Sette alt sammen

Det eneste som gjenstår å gjøre er å lage en vårkonfigurasjonsklasse (merket med @Konfigurasjon merknad) som vil be Spring om å skanne den nåværende pakken sammen med alle nestede pakker (dette er sikret av @ComponentScan merknad) og opprett en Spring container.

Vi trenger bare å legge til en ekstra bønne - the ActorSystem eksempel - og initialiser vårforlengelsen på dette ActorSystem:

@Configuration @ComponentScan public class AppConfiguration {@Autowired private ApplicationContext applicationContext; @Bean public ActorSystem actorSystem () {ActorSystem system = ActorSystem.create ("akka-spring-demo"); SPRING_EXTENSION_PROVIDER.get (system) .initialize (applicationContext); retur system; }}

4.4. Henter Spring-Wired Actors

For å teste at alt fungerer riktig, kan vi injisere ActorSystem forekomst i koden vår (enten en våradministrert applikasjonskode eller en vårbasert test), opprett en Rekvisitter objekt for en skuespiller som bruker utvidelsen vår, hente en referanse til en skuespiller via Rekvisitter protester og prøv å hilse på noen:

ActorRef greeter = system.actorOf (SPRING_EXTENSION_PROVIDER.get (system) .props ("greetingActor"), "greeter"); FiniteDuration varighet = FiniteDuration.create (1, TimeUnit.SECONDS); Timeout timeout = Timeout.durationToTimeout (varighet); Fremtidig resultat = spør (hilsen, ny hilsen ("John"), timeout); Assert.assertEquals ("Hei, John", Await.result (resultat, varighet));

Her bruker vi det typiske akka.pattern.Patterns.ask mønster som returnerer en Scala Framtid forekomst. Når beregningen er fullført, vil Framtid løses med en verdi som vi returnerte i vår HilsenActor.onMessasge metode.

Vi kan enten vente på resultatet ved å bruke Scala Venter. Resultat metoden til Framtid, eller, mer foretrukket, bygge hele applikasjonen med asynkrone mønstre.

5. Konklusjon

I denne artikkelen har vi vist hvordan du kan integrere Spring Framework med Akka og autowire bønner i skuespillere.

Kildekoden for artikkelen er tilgjengelig på GitHub.


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