Eine Anleitung zu Activiti mit Java

Ein Leitfaden für Activiti mit Java

1. Überblick

Activiti API ist ein Workflow- und Business Process Management-System. Mit den von der API bereitgestellten Diensten können wir einen Prozess definieren, ausführen und auf verschiedene Weise bearbeiten. Es erfordert JDK 7+.

Die Entwicklung mit der API kann in jeder IDE erfolgen, aber um dieActiviti Designer zu verwenden, benötigen wir Eclipse.

Wir können darin einen Prozess definieren, der den BPMN 2.0-Standard verwendet. Es gibt einen anderen, weniger beliebten Weg - die Verwendung von Java-Klassen wieStartEvent,EndEvent,UserTask,SequenceFlow usw.

Wenn wir einen Prozess ausführen oder auf einen der Dienste zugreifen möchten, müssen wirProcessEngineConfiguration erstellen.

Wir können dieProcessEngine mitProcessEngineConfiguration, auf einige Arten erhalten, die wir in diesem Artikel weiter diskutieren werden.. Durch_ the _ProcessEngine können wir die Workflow- und BPMN-Operationen ausführen.

2. Maven-Abhängigkeiten

Um diese API verwenden zu können, müssen wir die Activiti-Abhängigkeit einbeziehen:


    org.activiti
    activiti-engine

3. ProcessEngine erstellen

ProcessEngine in Activiti wird normalerweise mithilfe der XML-Dateiactiviti.cfg.xml konfiguriert. Ein Beispiel für diese Konfigurationsdatei ist:


    
        
        
        
        
        
    

Jetzt können wir dieProcessEngine mit der KlasseProcessEngines erhalten:

ProcessEngine processEngine = ProcessEngines.getDefaultProcessEngine();

Diese Anweisung sucht im Klassenpfad nach eineractiviti.cfg.xml-Datei und erstellt eineProcessEngine basierend auf der Konfiguration in der Datei.

Der Beispielcode für die Konfigurationsdatei zeigt, dass es sich nur um eine Spring-basierte Konfiguration handelt. Dies bedeutet jedoch nicht, dass wir Activiti nur in einer Spring-Umgebung verwenden können. Die Funktionen von Spring werden nur intern verwendet, um dieProcessEngine zu erstellen.

Schreiben wir einen JUnit-Testfall, in demProcessEnginemit der oben gezeigten Konfigurationsdatei erstellt werden:

@Test
public void givenXMLConfig_whenGetDefault_thenGotProcessEngine() {
    ProcessEngine processEngine
      = ProcessEngines.getDefaultProcessEngine();
    assertNotNull(processEngine);
    assertEquals("root", processEngine.getProcessEngineConfiguration()
      .getJdbcUsername());
}

4. Activiti Process Engine API und Services

Der Einstiegspunkt für die Interaktion mit der API istProcessEngine. ÜberProcessEngine, können wir auf verschiedene Dienste zugreifen, die Workflow- / BPMN-Methoden bereitstellen. DieProcessEngine und alle Serviceobjekte sind threadsicher.

image

Die KlasseProcessEngines sucht nach den Dateienactiviti.cfg.xml undactiviti-context.xml. Wie bereits erwähnt, werden für alleactiviti.cfg.xml-Dateien dieProcessEngine auf typische Weise erstellt.

Während für alleactiviti-context.xml-Dateien die Spring-Datei erstellt wird, erstelle ich den Spring-Anwendungskontext und erhalte daraus dieProcessEngine. Während der Ausführung eines Prozesses werden alle Schritte in der Reihenfolge aufgerufen, die in der BPMN-Datei definiert ist.

Während der Ausführung eines Prozesses werden alle Schritte in der Reihenfolge aufgerufen, die in der BPMN-Datei definiert ist.

A ProcessDefinition represents a business process. Wird verwendet, um die Struktur und das Verhalten verschiedener Schritte im Prozess zu definieren. Das Bereitstellen einer Prozessdefinition bedeutet, dass die Prozessdefinition in die Activiti-Datenbank geladen wird.

Prozessdefinitionen werden meist durch den BPMN 2.0-Standard definiert. Es ist auch möglich, sie mit Java-Code zu definieren. Alle in diesem Abschnitt definierten Begriffe sind auch als Java-Klassen verfügbar.

Sobald eine Prozessdefinition ausgeführt wird, kann sie als Prozess bezeichnet werden

AProcessInstance ist eine Ausführung vonProcessDefinition.

A StartEvent is associated with every business process. It indicates the entry point of the process. In ähnlicher Weise gibt es einEndEvent, das das Ende des Prozesses angibt. Wir können Bedingungen für diese Ereignisse definieren.

Alle Schritte (oder Elemente) zwischen Start und Ende werden alsTasks bezeichnet. Tasks können von verschiedenen Typen sein. Die am häufigsten verwendeten Aufgaben sindUserTasks undServiceTasks.

UserTasks sind, wie der Name schon sagt, so, dass sie von einem Benutzer manuell ausgeführt werden müssen.

ServiceTasks hingegen sind mit einem Code konfiguriert. Immer wenn die Ausführung sie erreicht, wird ihr Codeblock ausgeführt.

SequenceFlows verbinden dieTasks. Wir können dieSequenceFlows durch die Quell- und Zielelemente definieren, die sie verbinden. Auch hier können wir Bedingungen überSequenceFlowsdefinieren, um bedingte Pfade im Prozess zu erstellen.

4.2. Dienstleistungen

Wir werden kurz auf die von Activiti angebotenen Dienste eingehen:

  • RepositoryService hilft uns bei der Manipulation der Bereitstellung von Prozessdefinitionen. Dieser Service behandelt die statischen Daten einer Prozessdefinition

  • RuntimeService verwaltet dieProcessInstances (aktuell ausgeführten Prozesse) sowie die Prozessvariablen

  • TaskService verfolgt dieUserTasks. DieTasks, die von einem Benutzer manuell ausgeführt werden müssen, bilden den Kern der Activiti-API. Wir können eine Aufgabe erstellen, einen Anspruch erheben und eine Aufgabe abschließen, den Beauftragten der Aufgabe manipulieren usw. Nutzung dieses Dienstes

  • FormService ist ein optionaler Dienst. Die API kann ohne sie und ohne Beeinträchtigung ihrer Funktionen verwendet werden. Es wird verwendet, um das Startformular und das Aufgabenformular in einem Prozess zu definieren.

  • IdentityService verwaltet dieUsers undGroups

  • HistoryService verfolgt den Verlauf der Activiti Engine. Wir können auch verschiedene Verlaufsebenen festlegen.

  • ManagementService bezieht sich auf die Metadaten und ist normalerweise beim Erstellen einer Anwendung nicht erforderlich

  • DynamicBpmnService hilft uns, irgendetwas in einem Prozess zu ändern, ohne ihn neu zu implementieren.

5. Arbeiten mit Activiti Services

Um zu erfahren, wie wir mit verschiedenen Diensten arbeiten und einen Prozess ausführen können, nehmen wir ein Beispiel für einen Prozess für "Mitarbeiterurlaubsanfrage":

image

In der BPMN 2.0-DateiVacationRequest.bpmn20.xml für diesen Prozess ist das Startereignis wie folgt definiert:


    
        
        
        
     

In ähnlicher Weise sieht die erste Benutzeraufgabe, die der Benutzergruppe „Verwaltung“ zugewiesen ist, folgendermaßen aus:


    ${employeeName} would like to take ${numberOfDays} day(s)
      of vacation (Motivation: ${reason}).
    
        
        
    
    
      
        management
      
    

MitServiceTask, müssen wir den auszuführenden Code definieren. Wir haben diesen Code als Java-Klasse:


Der bedingte Fluss wird durch Hinzufügen des Tags“conditionExpression” in“sequenceFlow”: angezeigt


    
      
    

Hier istvacationApproved dasformProperty der oben gezeigtenUserTask.

Wie wir im Diagramm sehen können, ist dies ein sehr einfacher Vorgang. Der Mitarbeiter stellt eine Urlaubsanfrage und gibt die Anzahl der Tage und das Startdatum des Urlaubs an. Die Anfrage geht an den Manager. Sie können die Anfrage genehmigen / ablehnen.

Wenn genehmigt, ist eine Serviceaufgabe definiert, um die Bestätigungs-E-Mail zu senden. Bei Ablehnung kann der Mitarbeiter auswählen, ob die Anforderung geändert und erneut gesendet werden soll, oder nichts unternehmen.

Service-Tasks werden mit einem Teil des auszuführenden Codes versehen (hier als Java-Klasse). Wir haben die KlasseSendEmailServiceTask.java. angegeben

Diese Arten von Klassen sollten dieJavaDelegate. erweitern. Außerdem müssen wir dieexecute()-Methode überschreiben, die ausgeführt wird, wenn die Prozessausführung diesen Schritt erreicht.

5.1. Bereitstellen eines Prozesses

Um unseren Prozess der Activiti Engine bekannt zu machen, müssen wir den Prozess bereitstellen. Wir können dies programmgesteuert mitRepositoryService.tun. Schreiben wir einen JUnit-Test, um dies zu zeigen:

@Test
public void givenBPMN_whenDeployProcess_thenDeployed() {
    ProcessEngine processEngine
      = ProcessEngines.getDefaultProcessEngine();
    RepositoryService repositoryService
      = processEngine.getRepositoryService();
    repositoryService.createDeployment()
      .addClasspathResource(
      "org/activiti/test/vacationRequest.bpmn20.xml")
      .deploy();
    Long count=repositoryService.createProcessDefinitionQuery().count();
    assertEquals("1", count.toString());
}

Bereitstellung bedeutet, dass die Engine die BPMN-Datei analysiert und in eine ausführbare Datei konvertiert. Außerdem wird der Repository-Tabelle für jede Bereitstellung ein Datensatz hinzugefügt.

Daher können wir anschließend den DienstRepositoryabfragen, um die bereitgestellten Prozesse abzurufen. dieProcessDefinitions.

5.2. Starten einesProcessInstance

Nach der Bereitstellung vonProcessDefinition für Activiti Engine können wir den Prozess ausführen, indem wirProcessInstances erstellen. DasProcessDefinition ist eine Blaupause und dasProcessInstance ist die Laufzeitausführung davon.

Für ein einzelnesProcessDefinition kann es mehrereProcessInstances geben.

Auf alle Details zuProcessInstances kann überRuntimeService zugegriffen werden.

In unserem Beispiel müssen wir beim Startereignis die Anzahl der Urlaubstage, das Startdatum und den Grund übergeben. Wir werden die Prozessvariablen verwenden und sie beim Erstellen derProcessInstance. übergeben

Schreiben wir einen JUnit-Testfall, um eine bessere Vorstellung zu erhalten:

@Test
public void givenDeployedProcess_whenStartProcessInstance_thenRunning() {
    //deploy the process definition
    Map variables = new HashMap>();
    variables.put("employeeName", "John");
    variables.put("numberOfDays", 4);
    variables.put("vacationMotivation", "I need a break!");

    RuntimeService runtimeService = processEngine.getRuntimeService();
    ProcessInstance processInstance = runtimeService
      .startProcessInstanceByKey("vacationRequest", variables);
    Long count=runtimeService.createProcessInstanceQuery().count();

    assertEquals("1", count.toString());
}

Die mehreren Instanzen einer einzelnen Prozessdefinition unterscheiden sich durch die Prozessvariablen.

Es gibt mehrere Möglichkeiten, eine Prozessinstanz zu starten. Hier verwenden wir den Schlüssel des Prozesses. Nach dem Starten der Prozessinstanz können wir die Informationen dazu abrufen, indem wirRuntimeService abfragen.

5.3. Aufgaben erledigen

Wenn unsere Prozessinstanz ausgeführt wird, ist der erste Schritt eine Benutzeraufgabe, die der Benutzergruppe“management”. zugewiesen ist

Der Benutzer verfügt möglicherweise über einen Posteingang, der eine Liste der von ihm auszuführenden Aufgaben enthält. Wenn wir nun die Prozessausführung fortsetzen möchten, muss der Benutzer diese Aufgabe abschließen. Für Activiti Engine heißt es "Abschließen der Aufgabe".

Wir können dieTaskService, abfragen, um das Aufgabenobjekt zu erhalten und es dann abzuschließen.

Der Code, den wir dafür schreiben müssen, sieht folgendermaßen aus:

@Test
public void givenProcessInstance_whenCompleteTask_thenGotNextTask() {
    // deploy process and start process instance
    TaskService taskService = processEngine.getTaskService();
    List tasks = taskService.createTaskQuery()
      .taskCandidateGroup("management").list();
    Task task = tasks.get(0);

    Map taskVariables = new HashMap<>();
    taskVariables.put("vacationApproved", "false");
    taskVariables.put("comments", "We have a tight deadline!");
    taskService.complete(task.getId(), taskVariables);

    Task currentTask = taskService.createTaskQuery()
      .taskName("Modify vacation request").singleResult();
    assertNotNull(currentTask);
}

Beachten Sie, dass diecomplete()-Methode vonTaskService auch die erforderlichen Prozessvariablen berücksichtigt. Wir übergeben die Antwort des Managers.

Danach fährt die Process Engine mit dem nächsten Schritt fort. Hier fragt der nächste Schritt den Mitarbeiter, ob die Urlaubsanfrage erneut gesendet werden soll oder nicht.

UnsereProcessInstance warten nun auf dieseUserTask,, die den Namen“Modify vacation Anfrage hat. “

5.4. Anhalten und Aktivieren eines Prozesses

Wir können einProcessDefinition und auch einProcessInstance aussetzen. Wenn wir einProcessDefinition, aussetzen, können wir keine Instanz davon erstellen, während es angehalten ist. Wir können dies mitRepositoryService: tun

@Test(expected = ActivitiException.class)
public void givenDeployedProcess_whenSuspend_thenNoProcessInstance() {
    // deploy the process definition
    repositoryService.suspendProcessDefinitionByKey("vacationRequest");
    runtimeService.startProcessInstanceByKey("vacationRequest");
}

Um es wieder zu aktivieren, müssen wir nur eine derrepositoryService.activateProcessDefinitionXXX-Methoden aufrufen.

In ähnlicher Weise können wir aProcessInstance, mitRuntimeService. aussetzen

6. Fazit

In diesem Artikel haben wir gesehen, wie wir Activiti mit Java verwenden können. Wir haben eine BeispieldateiProcessEngineCofigurationerstellt, mit deren Hilfe wirProcessEngineerstellen können.

Damit haben wir auf verschiedene Dienste zugegriffen, die von der API bereitgestellt werden. Diese Dienste helfen uns,ProcessDefinitions,ProcessInstances,UserTasks usw. zu verwalten und zu verfolgen.

Wie immer lautet der Code für Beispiele, die wir im Artikel gesehen haben,over on GitHub.