Koristite Spring za izradu jednostavnog mehanizma tijeka rada

Mnoge Jave poslovne aplikacije zahtijevaju da se obrada izvršava u kontekstu odvojenom od konteksta glavnog sustava. U mnogim slučajevima ti pozadinski procesi izvode nekoliko zadataka, a neki zadaci ovise o statusu prethodnog zadatka. Sa zahtjevom međusobno ovisnih zadataka obrade, provedba koja koristi jedan skup postupovskih poziva metoda obično se pokazuje neadekvatnom. Koristeći Spring, programer može lako razdvojiti pozadinski proces u skup aktivnosti. Spremnik Spring pridružuje se tim aktivnostima kako bi oblikovao jednostavan tijek rada.

U svrhe ovog članka, jednostavni tijek rada definira se kao bilo koji skup aktivnosti koji se obavljaju unaprijed određenim redoslijedom bez interakcije korisnika. Međutim, ovaj pristup nije predložen kao zamjena za postojeće okvire tijeka rada. Za scenarije u kojima su potrebne naprednije interakcije, poput račvanja, spajanja ili prijelaza na temelju korisničkog unosa, samostalni mehanizam otvorenog koda ili komercijalni tijek rada je bolje opremljen. Jedan projekt otvorenog koda uspješno je integrirao složeniji dizajn tijeka rada s Springom.

Ako su zadaci tijeka posla pojednostavljeni, jednostavan pristup tijeku rada ima smisla za razliku od potpuno funkcionalnog samostalnog okvira tijeka rada, pogotovo ako se Spring već koristi, jer je brza implementacija zajamčena bez navođenja vremena za ubrzanje. Uz to, s obzirom na prirodu laganog Inversion-of-Control spremnika Spring, Spring smanjuje troškove resursa.

Ovaj članak ukratko predstavlja tijek rada kao temu programiranja. Koristeći koncepte tijeka rada, Spring se koristi kao okvir za pokretanje motora tijeka rada. Zatim se raspravlja o mogućnostima implementacije proizvodnje. Počnimo s idejom jednostavnog tijeka rada usredotočujući se na obrasce dizajna tijeka rada i povezane pozadinske informacije.

Jednostavan tijek rada

Modeliranje tijeka rada tema je koja se proučavala još 1970-ih, a mnogi su programeri pokušali stvoriti standardiziranu specifikaciju modeliranja tijeka rada. Uzorci tijeka rada , bijeli rad WHM van der Aalst i sur. (Srpanj 2003.) uspio je klasificirati skup obrazaca dizajna koji točno modeliraju najčešće scenarije tijeka rada. Među naj trivijalnijim uzorcima tijeka rada uzorak je slijed. Uklapajući kriterije jednostavnog tijeka rada, obrazac tijeka sekvence sastoji se od niza aktivnosti izvršenih u nizu.

Dijagrami aktivnosti UML (Unified Modeling Language) obično se koriste kao mehanizam za modeliranje tijeka rada. Na slici 1. prikazan je osnovni proces tijeka sekvence modeliran pomoću standardnog UML dijagrama aktivnosti.

Tok slijed je standardni obrazac tijeka rada koji prevladava u J2EE aplikacijama. J2EE aplikacija obično zahtijeva slijed događaja koji će se dogoditi u pozadinskoj niti ili asinkrono. Dijagram aktivnosti na slici 2 prikazuje jednostavan tijek rada za obavještavanje zainteresiranih putnika da je cijena avio karte do njihovog omiljenog odredišta smanjena.

Tok rada zrakoplovne tvrtke na slici 1. odgovoran je za stvaranje i slanje dinamičkih obavijesti e-poštom. Svaki korak u procesu predstavlja aktivnost. Prije pokretanja tijeka rada mora se dogoditi neki vanjski događaj. U ovom je slučaju taj događaj smanjenje stope za zrakoplovnu rutu leta.

Krenimo kroz poslovnu logiku tijeka rada zrakoplovne tvrtke. Ako prva aktivnost ne pronađe korisnike zainteresirane za obavijesti o smanjenju stope, cijeli tijek rada se otkazuje. Ako se otkriju zainteresirani korisnici, preostale aktivnosti se dovršavaju. Nakon toga, XSL (Extensible Stylesheet Language) transformacija generira sadržaj poruke, nakon čega se bilježe informacije o reviziji. Konačno, pokušava se poslati poruku putem SMTP poslužitelja. Ako se predaja dovrši bez greške, uspjeh se bilježi i postupak se završava. Ali, ako se tijekom komunikacije s SMTP poslužiteljem dogodi pogreška, preuzet će posebna rutina za rukovanje pogreškama. Ovaj kôd za rukovanje pogreškama pokušat će ponovno poslati poruku.

S obzirom na primjer zrakoplovne tvrtke, očito je jedno pitanje: Kako biste mogli učinkovito podijeliti sekvencijalni postupak na pojedinačne aktivnosti? Ovaj se problem rječito rješava pomoću Springa. Razgovarajmo brzo o Proljeću kao o inverziji kontrole.

Invertirajuća kontrola

Spring nam omogućuje uklanjanje odgovornosti upravljanja ovisnostima objekta premještanjem te odgovornosti u spremnik Spring. Ovaj prijenos odgovornosti poznat je pod nazivom Inverzija kontrole (IoC) ili Injekcija ovisnosti. Pogledajte "Inverzija upravljačkih spremnika i obrazac ubrizgavanja ovisnosti" Martina Fowlera (martinfowler.com, siječanj 2004.) za detaljniju raspravu o IoC-u i ubrizgavanju ovisnosti. Upravljajući ovisnostima između objekata, Spring uklanja potrebu za kodom ljepila , kodom napisanim isključivo u svrhu tjeranja klasa na međusobnu suradnju.

Komponente tijeka rada kao proljetni grah

Prije nego što stignemo predaleko, sada je dobro vrijeme da prođemo kroz glavne koncepte iza Proljeća. ApplicationContextSučelje, naslijedi iz BeanFactorysučelja, nameće se kao stvarni kontrolnog tijela ili više kontejnera u proljeće. Odgovorna ApplicationContextje za instanciju, konfiguraciju i upravljanje životnim ciklusom niza graha poznatog kao proljetni grah. The ApplicationContextse konfigurira ožičenjem Spring graha u konfiguracijskoj datoteci koja se temelji na XML-u. Ova konfiguracijska datoteka diktira prirodu u kojoj proljetni grah međusobno surađuje. Dakle, u proljeće govore, proljetni grah koji komunicira s drugima poznat je kao suradnik. Prema zadanim postavkama, proljetni grah postoji kao singleton uApplicationContext, ali atribut singleton može se postaviti na false, učinkovito mijenjajući ih da se ponašaju u onome što Spring naziva prototipom .

Povratak na naš primjer, u smanjenju avionske karte, apstrakcija SMTP rutine slanja ožičena je kao posljednja aktivnost u primjeru procesa rada (primjer koda dostupan u Resursima). Budući da je peta aktivnost, ovaj grah je prikladno nazvan activity5. Da biste poslali poruku, activity5potreban je suradnik delegata i voditelj pogrešaka:

Implementacija komponenata radnog toka kao Spring grah rezultira dvama poželjnim nusproizvodima, lakoćom jediničnog testiranja i velikim stupnjem ponovne upotrebe. Učinkovito jedinstveno testiranje vidljivo je s obzirom na prirodu IoC spremnika. Koristeći IoC spremnik poput Springa, ovisnosti suradnika mogu se lako zamijeniti lažnim zamjenama tijekom testiranja. U primjeru zrakoplovne tvrtke, Activityproljetni grah kakav activity5se lako može dobiti iz samostalnog testa ApplicationContext. Zamjenom lažnog SMTP delegata u activity5omogućuje activity5odvojeno testiranje jedinice .

Drugi nusproizvod, ponovna upotrebljivost, ostvaren je aktivnostima tijeka rada kao što je XSL transformacija. XSL transformacija, apstrahirana u aktivnost tijeka posla, sada može ponovno upotrijebiti bilo koji tijek rada koji se bavi XSL transformacijama.

Povezivanje tijeka rada

U pruženom API-ju (koji se može preuzeti iz Resursa) Spring kontrolira mali skup igrača za interakciju na način koji predstavlja tijek rada. Ključna sučelja su:

  • Activity: Inkapsulira poslovnu logiku jednog koraka u procesu rada.
  • ProcessContext: Objekti tipa ProcessContextprenose se između aktivnosti u tijeku rada. Objekti koji implementiraju ovo sučelje odgovorni su za održavanje stanja kako tijek rada prelazi iz jedne aktivnosti u drugu.
  • ErrorHandler: Pruža metodu povratnog poziva za rukovanje pogreškama.
  • Processor: Opisuje grah koji služi kao izvršitelj glavne niti tijeka rada.

Sljedeći izvadak iz uzorka koda je Spring bean konfiguracija koja primjeru zrakoplovne tvrtke veže kao jednostavan postupak tijeka rada.

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

SequenceProcessorKlasa je konkretna podklasa koje modele slijed uzorak. Ožičeno na procesor pet je aktivnosti koje će procesor tijeka rada izvršavati redom.

U usporedbi s većinom proceduralnih pozadinskih procesa, rješenje tijeka posla zaista se ističe kao sposobno za vrlo robusno rukovanje pogreškama. Obrađivač pogrešaka može se posebno povezati za svaku aktivnost. Ova vrsta rukovatelja omogućuje precizno rješavanje pogrešaka na razini pojedinačne aktivnosti. Ako za aktivnost nije povezan nijedan obrađivač pogrešaka, problem će riješiti obrađivač pogrešaka definiran za cjelokupni procesor tijeka posla. U ovom se primjeru, ako se bilo koja neobrađena pogreška dogodi bilo kada tijekom procesa rada, ona će se proširiti kako bi se njome upravljalo ErrorHandlerzrno, koje je ožičeno pomoću defaultErrorHandlersvojstva.

More complex workflow frameworks persist state to a datastore between transitions. In this article, we're only interested in simple workflow cases where state transition is automatic. State information is only available in the ProcessContext during the actual workflow's runtime. Having only two methods, you can see the ProcessContext interface is on a diet:

public interface ProcessContext extends Serializable { public boolean stopProcess(); public void setSeedData(Object seedObject); }

The concrete ProcessContext class used for the airline example workflow is the RateDropContext class. The RateDropContext class encapsulates the data necessary to execute an airline rate drop workflow.

Until now, all bean instances have been singletons as per the default ApplicationContext's behavior. But we must create a new instance of the RateDropContext class for every invocation of the airline workflow. To handle this requirement, the SequenceProcessor is configured, taking a fully qualified class name as the processContextClass property. For every workflow execution, the SequenceProcessor retrieves a new instance of ProcessContext from Spring using the class name specified. For this to work, a nonsingleton Spring bean or prototype of type org.iocworkflow.test.sequence.simple.SimpleContext must exist in the ApplicationContext (see rateDrop.xml for the entire listing).

Seeding the workflow

Sad kad znamo složiti jednostavan tijek rada pomoću Springa, usredotočimo se na instanciranje pomoću podataka sjemena. Da bismo razumjeli kako pokrenuti tijek rada, pogledajmo metode izložene na stvarnom Processorsučelju:

public interface Processor { public boolean supports(Activity activity); public void doActivities(); public void doActivities(Object seedData); public void setActivities(List activities); public void setDefaultErrorHandler(ErrorHandler defaultErrorHandler); }

U većini slučajeva procesi radnog procesa zahtijevaju neke početne podražaje za početak. Postoje dvije mogućnosti za pokretanje procesora: doActivities(Object seedData)metoda ili alternativa bez argumenata. Sljedeći popis kodova je doAcvtivities()implementacija za ono što je SequenceProcessoruključeno u uzorak koda:

 public void doActivities(Object seedData) { if (logger.isDebugEnabled()) logger.debug(getBeanName() + " processor is running.."); //retrieve injected by Spring List activities = getActivities(); //retrieve a new instance of the Workflow ProcessContext ProcessContext context = createContext(); if (seedData != null) context.setSeedData(seedData); for (Iterator it = activities.iterator(); it.hasNext();) { Activity activity = (Activity) it.next(); if (logger.isDebugEnabled()) logger.debug("running activity:" + activity.getBeanName() + " using arguments:" + context); try { context = activity.execute(context); } catch (Throwable th) { ErrorHandler errorHandler = activity.getErrorHandler(); if (errorHandler == null) { logger.info("no error handler for this action, run default error" + "handler and abort processing "); getDefaultErrorHandler().handleError(context, th); break; } else { logger.info("run error handler and continue"); errorHandler.handleError(context, th); } }