Spring Boot集成
根据其网站,Spring Boot是一个应用程序框架,可以轻松创建独立的、生产级的基于Spring的应用程序,你可以“just run”,大多数Spring Boot应用程序只需要很少的Spring配置。
Spring Boot-Activiti集成目前处于试验阶段,它已经与Spring提交者一起开发,但是还处于初期。
入门
Spring Boot完全是关于配置的约定,首先,只需将activiti-spring-boot-starter
依赖项添加到你的项目中,以Maven为例:
org.activiti
activiti-spring-boot-starter
7.0.0.SR1
这就是所有需要的,该依赖关系将向类路径中传递正确的Activiti和Spring依赖关系,你现在可以编写Spring Boot应用程序:
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数据库依赖项:
com.h2database
h2
现在可以启动该应用程序,你将看到如下输出:
. ____ _ __ _ _
/\\ / ___'_ __ _ _(_)_ __ __ _ \ \ \ \
( ( )\___ | '_ | '_| | '_ \/ _` | \ \ \ \
\\/ ___)| |_)| | | | | || (_| | ) ) ) )
' |____| .__|_| |_|_| |_\__, | / / / /
=========|_|==============|___/=/_/_/_/
:: 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
注解,在幕后发生了很多事情:
- 自动创建内存中的数据源(因为H2驱动程序在类路径中),并传递给Activiti流程引擎配置。
- 创建并公开了一个Activiti
ProcessEngine
bean。 - 所有Activiti服务都作为Spring Bean公开。
- Spring Job Executor已创建。
另外,processes文件夹中的任何BPMN 2.0流程定义都将自动部署,创建一个文件夹processes,然后向该文件夹添加一个虚拟流程定义(名为one-task-process.bpmn20.xml)。
还添加以下代码行以测试部署是否确实有效,CommandLineRunner
是一种特殊的Spring bean,在应用程序启动时执行:
@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());
}
};
}
}
输出将如预期的那样:
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使这变得非常容易,将以下依赖项添加到类路径:
org.springframework.boot
spring-boot-starter-web
创建一个新类,一个Spring服务,并创建两个方法:一个方法启动我们的流程,另一个方法获取给定受让人的任务列表,这里仅将简单包装Activiti调用,但是在实际情况下,这显然会更加复杂。
@Service
public class MyService {
@Autowired
private RuntimeService runtimeService;
@Autowired
private TaskService taskService;
@Transactional
public void startProcess() {
runtimeService.startProcessInstanceByKey("oneTaskProcess");
}
@Transactional
public List 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 getTasks(@RequestParam String assignee) {
List tasks = myService.getTasks(assignee);
List dtos = new ArrayList();
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"}]