Service tasks are one of the fundamental building blocks of any process. They allow you to implement complex business logic, make calculations, talk to external systems and services, and more. In Activiti there are a number of ways in which a service task can be implemented:
As a Spring Bean method (what this article covers)
What implementation approach you choose depend on the use-case. If you don’t need to use any Spring beans in your implementation then use a POJO Java Delegate. If your service task implementation needs to use, for example out-of-the-box Spring beans, then use the Spring Bean Java Delegate. These two approaches uses a “one operation per service task” implementation. If you need your implementation to support multiple operations, then go with the Spring bean method implementation.
There is also a runtime twist to this, most likely there will be multiple process instances calling the same service task implementation. And the same service task implementation might be called from multiple service tasks in a process. The implementation behaves differently depending on approach:
POJO Java Delegate- inside a process instance you have one class instance per service task, between process instances you share class instances per service task
Spring Bean Java Delegate- same Spring bean (i.e. class instance) is used within a process instance and between process instances
Spring Bean method- same Spring bean (i.e. class instance) is used within a process instance and between process instances but there is no field injection and all data is passed in via method params, so thread-safe
What this basically means is that if you use a third party class inside a Java Delegate, then it needs to be thread safe as it can be called by multiple concurrent threads. If you use a Spring bean Java Delegate approach then the same thing applies, if you inject beans they need to all be thread safe. With the Spring bean approach you can also change the bean instantiation scope to be PROTOTYPE, which means an instance will be created per service task.
Or you can use the Spring Bean Method approach, which this article covers, and which solves a lot of concurrency issues.
Source code for the Activiti Developer Series can be foundhere.
Before starting with your service task implementation make sure toset upa proper Activiti Extension project.
Implementing a Hello World Spring Bean Method
Let’s start the usual way with a Hello World Spring Bean Method. This differs from the other approaches as we are not implementing one specificexecutemethod for a Java Delegate. Here we are implementing as many methods as we want, serving as many service tasks as we need from the same Spring Bean implementation.
So every method we provide inside the Spring Bean class implementation is a potential Service Task implementation. In this case we are going to use thecustomGreetingmethod as the implementation and pass in differenttexts depending on what service task that is calling the method.
This is completely thread safe as we are not using any class members, just passing in data via a method parameter. However, the logging library needs to be thread safe as this method can be called from multiple concurrent threads, serving different service tasks.
Testing the method
Now to test the Spring Bean method as a service task implementation create a process model looking like this:
And the Service Task is connected to the Spring Bean method implementation via theExpressionproperty:
The first service task has the following Expression:
When we run this process it will print similar logs to the following:
03:11:10,919 [http-nio-8080-exec-7] INFO com.activiti.extension.bean.service.HelloWorldService - [Java object=com.activiti.extension.bean.service.HelloWorldService@4ed3dbd3]
03:11:10,919 [http-nio-8080-exec-7] INFO com.activiti.extension.bean.service.HelloWorldService - Hello World: ServiceTask 1
03:11:10,920 [http-nio-8080-exec-7] INFO com.activiti.extension.bean.service.HelloWorldService - [Java object=com.activiti.extension.bean.service.HelloWorldService@4ed3dbd3]
03:11:10,920 [http-nio-8080-exec-7] INFO com.activiti.extension.bean.service.HelloWorldService - Hello World: ServiceTask 2
We can see here that all the context for the method is passed in as a parameter. In this case it’s only a String of text, but could be any parameters you like. So using the same Spring bean works fine as the logging library is thread safe.
Now, what about process information and process variables? How do I get to them? That’s easy, just add an extra parameter of typeDelegateExecution:
In a Spring Bean Method we access process variables in the same way as in a POJO Java Delegate,so read its docs.
Returning data from the Spring Bean Method
There are probably many situations where we would want to return some data from the Spring Bean method and use it in the process. We can achieve this by defining return values for the service task. First update thecustomGreetingmethod to return aString: