Activiti workflow learning ----- Based on version 5.19.0 (7) and activiti5.19.0
8. BPMN 2.0 Flowchart
The emergence of BPMN 2.0 standards is a good thing. Users are not kidnapped by a workflow developer or develop compromises in the workflow. Activiti is a set of BPMN standard solutions, this allows you to smoothly migrate data when selecting a workflow framework. There is also a negative news, that is, the BPMN standard is the result of a large number of meetings and discussions with developers to compromise (this is generally a dream). Therefore, when users read the BPMN specification, they will feel that it is too heavy, the Activiti development workflow puts user experience at the first place and develops a workflow design plug-in. We recommend that you use the workflow design plug-in.
8.1 Event)
Each process is designed with a start event and end event, and events that occur throughout the process are represented by events. Events are represented in circles in the design panel. There are two main events in BPMN 2.0:
- Catching:When the process is executed to an event, it will wait for the event to be triggered. The trigger condition needs to be configured in the attributes of the circle icon. The difference between the shape of the second circle icon and the following is that the Catching icon is empty, that is, an empty circle.
- Throwing:When the process is executed to an event, it will be triggered immediately. The same trigger also needs to be configured in the icon attribute. Unlike the Catching icon, there is something in the circle icon, black.
In general, the event definition determines the meaning of the event. If there is no event definition, this event will not do anything special. A start event that does not have an event definition set does not do anything when the process is started. If an event definition (such as a timer event definition) is added to the start event, we declare the event "type" of the Start event (the timer event listener will be triggered at a certain time ).
8.1.1 timer event
A timer event is an event triggered at a specified time. It can be used to start events, intermediate events, and boundary events ). The timer event must contain the configuration of the following attributes.
TimeDate:Specifies date timer activation in ISO 8601 format. (For ISO 8601 date format, see Baidu: http://baike.baidu.com/view/931641.htm)
<timerEventDefinition> <timeDate>2016-08-23T18:13:00</timeDate></timerEventDefinition>
TimeDuration:Defines the time after which the timer is activated. The time period is also in ISO 8601 format. For example, you can write p1y3m5dt6108m30s within 7 minutes 30 seconds, five days, and six hours, three months, one year.
<timerEventDefinition> <timeDuration>P10D</timeDuration></timerEventDefinition>
TimeCycle:Defines the recurrence interval of the timer, which is used in some scenarios, such as periodic start processes and task timeout sending reminders. Currently, there are two ways to set timeCycle: ISO 8601 and Cron expressions (the solution provided by the quartz job scheduling framework). activiti uses ISO 8601 by default. For example, if three times are repeated, each interval is 10 hours:
1 <timerEventDefinition>2 <timeCycle activiti:endDate="2016-08-22T16:42:11+00:00">R3/PT10H</timeCycle>3 </timerEventDefinition>
<timerEventDefinition> <timeCycle>R3/PT10H/${EndDate}</timeCycle></timerEventDefinition>
Here, endDate is an optional configuration. The above two methods are used with endDate, And the timer will stop working at the specified time.
In addition, if you use a Cron expression, you can write it as follows:
0 0/5 * * * ?
Note:The first digit represents the second, rather than the minute as in Unix cron. Repeated time periods can better process relative time. They can calculate specific time points (such as the start time of a user task), while cron expressions can process absolute time, this is particularly useful for scheduled startup events.
You can use expressions for configuration and dynamically set the value in it. However, the value must be in ISO 8601 or (cron expression) format,
<boundaryEvent id="escalationTimer" cancelActivity="true" attachedToRef="firstLineSupport"> <timerEventDefinition> <timeDuration>${duration}</timeDuration> </timerEventDefinition></boundaryEvent>
There are prerequisites for the execution of the definer: The async executor and job will be activated only when the timer is enabled (for example, it is configured in activiti. cfg. xmlJobexecut1_tivateOrAsyncexecut1_tivateTrue ).
8.1.2 Error Event timer
BPMN errors are about exception handling in the business. They are different from exceptions in java code. For example, you can configure an error event as follows:
1 <endEvent id="myErrorEndEvent">2 <errorEventDefinition errorRef="myError" />3 </endEvent>
8.1.3 signal event
A signal event will reference a named signal. The so-called signal will be sent to all active processors within the global scope of the Process Engine. Signal events are defined in signalEventDefinition In the BPMN file. The signalRef attribute can reference the previously declared signal, while signal serves as a sub-element in the root node of definitions. The following is an example.
1 <definitions...> 2 <! -- Declare signal --> 3 <signal id = "alertSignal" name = "alert"/> 4 5 <process id = "catchSignal"> 6 <intermediateThrowEvent id = "throwSignalEvent" name = ""Alert"> 7 <! -- Signal event definition --> 8 <signalEventDefinition signalRef = "alertSignal"/> 9 </intermediateThrowEvent> 10... 11 <intermediateCatchEvent id = "catchSignalEvent" name = "On Alert"> 12 <! -- Signal event definition --> 13 <signalEventDefinition signalRef = "alertSignal"/> 14 </intermediateCatchEvent> 15... 16 </process> 17 </definitions>
Throwing signal event: You can send signals when configuring in BPMN or using code implementation. The code can be like this:
1 RuntimeService.signalEventReceived(String signalName);2 RuntimeService.signalEventReceived(String signalName, String executionId);
The difference between the two methods is that the first method sends a global signal, and the second method specifies execution to send a signal.
Catching signal events: Events captured by intermediate events and boundary events.
The executionId of the second method or the method for querying currently active signal events is as follows:
1 List<Execution> executions = runtimeService.createExecutionQuery()2 .signalEventSubscriptionName("alert")3 .list();
Signal scope:
The default signal scope is the entire process engine. That is to say, you can throw a single signal between multiple process instances and take effect. Sometimes we only need to limit the scope of the signal in the process instance where an event occurs. This can be configured in this way. However, it is not in the BPMN2.0 specification and is unique to activiti, among which activiti: the default value of scope is global.
1 <signal id="alertSignal" name="alert" activiti:scope="processInstance"/>
Signal event case: I used the Activiti Explorer online flowchart designer to design two diagrams to show signal interaction.
The first process begins with the change of the insurance rules, and then the relevant personnel approves the change. If agreed, a signal indicating a change in the insurance conditions will be sent.
In the second process, the event will be caught in the area marked in the red box, so that the insurance contract can be recalculated at this time.
Signals are transmitted to all active events through broadcast, but sometimes we do not want such results, such:
The flowchart above indicates that errors that occur when the "do something" task is executed will be captured by the boundary error event and then transmitted to the branch on the concurrent path using signals, this interrupts the "do something inparallel" task. However, according to the broadcast meaning of the signal, it will also spread to all other process instances that have subscribed to the signal event. This is what we don't want. In this case, we need to call the second method of the API that describes the trigger signal for manual Association.
8.1.4 message event
A message event references a named message. Different from the signal, a message has a name and content, and a message always specifies a single receiver.
Message events are defined in the messageEventDefinition element of the BPMN file. The messageRef attribute value is from message, and the message is configured in the root element of definitions. The following is an example:
<definitions id="definitions" xmlns="http://www.omg.org/spec/BPMN/20100524/MODEL" xmlns:activiti="http://activiti.org/bpmn" targetNamespace="Examples" xmlns:tns="Examples"> <message id="newInvoice" name="newInvoiceMessage" /> <message id="payment" name="paymentMessage" /> <process id="invoiceProcess"> <startEvent id="messageStart" > <messageEventDefinition messageRef="newInvoice" /> </startEvent> ... <intermediateCatchEvent id="paymentEvt" > <messageEventDefinition messageRef="payment" /> </intermediateCatchEvent> ... </process></definitions>
Throw a message event: Activiti, as an embedded engine, does not focus on receiving messages. It depends on your environment and a specific platform, for example, you can connect to a JMS message queue or execute WebService or REST requests. This requires implementation in your application layer architecture. Activiti is only part of it.
When you receive a message in your application, you need to process it. If it is a message that starts a process instance, you can refer to the following API:
1 ProcessInstance startProcessInstanceByMessage(String messageName);2 ProcessInstance startProcessInstanceByMessage(String messageName, Map<String, Object> processVariables);3 ProcessInstance startProcessInstanceByMessage(String messageName, String businessKey, Map<String, Object> processVariables);
These APIs allow you to start process instances using referenced messages. If the process instance needs to receive these messages, you must first associate the specified process instance with the message, and then trigger the waiting process. Using RunTimeService can trigger the message-based process.
1 void messageEventReceived(String messageName, String executionId);2 void messageEventReceived(String messageName, String executionId, HashMap<String, Object> processVariables);
Process Definition for querying and subscribing to message events:
For a start event message, the message event is associated with the specified process definition. You can use ProcessDefinitionQuery to query the message subscription.
1 ProcessDefinition processDefinition = repositoryService.createProcessDefinitionQuery()2 .messageEventSubscription("newCallCenterBooking")3 .singleResult();
A clear message corresponds to a process, so the query result is usually 0 or 1. If the process definition is updated, the method returns the latest process definition.
For intermediate message events, subscribed messages are associated with specific processes.ExecutionQueryQuery:
1 Execution execution = runtimeService.createExecutionQuery()2 .messageEventSubscriptionName("paymentReceived")3 .variableValueEquals("orderId", message.getOrderId())4 .singleResult();
The following instances start the process using two different messages:
It is useful when multiple start events are required to start process instances in a unified manner.