Introdução ao Flowable
1. Visão geral
Flowable é um mecanismo de processo de negócios escrito em Java. Neste tutorial, examinaremos os detalhes dos processos de negócios e entenderemos como podemos aproveitar a API Java Flowable para criar e implantar um processo de negócios de amostra.
2. Noções básicas sobre processos de negócios
Simplificando, um Processo de Negócios é um conjunto de tarefas que, uma vez concluídas em uma ordem definida, atingem um objetivo definido . Cada tarefa em um processo de negócios possui entradas e saídas claramente definidas. Essas tarefas podem exigir intervenção humana ou podem ser completamente automatizadas.
*OMG (Object Management Group) definiu um padrão chamado http://www.bpmn.org/[Business Process Model and Notation (BPMN)]] para as empresas definirem e comunicarem seus processos* . O BPMN passou a ser amplamente suportado e aceito no setor. A API Flowable suporta totalmente a criação e a implementação de definições de processo do BPMN 2.0.
3. Criando definições de processo
Vamos supor que tenhamos um processo simples para revisão de artigos antes da publicação.
A essência desse processo é que os autores enviam um artigo e os editores o aceitam ou rejeitam. Se aceito, o artigo é publicado imediatamente; no entanto, se rejeitado, o autor é notificado por email:
https://www..com/wp-content/uploads/2019/04/Screenshot-2019-04-15-at-05.49.51.png [imagem: https://www..com/wp-content/uploads/2019/04/Screenshot-2019-04-15-at-05.49.51-1024x373.png [imagem, largura = 588, altura = 214]]
Criamos definições de processo como arquivos XML usando o padrão XML do BPMN 2.0.
Vamos definir nosso processo simples conforme o padrão BPMN 2.0:
<?xml version="1.0" encoding="UTF-8"?>
<definitions
xmlns="http://www.omg.org/spec/BPMN/20100524/MODEL"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:xsd="http://www.w3.org/2001/XMLSchema"
xmlns:bpmndi="http://www.omg.org/spec/BPMN/20100524/DI"
xmlns:omgdc="http://www.omg.org/spec/DD/20100524/DC"
xmlns:omgdi="http://www.omg.org/spec/DD/20100524/DI"
xmlns:flowable="http://flowable.org/bpmn"
typeLanguage="http://www.w3.org/2001/XMLSchema"
expressionLanguage="http://www.w3.org/1999/XPath"
targetNamespace="http://www.flowable.org/processdef">
<process id="articleReview"
name="A simple process for article review." isExecutable="true">
<startEvent id="start"/>
<sequenceFlow sourceRef="start" targetRef="reviewArticle"/>
<userTask id="reviewArticle" name="Review the submitted tutorial"
flowable:candidateGroups="editors"/>
<sequenceFlow sourceRef="reviewArticle" targetRef="decision"/>
<exclusiveGateway id="decision"/>
<sequenceFlow sourceRef="decision" targetRef="tutorialApproved">
<conditionExpression xsi:type="tFormalExpression">
<![CDATA[${approved}]]>
</conditionExpression>
</sequenceFlow>
<sequenceFlow sourceRef="decision" targetRef="tutorialRejected">
<conditionExpression xsi:type="tFormalExpression">
<![CDATA[${!approved}]]>
</conditionExpression>
</sequenceFlow>
<serviceTask id="tutorialApproved" name="Publish the approved tutorial."
flowable:class="com..service.PublishArticleService"/>
<sequenceFlow sourceRef="tutorialApproved" targetRef="end"/>
<serviceTask id="tutorialRejected" name="Send out rejection email"
flowable:class="com..service.SendMailService"/>
<sequenceFlow sourceRef="tutorialRejected" targetRef="end"/>
<endEvent id="end"/>
</process>
</definitions>
Agora, existem vários elementos aqui que são itens XML padrão, enquanto outros são específicos para o BPMN 2.0:
*O* processo inteiro está envolvido em uma tag chamada "processo", * que por sua vez, faz parte de uma tag chamada "definições" * Um processo consiste em eventos, fluxos, tarefas e gateways * Um evento é um evento inicial ou final * Um fluxo (neste exemplo, um fluxo de sequência) conecta outros elementos, como eventos e tarefas * *As tarefas são onde o trabalho real é feito; podem ser "tarefas do usuário" ou "tarefas de serviço", entre outras* * Uma tarefa do usuário requer que um usuário humano interaja com a API Flowable e tome uma ação * Uma tarefa de serviço representa uma tarefa automática, que pode ser uma chamada para uma classe Java ou mesmo uma chamada HTTP *Um gateway é executado com base no atributo "aprovado";* isso é conhecido como variável de processo *, e veremos como configurá-los mais tarde
Embora possamos criar arquivos de definição de processo em qualquer editor de texto, essa nem sempre é a maneira mais conveniente. Felizmente, porém, o Flowable também vem com opções de interface do usuário para fazer isso usando um plugin do Eclipse ou um https://www.flowable. org/docs/userguide/index.html # flowableApps [aplicativo da Web].
4. Trabalhando com API Flowable
Agora que definimos nosso processo simples em um arquivo XML conforme o padrão BPMN 2.0, precisamos de uma maneira de enviá-lo e executá-lo. O Flowable fornece a API do Process Engine para interagir com os Flowable Engines. O Flowable é muito flexível e oferece várias maneiras de implantar essa API.
Como o Flowable é uma API Java, podemos incluir o mecanismo de processo em qualquer aplicativo Java simplesmente incluindo os arquivos JAR necessários. Podemos aproveitar muito bem o Maven para gerenciar essas dependências.
Além disso, o Flowable vem com APIs REST incluídas para interagir com o Flowable via HTTP. Podemos usar essas APIs REST para praticamente fazer qualquer outra coisa possível por meio da API Flowable.
Por fim, o Flowable possui excelente suporte para integração com o Spring e o Spring Boot! Usaremos a integração do Flowable e do Spring Boot em nosso tutorial.
5. Criando um aplicativo de demonstração com o Process Engine
Vamos agora criar um aplicativo simples que agrupe um mecanismo de processo do Flowable e ofereça APIs REST para interagir com a API Flowable. Também pode haver um aplicativo da Web ou móvel na API REST para melhorar a experiência, mas pularemos isso para este tutorial.
Criaremos nossa demonstração como um aplicativo Spring Boot.
5.1. Dependências
Primeiro, vamos ver as dependências que precisamos extrair do Maven:
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.flowable</groupId>
<artifactId>flowable-spring-boot-starter</artifactId>
<version>6.4.1</version>
</dependency>
<dependency>
<groupId>com.h2database</groupId>
<artifactId>h2</artifactId>
<scope>runtime</scope>
</dependency>
As dependências que exigimos estão disponíveis no Maven Central:
-
Spring Boot Starter para Web - este é um iniciador padrão para o Spring Boot
-
Flowable Starter for Spring Boot - isso é necessário para os mecanismos de inicialização da Spring
-
H2 Database - O Flowable requer um banco de dados para armazenar dados, e H2 é o banco de dados padrão na memória
5.2. Definição do Processo
*Quando iniciamos nosso aplicativo Spring Boot, ele tenta carregar automaticamente todas as definições de processo presentes na pasta "recursos/processos".* Portanto, vamos criar um arquivo XML com a definição de processo que criamos acima, com o nome "article-workflow .bpmn20.xml ”e coloque-o nessa pasta.
5.3. Configurações
Como sabemos que o Spring Boot adota uma abordagem altamente opinativa em relação à configuração do aplicativo, isso também se aplica ao Flowable como parte do Spring Boot. Por exemplo, detectando H2 como o único driver de banco de dados no caminho de classe, o Flowable o configura automaticamente para uso .
Obviamente, todos os aspectos configuráveis podem ser configurados de maneira personalizada através das application properties. Para este tutorial, no entanto, manteremos os padrões!
5.4. Delegados Java
Em nossa definição de processo, usamos algumas classes Java que deveriam ser chamadas como partes das tarefas de serviço. * Essas classes implementam a interface JavaDelegate e são conhecidas como Delegados Java no Flowable. Agora definiremos classes fictícias para esses delegados Java:
public class PublishArticleService implements JavaDelegate {
public void execute(DelegateExecution execution) {
System.out.println("Publishing the approved article.");
}
}
public class SendMailService implements JavaDelegate {
public void execute(DelegateExecution execution) {
System.out.println("Sending rejection mail to author.");
}
}
Obviamente, devemos substituir essas classes fictícias por serviços reais para publicar um artigo ou enviar um email.
5.5. APIs REST
Por fim, vamos criar alguns pontos de extremidade REST para interagir com o mecanismo de processo e trabalhar com o processo que definimos.
Começaremos definindo um controlador REST expondo três pontos de extremidade:
@RestController
public class ArticleWorkflowController {
@Autowired
private ArticleWorkflowService service;
@PostMapping("/submit")
public void submit(@RequestBody Article article) {
service.startProcess(article);
}
@GetMapping("/tasks")
public List<Article> getTasks(@RequestParam String assignee) {
return service.getTasks(assignee);
}
@PostMapping("/review")
public void review(@RequestBody Approval approval) {
service.submitReview(approval);
}
}
Nosso controlador expõe os pontos de extremidade para enviar um artigo para revisão, buscar uma lista de artigos para revisar e, finalmente, enviar uma revisão para um artigo. Article e Approval são POJOs padrão que podem ser encontrados no repositório.
*Na verdade, estamos delegando a maior parte do trabalho para _ArticleWorkflowService _:*
@Service
public class ArticleWorkflowService {
@Autowired
private RuntimeService runtimeService;
@Autowired
private TaskService taskService;
@Transactional
public void startProcess(Article article) {
Map<String, Object> variables = new HashMap<>();
variables.put("author", article.getAuthor());
variables.put("url", article.getUrl());
runtimeService.startProcessInstanceByKey("articleReview", variables);
}
@Transactional
public List<Article> getTasks(String assignee) {
List<Task> tasks = taskService.createTaskQuery()
.taskCandidateGroup(assignee)
.list();
return tasks.stream()
.map(task -> {
Map<String, Object> variables = taskService.getVariables(task.getId());
return new Article(task.getId(), (String) variables.get("author"), (String) variables.get("url"));
})
.collect(Collectors.toList());
}
@Transactional
public void submitReview(Approval approval) {
Map<String, Object> variables = new HashMap<String, Object>();
variables.put("approved", approval.isStatus());
taskService.complete(approval.getId(), variables);
}
}
Agora, a maior parte do código aqui é bastante intuitiva, mas vamos entender os pontos mais importantes:
-
RuntimeService para instanciar o processo para um envio específico
-
TaskService para consultar e atualizar tarefas
-
Agrupando todas as chamadas do banco de dados em transações suportadas pelo Spring Armazenando detalhes como autor e URL, entre outros, em um Map e salvando com a instância do processo; são conhecidas como variáveis de processo e podemos acessá-las dentro de uma definição de processo *, como vimos anteriormente
Agora, estamos prontos para testar nosso aplicativo e mecanismo de processo. Depois de iniciar o aplicativo, podemos simplesmente usar curl ou qualquer cliente REST como o Postman para interagir com os pontos de extremidade REST que criamos.
6. Processos de teste de unidade
*O Flowable suporta diferentes versões do JUnit, incluindo o JUnit 5, para criar testes de unidade para processos de negócios.* A integração do Flowable com o Spring também oferece suporte adequado. Vamos ver um teste de unidade típico para um processo no Spring:
@ExtendWith(FlowableSpringExtension.class)
@ExtendWith(SpringExtension.class)
public class ArticleWorkflowUnitTest {
@Autowired
private RuntimeService runtimeService;
@Autowired
private TaskService taskService;
@Test
@Deployment(resources = { "processes/article-workflow.bpmn20.xml" })
void articleApprovalTest() {
Map<String, Object> variables = new HashMap<>();
variables.put("author", "[email protected]");
variables.put("url", "http://.com/dummy");
runtimeService.startProcessInstanceByKey("articleReview", variables);
Task task = taskService.createTaskQuery().singleResult();
assertEquals("Review the submitted tutorial", task.getName());
variables.put("approved", true);
taskService.complete(task.getId(), variables);
assertEquals(0, runtimeService.createProcessInstanceQuery().count());
}
}
Isso deve se parecer com um teste de unidade padrão no Spring, exceto por algumas anotações como _ @ Deployment_. Agora, a anotação _ @ Deployment_ é fornecida pelo Flowable para criar e excluir uma implantação de processo em torno dos métodos de teste.
7. Compreendendo a implantação de processos
Embora não abordemos os detalhes da implantação do processo neste tutorial, vale a pena abordar alguns aspectos que são importantes.
Normalmente, os processos são arquivados como Business Archive (BAR) e implantados em um aplicativo . Enquanto está sendo implementado, esse arquivo é verificado quanto a artefatos - como definições de processo - e processado. Você deve ter notado a convenção do arquivo de definição de processo que termina com _ ". Bpmn20.xml" ._
Embora tenhamos usado o banco de dados H2 na memória padrão em nosso tutorial, ele na verdade não pode ser usado em um aplicativo do mundo real, pelo simples motivo de que um banco de dados na memória não reterá nenhum dado entre as startups e é praticamente impossível usar em um ambiente em cluster! Portanto, devemos usar um banco de dados relacional de nível de produção e fornecer as configurações necessárias no aplicativo .
Embora o próprio BPMN 2.0 não tenha noção de controle de versão, o Flowable cria um atributo de versão para o processo, que é implementado no banco de dados . Se uma versão atualizada do mesmo processo, conforme identificada pelo atributo “id”, for implementada, uma nova entrada será criada com a versão sendo incrementada. Quando tentamos iniciar um processo por "id", o mecanismo de processo busca a versão mais recente da definição de processo implementada.
Se usarmos um dos designers que discutimos anteriormente para criar a definição do processo, já teremos uma visualização para o nosso processo. Podemos exportar o diagrama de processo como uma imagem e colocá-lo ao lado do arquivo de definição de processo XML. Se seguirmos a Convenção de nomeação sugerida pelo Flowable, essa imagem será processada pelo mecanismo de processo junto com o próprio processo. Além disso, também podemos buscar essa imagem por meio de APIs!
8. Histórico de Navegação de Instâncias de Processo
Muitas vezes, é de importância fundamental, no caso dos processos de negócios, entender o que aconteceu no passado. Podemos precisar disso para fins simples de depuração ou auditoria jurídica complexa.
O Flowable registra o que acontece durante a execução do processo e o mantém no banco de dados. Além disso, o Flowable disponibiliza esse histórico por meio de APIs para consulta e análise. Existem seis entidades sob as quais o Flowable registra isso e o HistoryService possui métodos para consultar todas elas.
Vamos ver uma consulta simples para buscar instâncias de processo concluídas:
HistoryService historyService = processEngine.getHistoryService();
List<HistoricActivityInstance> activities = historyService
.createHistoricActivityInstanceQuery()
.processInstanceId(processInstance.getId())
.finished()
.orderByHistoricActivityInstanceEndTime()
.asc()
.list();
Como podemos ver, a API para consultar dados gravados é bastante passível de composição. Neste exemplo, estamos consultando instâncias de processo concluídas por ID e ordenando-as em ordem crescente de seu horário final.
9. Processos de monitoramento
O monitoramento é um aspecto essencial de qualquer aplicativo crítico para os negócios, e ainda mais para um aplicativo que lida com os processos de negócios de uma organização. O Flowable possui várias opções para monitorar os processos em tempo real.
O Flowable fornece MBeans específicos que podemos acessar pelo JMX , não apenas para coletar dados para monitoramento, mas também para executar muitas outras atividades. Podemos integrar isso com qualquer cliente JMX padrão, incluindo jconsole, que está presente ao lado de distribuições Java padrão.
O uso do JMX para monitoramento abre muitas opções, mas é relativamente complexo e demorado. No entanto, como estamos usando o Spring Boot, estamos com sorte!
https://www..com/spring-boot-actuators [Spring Boot oferece pontos de extremidade do atuador] para reunir métricas de aplicativos por HTTP. Podemos integrar isso perfeitamente com uma pilha de ferramentas como Prometheus e Grafana para criar uma ferramenta de monitoramento de nível de produção com o mínimo esforço.
O Flowable fornece um ponto de extremidade do atuador adicional que expõe informações sobre os processos em execução. * Isso não é tão bom quanto coletar informações através do JMX, mas é rápido, fácil e, acima de tudo, suficiente.
10. Conclusão
Neste tutorial, discutimos processos de negócios e como defini-los no padrão BPMN 2.0. Em seguida, discutimos os recursos do mecanismo de processo Flowable e APIs para implantar e executar processos. Vimos como integrar isso em um aplicativo Java, especificamente no Spring Boot.
Continuando ainda mais, discutimos outros aspectos importantes dos processos, como implantação, visualização e monitoramento. Escusado será dizer que acabamos de arranhar a superfície do processo de negócios e um mecanismo poderoso como o Flowable. O Flowable possui uma API muito rica com documentação suficiente disponível. Este tutorial, no entanto, deveria ter despertado nosso interesse no assunto!
Como sempre, o código para os exemplos está disponível over no GitHub.