Een gids voor Activiti met Java

1. Overzicht

Activiti API is een workflow- en bedrijfsprocesbeheersysteem. We kunnen er een proces in definiëren, het uitvoeren en het op verschillende manieren manipuleren met behulp van de services die door de API worden geboden. Het vereist JDK 7+.

Ontwikkeling met behulp van de API kan in elke IDE worden gedaan, maar om de Activiti Designer te gebruiken, hebben we Eclipse nodig.

We kunnen er een proces in definiëren met behulp van de BPMN 2.0-standaard. Er is een andere, minder populaire manier - het gebruik van Java-klassen zoals StartEvent, EndEvent, UserTask, SequenceFlow, enz.

Als we een proces willen uitvoeren of toegang willen krijgen tot een van de services, moeten we een ProcessEngineConfiguration.

We kunnen de ProcessEngine gebruik makend van ProcessEngineConfiguration, op een aantal manieren, die we verderop in dit artikel zullen bespreken. Doorde ProcessEngine we kunnen de Workflow- en BPMN-bewerkingen uitvoeren.

2. Maven afhankelijkheden

Om deze API te gebruiken, moeten we de Activiti-afhankelijkheid opnemen:

 org.activiti activiti-engine 

3. Een ProcessEngine

ProcessEngine in Activiti, wordt meestal geconfigureerd met behulp van een XML-bestand, activiti.cfg.xml. Een voorbeeld van dit configuratiebestand is:

Nu kunnen we het ProcessEngine de ... gebruiken ProcessEngines klasse:

ProcessEngine processEngine = ProcessEngines.getDefaultProcessEngine ();

Deze verklaring zoekt naar een activiti.cfg.xml-bestand in het klassenpad en construeer een ProcessEngine gebaseerd op de configuratie in het bestand.

De voorbeeldcode voor het configuratiebestand laat zien dat het slechts een op Spring gebaseerde configuratie is. Maar dit betekent niet dat we Activiti alleen in een Spring-omgeving kunnen gebruiken. De mogelijkheden van Spring worden alleen intern gebruikt om het ProcessEngine.

Laten we een JUnit-testcase schrijven die het ProcessEngine met behulp van het bovenstaande configuratiebestand:

@Test openbare ongeldig gegevenXMLConfig_whenGetDefault_thenGotProcessEngine () {ProcessEngine processEngine = ProcessEngines.getDefaultProcessEngine (); assertNotNull (processEngine); assertEquals ("root", processEngine.getProcessEngineConfiguration () .getJdbcUsername ()); } 

4. Activiti Process Engine API en services

Het toegangspunt voor interactie met de API is het ProcessEngine. Door het Process Engine, we hebben toegang tot verschillende services die workflow / BPMN-methoden bieden. De ProcessEngine en alle service-objecten zijn draadveilig.

Ontleend aan //www.activiti.org/userguide/images/api.services.png

De ProcessEngines klasse zal zoeken naar het activiti.cfg.xml en activiti-context.xml bestanden. Zoals eerder vermeld, voor alle activiti.cfg.xml bestanden, de ProcessEngine wordt op een typische manier gemaakt.

Terwijl, voor alle activiti-context.xml bestanden, wordt deze op de Spring-manier gemaakt - ik zal de Spring Application Context maken en de ProcessEngine van dat. Tijdens de uitvoering van een proces worden alle stappen bezocht in de volgorde die is gedefinieerd in het BPMN-bestand.

Tijdens de uitvoering van een proces worden alle stappen bezocht in de volgorde die is gedefinieerd in het BPMN-bestand.

4.1. Procesdefinitie en gerelateerde termen

EEN Procesdefinitie vertegenwoordigt een bedrijfsproces. Het wordt gebruikt om de structuur en het gedrag van verschillende stappen in het proces te definiëren. Het implementeren van een procesdefinitie betekent het laden van de procesdefinitie in de Activiti-database.

Procesdefinities worden meestal gedefinieerd door de BPMN 2.0-standaard. Het is ook mogelijk om ze te definiëren met Java-code. Alle termen die in deze sectie worden gedefinieerd, zijn ook beschikbaar als Java-klassen.

Zodra we beginnen met het uitvoeren van een procesdefinitie, kan dit een proces worden genoemd

EEN ProcessInstance is een uitvoering van een Procesdefinitie.

EEN StartEvent wordt geassocieerd met elk bedrijfsproces. Het geeft het beginpunt van het proces aan. Evenzo is er een EndEvent wat het einde van het proces aangeeft. We kunnen voorwaarden definiëren voor deze gebeurtenissen.

Alle stappen (of elementen) tussen het begin en het einde worden aangeduid als Taken. Taken kan van verschillende typen zijn. De meest gebruikte taken zijn UserTasks en Servicetaken.

UserTasks, zoals de naam suggereert, zijn zodanig dat ze handmatig door een gebruiker moeten worden uitgevoerd.

Servicetaken, aan de andere kant, zijn geconfigureerd met een stukje code. Telkens wanneer de uitvoering hen bereikt, wordt hun codeblok uitgevoerd.

SequenceFlows verbind de Taken. We kunnen de SequenceFlows door de bron- en doelelementen die ze zullen verbinden. Nogmaals, we kunnen ook voorwaarden definiëren voor de SequenceFlows om voorwaardelijke paden in het proces te creëren.

4.2. Diensten

We zullen de diensten van Activiti kort bespreken:

  • RepositoryService helpt ons bij het manipuleren van de implementatie van procesdefinities. Deze service behandelt de statische gegevens die betrekking hebben op een procesdefinitie
  • RuntimeService beheert de Procesomstandigheden (momenteel lopende processen) evenals de procesvariabelen
  • TaskService houdt de UserTasks. De Taken die handmatig door een gebruiker moeten worden uitgevoerd, vormen de kern van de Activiti API. We kunnen een taak creëren, een taak claimen en voltooien, de toegewezen persoon van de taak manipuleren, enz. Met behulp van deze service
  • FormService is een optionele service. De API kan zonder de API worden gebruikt en zonder enige van zijn functies op te offeren. Het wordt gebruikt om het startformulier en het taakformulier in een proces te definiëren.
  • IdentityService beheert de Gebruikers en Groepen
  • GeschiedenisService houdt de geschiedenis van Activiti Engine bij. We kunnen ook verschillende geschiedenisniveaus instellen.
  • ManagementService is gerelateerd aan de metadata en is meestal niet vereist bij het maken van een applicatie
  • DynamicBpmnService helpt ons om iets in een proces te veranderen zonder het opnieuw te implementeren

5. Werken met Activiti Services

Laten we, om te zien hoe we met verschillende services kunnen werken en een proces kunnen uitvoeren, een voorbeeld nemen van een proces voor 'Vakantieverzoek van werknemer':

Het BPMN 2.0-bestand, VacationRequest.bpmn20.xml, voor dit proces wordt de startgebeurtenis gedefinieerd als:

Evenzo ziet de eerste gebruikerstaak, toegewezen aan de gebruikersgroep “beheer”, er als volgt uit:

 $ {employeeName} wil $ {numberOfDays} dag (en) vakantie opnemen (Motivatie: $ {reason}). beheer 

Met de Servicetaak, we moeten het stuk code definiëren dat moet worden uitgevoerd. We hebben dit stukje code als een Java-klasse:

De voorwaardelijke stroom wordt weergegeven door de toevoeging "ConditionExpression" tag in het "SequenceFlow":

Hier, vakantieGoedgekeurd is de formProperty van de UserTask hierboven weergegeven.

Zoals we in het diagram kunnen zien, is het een heel eenvoudig proces. De werknemer doet een vakantieaanvraag onder vermelding van het aantal dagen en de begindatum van de vakantie. Het verzoek gaat naar de manager. Ze kunnen het verzoek goedkeuren / afkeuren.

Indien goedgekeurd, is er een servicetaak gedefinieerd om de bevestigingsmail te verzenden. Als het wordt afgekeurd, kan de werknemer ervoor kiezen om het verzoek te wijzigen en opnieuw te verzenden, of niets doen.

Servicetaken zijn voorzien van een stukje code om uit te voeren (hier, als een Java-klasse). We hebben de klas gegeven SendEmailServiceTask.java.

Dit soort klassen moet de extensie JavaDelegate. We moeten ook zijn uitvoeren () methode, die zal worden uitgevoerd wanneer de procesuitvoering deze stap bereikt.

5.1. Een proces implementeren

Om ons proces bekend te maken aan de Activiti Engine, moeten we het proces implementeren. We kunnen het programmatisch doen met behulp van de RepositoryService. Laten we een JUnit-test schrijven om dit te laten zien:

@Test openbare ongeldig gegevenBPMN_whenDeployProcess_thenDeployed () {ProcessEngine processEngine = ProcessEngines.getDefaultProcessEngine (); RepositoryService repositoryService = processEngine.getRepositoryService (); repositoryService.createDeployment () .addClasspathResource ("org / activiti / test / vakantieRequest.bpmn20.xml") .deploy (); Lange telling = repositoryService.createProcessDefinitionQuery (). Count (); assertEquals ("1", count.toString ()); }

Implementatie betekent dat de engine het BPMN-bestand zal ontleden en het naar iets uitvoerbaars zal converteren. Ook wordt voor elke implementatie een record aan de Repository-tabel toegevoegd.

Daarom kunnen we daarna het Opslagplaats service om de ingezette processen te krijgen; de Procesdefinities.

5.2. Beginnen met een ProcessInstance

Na het inzetten van het Procesdefinitie aan Activiti Engine, kunnen we het proces uitvoeren door Procesomstandigheden. De Procesdefinitie is een blauwdruk, en de ProcessInstance is de runtime-uitvoering ervan.

Voor een enkele Procesdefinitie, kunnen er meerdere zijn Procesomstandigheden.

Alle details met betrekking tot het Procesomstandigheden is toegankelijk via de RuntimeService.

In ons voorbeeld moeten we bij het startevenement het aantal vakantiedagen, de startdatum en de reden opgeven. We zullen de procesvariabelen gebruiken en ze doorgeven tijdens het maken van het ProcessInstance.

Laten we een JUnit-testcase schrijven om een ​​beter idee te krijgen:

@Test openbare ongeldige gegevenDeployedProcess_whenStartProcessInstance_thenRunning () {// implementeer de procesdefinitie Kaartvariabelen = nieuwe HashMap> (); variables.put ("employeeName", "John"); variables.put ("numberOfDays", 4); variables.put ("vakantieMotivation", "Ik heb een pauze nodig!"); RuntimeService runtimeService = processEngine.getRuntimeService (); ProcessInstance processInstance = runtimeService .startProcessInstanceByKey ("vacationRequest", variabelen); Lange telling = runtimeService.createProcessInstanceQuery (). Count (); assertEquals ("1", count.toString ()); }

De meerdere exemplaren van een enkele procesdefinitie zullen verschillen door de procesvariabelen.

Er zijn meerdere manieren om een ​​procesinstantie te starten. Hier gebruiken we de sleutel van het proces. Nadat we de procesinstantie hebben gestart, kunnen we de informatie erover verkrijgen door het RuntimeService.

5.3. Taken voltooien

Wanneer onze procesinstantie begint te draaien, is de eerste stap een gebruikerstaak, toegewezen aan de gebruikersgroep "beheer".

De gebruiker heeft mogelijk een inbox met een lijst met taken die hij moet uitvoeren. Als we de procesuitvoering willen voortzetten, moet de gebruiker deze taak voltooien. Voor Activiti Engine heet het "de taak voltooien".

We kunnen het TaskService, om het taakobject te krijgen en het vervolgens te voltooien.

De code die we hiervoor moeten schrijven, ziet er als volgt uit:

@Test openbare ongeldig gegevenProcessInstance_whenCompleteTask_thenGotNextTask () {// implementeer proces en start procesinstantie TaskService taskService = processEngine.getTaskService (); Lijsttaken = taskService.createTaskQuery () .taskCandidateGroup ("beheer"). List (); Taak task = taken.get (0); Kaart taskVariables = nieuwe HashMap (); taskVariables.put ("vakantieApproved", "false"); taskVariables.put ("comments", "We hebben een strakke deadline!"); taskService.complete (task.getId (), taskVariables); Taak currentTask = taskService.createTaskQuery () .taskName ("Wijzig vakantieverzoek"). SingleResult (); assertNotNull (currentTask); }

Merk op dat de compleet() methode van TaskService neemt ook de benodigde procesvariabelen op. We geven het antwoord van de manager door.

Hierna gaat de procesengine door naar de volgende stap. Hier wordt in de volgende stap aan de werknemer gevraagd of het vakantieverzoek opnieuw moet worden verzonden of niet.

Zo onze ProcessInstance wacht hier nu op UserTask, die de naam heeft “Pas vakantie aan verzoek".

5.4. Een proces opschorten en activeren

We kunnen een Procesdefinitie en ook een ProcessInstance. Als we een ProcesDefinitie, we kunnen er geen exemplaar van maken terwijl het is opgeschort. We kunnen dit doen met behulp van de RepositoryService:

@Test (verwacht = ActivitiException.class) public void givenDeployedProcess_whenSuspend_thenNoProcessInstance () {// implementeer de procesdefinitie repositoryService.suspendProcessDefinitionByKey ("vacationRequest"); runtimeService.startProcessInstanceByKey ("vakantieRequest"); } 

Om het opnieuw te activeren, hoeven we alleen maar een van de repositoryService.activateProcessDefinitionXXX methoden.

Evenzo kunnen we een ProcessInstance, de ... gebruiken RuntimeService.

6. Conclusie

In dit artikel hebben we gezien hoe we Activiti konden gebruiken met Java. We hebben een voorbeeld gemaakt ProcessEngineCofiguration -bestand, wat ons helpt bij het maken van het ProcessEngine.

Door het te gebruiken, hebben we toegang gekregen tot verschillende services die door de API worden aangeboden. Deze diensten helpen ons bij het beheren en bijhouden van Procesdefinities, Procesomstandigheden, UserTasks, enz.

Zoals altijd ligt de code voor voorbeelden die we in het artikel hebben gezien op GitHub.