Programmering

Bruk våren til å lage en enkel arbeidsflytmotor

Mange Jave-bedriftsapplikasjoner krever at behandlingen utføres i en sammenheng som er forskjellig fra hovedsystemets. I mange tilfeller utfører disse backendprosessene flere oppgaver, med noen oppgaver avhengig av statusen til en tidligere oppgave. Med kravet om gjensidig avhengige behandlingsoppgaver, viser det seg at en implementering ved hjelp av et enkelt sett av metodesamtaler av metodesamtaler er utilstrekkelig. Ved å bruke Spring kan en utvikler enkelt skille en backend-prosess i en aggregering av aktiviteter. Vårcontaineren slutter seg til disse aktivitetene for å danne en enkel arbeidsflyt.

For denne artikkelens formål, enkel arbeidsflyt er definert som ethvert sett med aktiviteter utført i en forutbestemt rekkefølge uten brukerinteraksjon. Denne tilnærmingen foreslås imidlertid ikke som en erstatning for eksisterende arbeidsflytrammer. For scenarier der mer avanserte interaksjoner er nødvendige, for eksempel forking, sammenføyning eller overganger basert på brukerinngang, er en frittstående åpen kildekode eller kommersiell arbeidsflytmotor bedre utstyrt. Ett åpen kildekodeprosjekt har med hell integrert en mer kompleks arbeidsflytdesign med Spring.

Hvis arbeidsflytoppgavene er enkle, er den enkle arbeidsflyttilnærmingen fornuftig i motsetning til et fullt funksjonelt frittstående arbeidsflytrammeverk, spesielt hvis Spring allerede er i bruk, ettersom rask implementering er garantert uten å påløpe oppstartstid. I tillegg, gitt vårens lette Inversion-of-Control-container, reduserer Spring ressursomkostningene.

Denne artikkelen introduserer kort arbeidsflyt som et programmeringsemne. Ved hjelp av arbeidsflytkonsepter brukes Spring som rammeverket for å kjøre en arbeidsflytmotor. Deretter diskuteres distribusjonsalternativer for produksjon. La oss begynne med ideen om enkel arbeidsflyt ved å fokusere på arbeidsflytdesignmønstre og relatert bakgrunnsinformasjon.

Enkel arbeidsflyt

Modelleringsarbeidsflyt er et tema som har blitt studert helt tilbake til 1970-tallet, og mange utviklere har forsøkt å lage en standardisert arbeidsflytmodelleringsspesifikasjon. Arbeidsflytmønstre, et hvitt papir av W.H.M. van der Aalst et al. (Juli 2003), har lykkes med å klassifisere et sett med designmønstre som nøyaktig modellerer de vanligste arbeidsflytscenariene. Blant de mest trivielle arbeidsflytmønstrene er sekvensmønsteret. Oppfyller kriteriene for en enkel arbeidsflyt, består arbeidsflytmønsteret for sekvens av et sett med aktiviteter utført i rekkefølge.

UML-aktivitetsdiagrammer (Unified Modelling Language) brukes ofte som en mekanisme for å modellere arbeidsflyt. Figur 1 viser en grunnleggende Sequence-arbeidsflytprosess modellert med et standard UML-aktivitetsdiagram.

Sequence-arbeidsflyten er et standard arbeidsflytmønster som er vanlig i J2EE-applikasjoner. En J2EE-applikasjon krever vanligvis at en sekvens av hendelser skal skje i en bakgrunnstråd eller asynkront. Figur 2s aktivitetsdiagram illustrerer en enkel arbeidsflyt for å varsle interesserte reisende om at flybilletten til favorittdestinasjonen har redusert.

Flyselskapets arbeidsflyt i figur 1 er ansvarlig for å opprette og sende dynamiske e-postvarsler. Hvert trinn i prosessen representerer en aktivitet. Noen eksterne hendelser må inntreffe før arbeidsflyten settes i gang. I dette tilfellet er denne hendelsen en hastighetsreduksjon for et flyselskaps flyrute.

La oss gå gjennom flyselskapets arbeidsflyt. Hvis den første aktiviteten ikke finner brukere interessert i varslinger om hastighetsfall, kanselleres hele arbeidsflyten. Hvis interesserte brukere blir oppdaget, blir de gjenværende aktivitetene fullført. Deretter genererer en XSL (Extensible Stylesheet Language) transformasjon meldingsinnholdet, hvorpå revisjonsinformasjon blir registrert. Til slutt gjøres et forsøk på å sende meldingen via en SMTP-server. Hvis innsendingen fullføres uten feil, logges suksessen og prosessen avsluttes. Men hvis det oppstår en feil under kommunikasjon med SMTP-serveren, vil en spesiell feilhåndteringsrutine ta over. Denne feilhåndteringskoden prøver å sende meldingen på nytt.

Gitt flyselskapseksemplet er det et spørsmål tydelig: Hvordan kan du effektivt dele opp en sekvensiell prosess i individuelle aktiviteter? Dette problemet håndteres veltalende ved hjelp av våren. La oss raskt diskutere våren som en inversjon av kontrollrammeverket.

Inverterende kontroll

Våren lar oss fjerne ansvaret for å kontrollere et objekts avhengighet ved å flytte dette ansvaret til vårbeholderen. Denne overføringen av ansvar er kjent som Inversion of Control (IoC) eller Dependency Injection. Se Martin Fowlers "Inversion of Control Containers and the Dependency Injection Pattern" (martinfowler.com, januar 2004) for en mer inngående diskusjon om IoC og Dependency Injection. Ved å håndtere avhengigheter mellom objekter, eliminerer Spring behovet for limkode, kode skrevet med det ene formål å få klasser til å samarbeide med hverandre.

Arbeidsflytkomponenter som vårbønner

Før vi kommer for langt, er det nå en god tid å gå gjennom hovedkonseptene bak våren. De ApplicationContext grensesnitt, arver fra BeanFactory grensesnitt, pålegger seg selv som den faktiske kontrollerende enheten eller containeren i løpet av våren. De ApplicationContext er ansvarlig for instantiering, konfigurasjon og livssyklusadministrasjon av et sett med bønner kjent som Vårbønner. De ApplicationContext er konfigurert av ledninger Spring bønner i en XML-basert konfigurasjonsfil. Denne konfigurasjonsfilen dikterer arten som Spring beans samarbeider med hverandre. Således, om våren, er vårbønner som samhandler med andre kjent som samarbeidspartnere. Som standard finnes vårbønner som singletoner i ApplicationContext, men singleton-attributtet kan settes til falsk, og effektivt endre dem til å oppføre seg i det Spring kaller prototype modus.

Tilbake til eksemplet vårt, når flybilletten er redusert, kobles en abstraksjon av en SMTP-sendingsrutine som den siste aktiviteten i arbeidsflytprosesseksemplet (eksempelkode tilgjengelig i Resources). Å være den femte aktiviteten, blir denne bønnen passende kalt aktivitet5. For å sende en melding, aktivitet5 krever en delegat-samarbeidspartner og en feilbehandler:

Implementering av arbeidsflytkomponentene som vårbønner resulterer i to ønskelige biprodukter, enkel enhetstesting og stor grad av gjenbruk. Effektiv enhetstesting er tydelig gitt naturen til IoC-containere. Ved hjelp av en IoC-container som Spring, kan samarbeidspartneravhengigheter enkelt byttes ut med mock-erstatninger under testing. I flyeksemplet er et Aktivitet Vårbønne som aktivitet5 kan enkelt hentes fra en frittstående test ApplicationContext. Å erstatte en mock SMTP-delegat i aktivitet5 gjør det mulig å teste enheten aktivitet5 hver for seg.

Det andre biproduktet, gjenbrukbarhet, realiseres av arbeidsflytaktiviteter som en XSL-transformasjon. En XSL-transformasjon, abstrakt til en arbeidsflytaktivitet, kan nå gjenbrukes av hvilken som helst arbeidsflyt som håndterer XSL-transformasjoner.

Koble til arbeidsflyten

I det medfølgende API-et (nedlastbart fra Resources) styrer Spring et lite sett med spillere for å samhandle på en måte som utgjør en arbeidsflyt. Nøkkelgrensesnittene er:

  • Aktivitet: Innkapsler forretningslogikken til et enkelt trinn i arbeidsflytprosessen.
  • ProcessContext: Objekter av typen ProcessContext overføres mellom aktiviteter i arbeidsflyten. Objekter som implementerer dette grensesnittet, er ansvarlige for å opprettholde tilstanden når arbeidsflyten overgår fra en aktivitet til den neste.
  • ErrorHandler: Gir en tilbakekallingsmetode for håndtering av feil.
  • Prosessor: Beskriver en bønne som tjener som utfører av hovedarbeidsflyttråden.

Følgende utdrag fra eksempelkoden er en vårbønnekonfigurasjon som binder flyselskapseksemplet som en enkel arbeidsflytprosess.

             / eiendom> org.iocworkflow.test.sequence.ratedrop.RateDropContext 

De SekvensProsessor klasse er en konkret underklasse som modellerer et Sekvensmønster. Kablet til prosessoren er fem aktiviteter som arbeidsflytprosessoren vil utføre i rekkefølge.

Sammenlignet med de fleste prosessuelle backend-prosessene, fremstår arbeidsflytløsningen for å være i stand til svært robust feilhåndtering. En feilbehandler kan kobles separat for hver aktivitet. Denne typen behandlere gir finkornet feilhåndtering på det enkelte aktivitetsnivå. Hvis ingen feilbehandler er koblet til en aktivitet, vil feilbehandleren som er definert for den totale arbeidsflytprosessoren, håndtere problemet. For dette eksemplet, hvis en uhåndtert feil oppstår når som helst under arbeidsflytprosessen, vil den forplante seg til å bli håndtert av ErrorHandler bønne, som er koblet til med defaultErrorHandler eiendom.

Mer komplekse rammer for arbeidsflyt vedvarer til en datalagring mellom overgangene. I denne artikkelen er vi bare interessert i enkle arbeidsflyt tilfeller der tilstandsovergang er automatisk. Statlig informasjon er bare tilgjengelig i ProcessContext i løpet av den faktiske arbeidsflytens kjøretid. Å ha bare to metoder, kan du se ProcessContext grensesnittet er på diett:

offentlig grensesnitt ProcessContext utvider Serializable {public boolean stopProcess (); public void setSeedData (Object seedObject); }

Betongen ProcessContext klassen som brukes for flyseksemplet arbeidsflyt er RateDropContext klasse. De RateDropContext klasse innkapsler dataene som er nødvendige for å utføre en arbeidsflyt for flyraten.

Inntil nå har alle bønneforekomster vært singler som standard ApplicationContextoppførsel. Men vi må opprette en ny forekomst av RateDropContext klasse for hver påkalling av flyets arbeidsflyt. For å håndtere dette kravet, SekvensProsessor er konfigurert, og tar et fullt kvalifisert klassenavn som processContextClass eiendom. For hver arbeidsflytutførelse, SekvensProsessor henter en ny forekomst av ProcessContext fra våren ved bruk av klassens navn. For at dette skal fungere, en nonsingleton Spring bønne eller prototype av typen org.iocworkflow.test.sequence.simple.SimpleContext må eksistere i ApplicationContext (se rateDrop.xml for hele noteringen).

Såning av arbeidsflyten

Nå som vi vet hvordan vi kan sette sammen en enkel arbeidsflyt ved hjelp av Spring, la oss fokusere på instantiering ved hjelp av frødata. For å forstå hvordan man frø arbeidsflyten, la oss se på metoder som er utsatt for selve Prosessor grensesnitt:

offentlig grensesnitt Prosessor {public boolean supports (Activity activity); offentlig ugyldig doActivities (); offentlig ugyldig doActivities (Object seedData); public void setActivities (Liste aktiviteter); public void setDefaultErrorHandler (ErrorHandler defaultErrorHandler); }

I de fleste tilfeller krever arbeidsflytprosesser noen innledende stimuli for kickoff. Det finnes to alternativer for å sette i gang en prosessor: doActivities (Object seedData) metoden eller alternativet uten argument. Følgende kodeliste er doAcvtivities () implementering for SekvensProsessor følger med prøvekoden:

 public void doActivities (Object seedData) {if (logger.isDebugEnabled ()) logger.debug (getBeanName () + "prosessor kjører .."); // hente injisert av Spring List-aktiviteter = getActivities (); // hente en ny forekomst av Workflow ProcessContext ProcessContext context = createContext (); hvis (seedData! = null) context.setSeedData (seedData); for (Iterator it = activities.iterator (); it.hasNext ();) {Activity activity = (Activity) it.next (); hvis (logger.isDebugEnabled ()) logger.debug ("kjører aktivitet:" + aktivitet.getBeannavn () + "ved hjelp av argumenter:" + kontekst); prøv {context = activity.execute (context); } catch (Throwable th) {ErrorHandler errorHandler = activity.getErrorHandler (); hvis (errorHandler == null) {logger.info ("ingen feilbehandler for denne handlingen, kjør standardfeil" + "behandler og avbryt behandling"); getDefaultErrorHandler (). handleError (kontekst, th); gå i stykker; } annet {logger.info ("kjør feilbehandler og fortsett"); errorHandler.handleError (kontekst, th); }} 
$config[zx-auto] not found$config[zx-overlay] not found