Activiti 用户指南(Spring Boot集成)

Spring Boot集成

根据其网站,Spring Boot是一个应用程序框架,能够轻松建立独立的、生产级的基于Spring的应用程序,你能够“just run”,大多数Spring Boot应用程序只须要不多的Spring配置。mysql

Spring Boot-Activiti集成目前处于试验阶段,它已经与Spring提交者一块儿开发,可是还处于初期。web

入门

Spring Boot彻底是关于配置的约定,首先,只需将activiti-spring-boot-starter依赖项添加到你的项目中,以Maven为例:spring

<dependency>
    <groupId>org.activiti</groupId>
    <artifactId>activiti-spring-boot-starter</artifactId>
    <version>7.0.0.SR1</version>
</dependency>

这就是全部须要的,该依赖关系将向类路径中传递正确的Activiti和Spring依赖关系,你如今能够编写Spring Boot应用程序:sql

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.EnableAutoConfiguration;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;

@Configuration
@ComponentScan
@EnableAutoConfiguration
public class MyApplication {

    public static void main(String[] args) {
        SpringApplication.run(MyApplication.class, args);
    }

}

Activiti须要一个数据库来存储其数据,若是你运行上面的代码,它将为你提供一条提示性异常消息,你须要将数据库驱动程序依赖项添加到类路径中,如今,添加H2数据库依赖项:数据库

<dependency>
    <groupId>com.h2database</groupId>
    <artifactId>h2</artifactId>
</dependency>

如今能够启动该应用程序,你将看到以下输出:apache

.   ____          _            __ _ _
 /\\ / ___'_ __ _ _(_)_ __  __ _ \ \ \ \
( ( )\___ | '_ | '_| | '_ \/ _` | \ \ \ \
 \\/  ___)| |_)| | | | | || (_| |  ) ) ) )
  '  |____| .__|_| |_|_| |_\__, | / / / /
 =========|_|==============|___/=/_/_/_/
 :: Spring Boot ::        (v2.2.2.RELEASE)

2019-12-19 17:19:27.564  INFO 74776 --- [           main] c.i.a.ActivitiDemoApplication            : No active profile set, falling back to default profiles: default
2019-12-19 17:19:28.929  INFO 74776 --- [           main] o.s.b.w.embedded.tomcat.TomcatWebServer  : Tomcat initialized with port(s): 7000 (http)
2019-12-19 17:19:28.941  INFO 74776 --- [           main] o.apache.catalina.core.StandardService   : Starting service [Tomcat]
2019-12-19 17:19:28.941  INFO 74776 --- [           main] org.apache.catalina.core.StandardEngine  : Starting Servlet engine: [Apache Tomcat/9.0.29]
2019-12-19 17:19:29.027  INFO 74776 --- [           main] o.a.c.c.C.[Tomcat].[localhost].[/]       : Initializing Spring embedded WebApplicationContext
2019-12-19 17:19:29.027  INFO 74776 --- [           main] o.s.web.context.ContextLoader            : Root WebApplicationContext: initialization completed in 1422 ms
2019-12-19 17:19:29.070  INFO 74776 --- [           main] .s.s.UserDetailsServiceAutoConfiguration : 
2019-12-19 17:19:33.068  INFO 74776 --- [           main] o.a.engine.impl.ProcessEngineImpl        : ProcessEngine default created
2019-12-19 17:19:33.069  INFO 74776 --- [           main] o.a.e.i.a.DefaultAsyncJobExecutor        : Starting up the default async job executor [org.activiti.spring.SpringAsyncExecutor].
2019-12-19 17:19:33.069  INFO 74776 --- [      Thread-13] o.a.e.i.a.AcquireAsyncJobsDueRunnable    : {} starting to acquire async jobs due
2019-12-19 17:19:33.069  INFO 74776 --- [      Thread-14] o.a.e.i.a.AcquireTimerJobsRunnable       : {} starting to acquire async jobs due
2019-12-19 17:19:33.070  INFO 74776 --- [      Thread-15] o.a.e.i.a.ResetExpiredJobsRunnable       : {} starting to reset expired jobs
2019-12-19 17:19:34.049  INFO 74776 --- [           main] o.s.s.web.DefaultSecurityFilterChain     : Creating filter chain: any request, [org.springframework.security.web.context.request.async.WebAsyncManagerIntegrationFilter@66e341e9, org.springframework.security.web.context.SecurityContextPersistenceFilter@28d739f1, org.springframework.security.web.header.HeaderWriterFilter@448462f0, org.springframework.security.web.csrf.CsrfFilter@55877274, org.springframework.security.web.authentication.logout.LogoutFilter@5ec9eefa, org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter@5d1bdd4a, org.springframework.security.web.authentication.ui.DefaultLoginPageGeneratingFilter@5fb3111a, org.springframework.security.web.authentication.ui.DefaultLogoutPageGeneratingFilter@5b48f0f4, org.springframework.security.web.authentication.www.BasicAuthenticationFilter@682e422c, org.springframework.security.web.savedrequest.RequestCacheAwareFilter@7e3d2ebd, org.springframework.security.web.servletapi.SecurityContextHolderAwareRequestFilter@6f50d55c, org.springframework.security.web.authentication.AnonymousAuthenticationFilter@546ed2a0, org.springframework.security.web.session.SessionManagementFilter@132e3594, org.springframework.security.web.access.ExceptionTranslationFilter@138f0661, org.springframework.security.web.access.intercept.FilterSecurityInterceptor@32ae8f27]
2019-12-19 17:19:34.098  INFO 74776 --- [           main] o.s.b.a.e.web.EndpointLinksResolver      : Exposing 2 endpoint(s) beneath base path '/actuator'
2019-12-19 17:19:34.169  INFO 74776 --- [           main] o.a.s.AbstractActivitiSmartLifeCycle     : Starting...
2019-12-19 17:19:34.193  INFO 74776 --- [           main] o.a.s.AbstractActivitiSmartLifeCycle     : Started.
2019-12-19 17:19:34.193  INFO 74776 --- [           main] o.a.s.AbstractActivitiSmartLifeCycle     : Starting...
2019-12-19 17:19:34.195  INFO 74776 --- [           main] o.a.s.AbstractActivitiSmartLifeCycle     : Started.
2019-12-19 17:19:34.248  INFO 74776 --- [           main] o.s.b.w.embedded.tomcat.TomcatWebServer  : Tomcat started on port(s): 7000 (http) with context path ''
2019-12-19 17:19:34.251  INFO 74776 --- [           main] c.i.a.ActivitiDemoApplication            : Started ActivitiDemoApplication in 7.2 seconds (JVM running for 7.818)

所以,仅将依赖项添加到类路径并使用@EnableAutoConfiguration注解,在幕后发生了不少事情:api

  • 自动建立内存中的数据源(由于H2驱动程序在类路径中),并传递给Activiti流程引擎配置。
  • 建立并公开了一个Activiti ProcessEngine bean。
  • 全部Activiti服务都做为Spring Bean公开。
  • Spring Job Executor已建立。

另外,processes文件夹中的任何BPMN 2.0流程定义都将自动部署,建立一个文件夹processes,而后向该文件夹添加一个虚拟流程定义(名为one-task-process.bpmn20.xml)。tomcat

<?xml version="1.0" encoding="UTF-8"?>
<definitions
        xmlns="http://www.omg.org/spec/BPMN/20100524/MODEL"
        xmlns:activiti="http://activiti.org/bpmn"
        targetNamespace="Examples">

    <process id="oneTaskProcess" name="The One Task Process">
        <startEvent id="theStart" />
        <sequenceFlow id="flow1" sourceRef="theStart" targetRef="theTask" />
        <userTask id="theTask" name="my task" activiti:assignee="kermit" />
        <sequenceFlow id="flow2" sourceRef="theTask" targetRef="theEnd" />
        <endEvent id="theEnd" />
    </process>

</definitions>

还添加如下代码行以测试部署是否确实有效,CommandLineRunner是一种特殊的Spring bean,在应用程序启动时执行:session

@Configuration
@ComponentScan
@EnableAutoConfiguration
public class MyApplication {

    public static void main(String[] args) {
        SpringApplication.run(MyApplication.class, args);
    }

    @Bean
    public CommandLineRunner init(final RepositoryService repositoryService,
                                  final RuntimeService runtimeService,
                                  final TaskService taskService) {

        return new CommandLineRunner() {
            @Override
            public void run(String... strings) throws Exception {
                System.out.println("Number of process definitions : "
                    + repositoryService.createProcessDefinitionQuery().count());
                System.out.println("Number of tasks : " + taskService.createTaskQuery().count());
                runtimeService.startProcessInstanceByKey("oneTaskProcess");
                System.out.println("Number of tasks after process start: " + taskService.createTaskQuery().count());
            }
        };

    }

}

输出将如预期的那样:app

Number of process definitions : 1
Number of tasks : 0
Number of tasks after process start : 1

更改数据库和链接池

如上所述,Spring Boot是关于配置的约定,默认状况下,经过仅在类路径上使用H2,它建立了一个内存数据源,并将其传递给Activiti流程引擎配置。

要更改数据源,只需提供Datasource bean便可覆盖默认值,咱们在这里使用DataSourceBuilder类,它是Spring Boot的帮助类。若是在类路径上有Tomcat、HikariCP或Commons DBCP,则将选择其中之一(首先按Tomcat的顺序),例如,要切换到MySQL数据库:

@Bean
public DataSource database() {
    return DataSourceBuilder.create()
        .url("jdbc:mysql://127.0.0.1:3306/activiti-spring-boot?characterEncoding=UTF-8")
        .username("alfresco")
        .password("alfresco")
        .driverClassName("com.mysql.jdbc.Driver")
        .build();
}

从Maven依赖项中删除H2并将MySQL驱动程序和Tomcat链接池添加到类路径中:

如今启动应用程序后,你会看到它使用MySQL做为数据库(和Tomcat链接池框架):

org.activiti.engine.impl.db.DbSqlSession   : performing create on engine with resource org/activiti/db/create/activiti.mysql.create.engine.sql
org.activiti.engine.impl.db.DbSqlSession   : performing create on history with resource org/activiti/db/create/activiti.mysql.create.history.sql
org.activiti.engine.impl.db.DbSqlSession   : performing create on identity with resource org/activiti/db/create/activiti.mysql.create.identity.sql

屡次从新启动应用程序时,你会看到任务数量增长(H2内存数据库没法在关机后生存,而MySQL能够)。

REST支持

一般,嵌入式Activiti引擎之上须要REST API(与公司中的不一样服务进行交互),Spring Boot使这变得很是容易,将如下依赖项添加到类路径:

<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-web</artifactId>
</dependency>

建立一个新类,一个Spring服务,并建立两个方法:一个方法启动咱们的流程,另外一个方法获取给定受让人的任务列表,这里仅将简单包装Activiti调用,可是在实际状况下,这显然会更加复杂。

@Service
public class MyService {

    @Autowired
    private RuntimeService runtimeService;

    @Autowired
    private TaskService taskService;

    @Transactional
    public void startProcess() {
        runtimeService.startProcessInstanceByKey("oneTaskProcess");
    }

    @Transactional
    public List<Task> getTasks(String assignee) {
        return taskService.createTaskQuery().taskAssignee(assignee).list();
    }

}

如今,咱们能够经过使用@RestController注解类来建立REST端点,在这里,咱们仅委托给上面定义的服务。

@RestController
public class MyRestController {

    @Autowired
    private MyService myService;

    @RequestMapping(value="/process", method= RequestMethod.POST)
    public void startProcessInstance() {
        myService.startProcess();
    }

    @RequestMapping(value="/tasks", method= RequestMethod.GET, produces=MediaType.APPLICATION_JSON_VALUE)
    public List<TaskRepresentation> getTasks(@RequestParam String assignee) {
        List<Task> tasks = myService.getTasks(assignee);
        List<TaskRepresentation> dtos = new ArrayList<TaskRepresentation>();
        for (Task task : tasks) {
            dtos.add(new TaskRepresentation(task.getId(), task.getName()));
        }
        return dtos;
    }

    static class TaskRepresentation {

        private String id;
        private String name;

        public TaskRepresentation(String id, String name) {
            this.id = id;
            this.name = name;
        }

         public String getId() {
            return id;
        }
        public void setId(String id) {
            this.id = id;
        }
        public String getName() {
            return name;
        }
        public void setName(String name) {
            this.name = name;
        }

    }

}

咱们添加到应用程序类中的自动组件扫描(@ComponentScan)均可以找到@Service@RestController,再次运行应用程序类,如今,咱们可使用如cURL与REST API进行交互:

curl http://localhost:8080/tasks?assignee=kermit
[]

curl -X POST  http://localhost:8080/process
curl http://localhost:8080/tasks?assignee=kermit
[{"id":"10004","name":"my task"}]