下列示例将演示如何使用一行代码启动Activiti流程引擎,之前的介绍中说到了Activit的核心功能是由7大Service完成的,而7大Service可以从ProcessEngine中获得,所以我们只需要获得ProcessEngine这个对象,便拥有了Activiti所有的功能。
参考源码: GitHub示例
首先做点准备工作:构建一个Maven项目引入Activiti的依赖(5.22和6.0在这儿没有区别)
pom.xml如下
com.h2database
h2
1.3.176
test
org.activiti
activiti-engine
6.0.0
接着新建一个测试类 获取流程引擎ProcessEngine 而且从引擎中获取ManagementService这个接口读取我们当前引擎的系统属性。
@Test
public void oneLineStartActiviti(){
ProcessEngine processEngine = ProcessEngineConfiguration.createStandaloneInMemProcessEngineConfiguration()
.setDatabaseSchemaUpdate(ProcessEngineConfiguration.DB_SCHEMA_UPDATE_CREATE_DROP)
.setJdbcUrl("jdbc:h2:mem:my-own-db;DB_CLOSE_DELAY=1000")
.buildProcessEngine();
ManagementService managementService = processEngine.getManagementService();
Map properties = managementService.getProperties();
for (String s : properties.keySet()) {
System.out.println(s+":"+properties.get(s));
}
}
控制台输出如下:
cfg.execution-related-entities-count:false 先忽略此属性
next.dbid:1 下一个主键ID
schema.version:6.0.0.4 当前数据库版本
schema.history:create(5.22.0.0) upgrade(5.22.0.0->6.0.0.4) 数据库升级历史
不过上述项目是通过内存数据库建立的测试引擎,那么我们如何在本地的数据库中建立我们的流程引擎呢,下面我将以Mysql为例(主流数据库都是支持的,不用改配置文件,自动识别)
在本地数据库中启动流程引擎,且创建数据库表
- 引入mysql驱动依赖
mysql
mysql-connector-java
5.1.40
- 新建Activiti的配置文件
这里配置的核心是processEngineConfiguration这个Bean,因为通过这个bean的buildProcessEngine()方法我们可以构建我们的流程引擎对象。
- 使用Activiti配置类读取配置文件初始化流程引擎
@Test
public void testDefaltEngine(){
ProcessEngineConfiguration processEngineConfiguration = ProcessEngineConfiguration.createProcessEngineConfigurationFromResource("activiti.cfg.xml");
ProcessEngine processEngine = processEngineConfiguration.buildProcessEngine();
Assert.assertEquals("MyProcessEngine", processEngine.getName());
RuntimeService runtimeService = processEngine.getRuntimeService();
Assert.assertNotNull(runtimeService);
TaskService taskService = processEngine.getTaskService();
Assert.assertNotNull(taskService);
}
- 最简单的获取方式是ProcessEngines.getDefaultProcessEngine()方法,它会自动去ClassPath查找activiti.cfg.xml文件,并按照配置文件创建流程引擎(如果你是按照我的配置来的,这里会报错)
@Test
public void getDefaultProcessEngine(){
ProcessEngine engine = ProcessEngines.getDefaultProcessEngine();
Assert.assertNotNull(engine);
}
大家有没有发现Activiti的配置文件其实就是一个Spring的配置文件
所以这里我们可以不通过ProcessEngineConfiguration去读取配置文件来创建引擎,我们可以让Spring去实例化这个类(真正和Spring整合的时候需要更改一下配置文件中配置的Bean对象,后期会有专门的文章来讲解如何与Spring整合)
- 使用Spring容器实例化流程引擎
引入Activiti-Spring依赖
org.activiti
activiti-spring
6.0.0
@Test
public void testEngine() {
ApplicationContext context = new ClassPathXmlApplicationContext(new String[] { "activiti.cfg.xml" });
ProcessEngineConfiguration processEngineConfiguration = (ProcessEngineConfiguration) context.getBean("processEngineConfiguration");
ProcessEngine processEngine = processEngineConfiguration.buildProcessEngine();
Assert.assertEquals("MyProcessEngine", processEngine.getName());
RuntimeService runtimeService = processEngine.getRuntimeService();
Assert.assertNotNull(runtimeService);
TaskService taskService = processEngine.getTaskService();
Assert.assertNotNull(taskService);
}
这里有个很有意思的坑,我测试了几遍都是获取不到ProcessEngine,同时教大家一个小技巧,因为我们配置的数据库策略databaseSchemaUpdate为 true 所以在引擎启动的时候一定会创建数据库表,所以在刚才的单元测试中我根据数据库判断流程引擎一定是启动的,点进源码可以看到getDefaultProcessEngine()是会将类路径下的所有配置文件都创建一次流程引擎,最后将这些引擎存入Map中Key为引擎名称,value为引擎对象。而getDefaultProcessEngine()只会从这个map中查找名为default的对象
public static final String NAME_DEFAULT = "default";
protected static Map processEngines = new HashMap();
/** Initializes all process engines that can be found on the classpath for
* resources activiti.cfg.xml
(plain Activiti style configuration)
* and for resources activiti-context.xml
(Spring style configuration). */
public synchronized static void init() {
if (!isInitialized()) {
if(processEngines == null) {
// Create new map to store process-engines if current map is null
processEngines = new HashMap();
}
ClassLoader classLoader = ReflectUtil.getClassLoader();
Enumeration resources = null;
try {
resources = classLoader.getResources("activiti.cfg.xml");
} catch (IOException e) {
throw new ActivitiIllegalArgumentException("problem retrieving activiti.cfg.xml resources on the classpath: "+System.getProperty("java.class.path"), e);
}
// Remove duplicated configuration URL's using set. Some classloaders may return identical URL's twice, causing duplicate startups
Set configUrls = new HashSet();
while (resources.hasMoreElements()) {
configUrls.add( resources.nextElement() );
}
for (Iterator iterator = configUrls.iterator(); iterator.hasNext();) {
URL resource = iterator.next();
log.info("Initializing process engine using configuration '{}'", resource.toString());
initProcessEnginFromResource(resource);
} 略...
所以这里我们只需要将配置文件中的流程名称配置删除就能正常获取流程引擎了
使用Activiti配置类读取配置文件方式还有以下几种,不过原理都是差不多的,了解即可
//使用IO流读取配置
InputStream stream = this.getClass().getClassLoader().getResourceAsStream("activiti.cfg.xml");
ProcessEngineConfiguration configuration = ProcessEngineConfiguration.createProcessEngineConfigurationFromInputStream(stream);
//默认配置
configuration = ProcessEngineConfiguration.createProcessEngineConfigurationFromResourceDefault();
//指定文件名
configuration = ProcessEngineConfiguration.createProcessEngineConfigurationFromResource("activiti.cfg.xml");
还可以借助Activiti给我们提供的单元测试类ActivitiRule来获取引擎以及7大Service
@Rule
public ActivitiRule activitiRule = new ActivitiRule();
@Test
public void activitiUnitTest(){
ProcessEngine engine = activitiRule.getProcessEngine();
System.out.println(engine.getName());
Map properties = engine.getManagementService().getProperties();
for (String s : properties.keySet()) {
System.out.println(s+":"+properties.get(s));
}
}
通过流程引擎获取7大Service接口,后续我会讲解如何使用这7大Service来真正的使用Activiti
@Test
public void setActivitiRule(){
ProcessEngine engine = activitiRule.getProcessEngine();
//这里不局限于使用activitiRule类获取的引擎,前面所有的方式获取的流程引擎都可以按照如下方式使用
IdentityService identityService = engine.getIdentityService();
RepositoryService repositoryService = engine.getRepositoryService();
RuntimeService runtimeService = engine.getRuntimeService();
TaskService taskService = engine.getTaskService();
FormService formService = engine.getFormService();
ManagementService managementService = engine.getManagementService();
HistoryService historyService = engine.getHistoryService();
}