activiti原始碼剖析--流程引擎ProcessEngine的獲取
感謝冀正,張志祥前輩《Activiti權威指南》
activiti原始碼剖析--流程引擎ProcessEngine的獲取
前言
本篇文章通過原始碼進行分析ProcessEngine是如何被創建出來,在學習activiti的同時,通過原始碼進行分析以對activiti流程引擎進行更深層次的理解深入。
一、流程配置檔案
Acticiti配置檔案的風格使用了Spring中的檔案配置方式,這樣有什麼好處呢?那當然從Spring的特性IOC說起,依賴注入,控制反轉,這裡就不再多說,選取這樣的配置方式也說明了,Activiti在設計之時就考慮到了與spring的融合。activiti的配置檔案型別分為 普通配置 和Spring配置(這裡說明一下,activiti的配置檔案方式採用Spring方式,但是activiti可以整合Spring開發,也可以不整合,所以後者的Spring配置方式其實也就是整合Spring進行開發)
- 普通配置檔名稱為activiti.cfg.xml
<?xml version="1.0" encoding="UTF-8"?> <beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://www.springframework.org/schema/beanshttp://www.springframework.org/schema/beans/spring-beans.xsd"> <bean id="processEngineConfiguration" class="org.activiti.engine.impl.cfg.StandaloneProcessEngineConfiguration"> <property name="jdbcUrl" value="jdbc:mysql://localhost:3306/db_activiti" /> <property name="jdbcDriver" value="com.mysql.jdbc.Driver" /> <property name="jdbcUsername" value="root" /> <property name="jdbcPassword" value="1234" /> <property name="databaseSchemaUpdate" value="true" /> </bean> </beans>
- Spring配置檔名稱為activiti-context.xml
<?xml version="1.0" encoding="UTF-8"?> <beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:tx="http://www.springframework.org/schema/tx" xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx.xsd"> <!--配置資料來源--> <bean id="dataSource" class="org.springframework.jdbc.datasource.SimpleDriverDataSource"> <property name="driverClass" value="com.mysql.jdbc.Driver"/> <property name="url" value="jdbc:mysql://localhost:3306/spring_activiti"/> <property name="username" value="root"/> <property name="password" value="1234"/> </bean> <!--配置事務管理器--> <bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager"> <!--注入資料來源--> <property name="dataSource" ref="dataSource"/> </bean> <!--配置註解方式配置事務--> <tx:annotation-drivenproxy-target-class="true" transaction-manager="transactionManager"/> <!--定義基於Spring的引擎配置物件BEAN--> <bean id="processEngineConfiguration" class="org.activiti.spring.SpringProcessEngineConfiguration"> <property name="dataSource" ref="dataSource"/> <property name="transactionManager" ref="transactionManager"/> <property name="databaseSchemaUpdate" value="true"/> <property name="deploymentResources" value="classpath:userAndGroupTest.bpmn20.xml"/> <!--<property name="jobExecutorActivate" value="false"/>--> </bean> <!--配置引擎工廠物件BEAN--> <bean id="processEngineFactory" class="org.activiti.spring.ProcessEngineFactoryBean"> <property name="processEngineConfiguration" ref="processEngineConfiguration"/> </bean> <!--使用spring提供的工廠方式獲取actititi7個service介面物件--> <bean id="repositoryService" factory-bean="processEngineFactory" factory-method="getRepositoryService"/> ....7大服務 </beans>
二、構造流程引擎例項物件
獲取流程引擎例項物件程式碼如下
ProcessEngine defaultProcessEngine = ProcessEngines.getDefaultProcessEngine(); //這裡也可以通過自定義流程引擎名稱獲取 //ProcessEngines.getProcessEngine(String processEngineName) RepositoryService repositoryService = defaultProcessEngine.getRepositoryService(); assert repositoryService !=null;
ProcessEngines:該類負責管理所有的流程引擎ProcessEngine集合,並負責流程引擎例項物件的註冊、獲取、登出等操作。
只需要ProcessEngines.getDefaultProcessEngine();一句話即可獲取到我們的重要角色:processEngine,那麼它是怎麼被獲取到的呢?接下來圍繞這一話題進行原始碼剖析。
ProcessEngines.java原始碼
public static ProcessEngine getDefaultProcessEngine() { return getProcessEngine("default"); }
相信從這裡也可看出來,在通過ProcessEngines獲取流程引擎的時候,不管使用預設的方式還是通過指定流程引擎名稱,其實都是呼叫的ProcessEngine(processEngineName)方法獲取
public static ProcessEngine getProcessEngine(String processEngineName) { if (!isInitialized()) { init(); } return (ProcessEngine)processEngines.get(processEngineName); }
在獲取流程引擎的前提要先進行初始化。如果已經完成初始化,那麼返回指定名稱的流程引擎物件。從這裡也可以看出Activiti支援多個流程引擎例項物件一起執行,通過流程引擎名稱進行區分。
protected static Map<String, ProcessEngine> processEngines = new HashMap();
在這裡processEngines為MAP結構,key為流程引擎名稱,value為流程引擎例項物件。
接下來看看Activiti是如何做初始化準備工作的
public static synchronized void init() { if (!isInitialized()) { if (processEngines == null) { processEngines = new HashMap(); } ClassLoader classLoader = ReflectUtil.getClassLoader(); Enumeration resources = null; try { resources = classLoader.getResources("activiti.cfg.xml"); } catch (IOException var6) { throw new ActivitiIllegalArgumentException("problem retrieving activiti.cfg.xml resources on the classpath: " + System.getProperty("java.class.path"), var6); } HashSet configUrls = new HashSet(); while(resources.hasMoreElements()) { configUrls.add(resources.nextElement()); } Iterator iterator = configUrls.iterator(); while(iterator.hasNext()) { URL resource = (URL)iterator.next(); log.info("Initializing process engine using configuration '{}'", resource.toString()); initProcessEngineFromResource(resource); } try { resources = classLoader.getResources("activiti-context.xml"); } catch (IOException var5) { throw new ActivitiIllegalArgumentException("problem retrieving activiti-context.xml resources on the classpath: " + System.getProperty("java.class.path"), var5); } while(resources.hasMoreElements()) { URL resource = (URL)resources.nextElement(); log.info("Initializing process engine using Spring configuration '{}'", resource.toString()); initProcessEngineFromSpringResource(resource); } setInitialized(true); } else { log.info("Process engines already initialized"); } }
首先再次判斷確認流程引擎是否已經被初始化。 接下的工作就是定位activiti配置檔案啦,(在這裡可以看到是從根路徑中載入配置檔案,為什麼的話,可以從這裡補充補充知識 getClass().getResource()和classLoader.getResource() )這裡也可以看出activiti配置檔案的名稱啦。
普通配置檔案(activiti.cfg.xml)通過initProcessEngineFromResource(resource);進行初始化載入,整合spring配置檔案通過initProcessEngineFromSpringResource(resource);進行初始化載入。
2.1、初始化流程引擎之普通配置檔案
再進入initProcessEngineFromResource(resource)首先是做了大量的準備工作,準備工作其實也就是清除已經存在同名稱的流程引擎資訊,之後呼叫buildProcessEngine(resourceUrl)構造流程引擎例項物件,然後放入新的流程引擎資訊相關資訊。
private static ProcessEngine buildProcessEngine(URL resource) { InputStream inputStream = null; ProcessEngine var3; try { inputStream = resource.openStream(); ProcessEngineConfiguration processEngineConfiguration = ProcessEngineConfiguration.createProcessEngineConfigurationFromInputStream(inputStream); var3 = processEngineConfiguration.buildProcessEngine(); } catch (IOException var7) { throw new ActivitiIllegalArgumentException("couldn't open resource stream: " + var7.getMessage(), var7); } finally { IoUtil.closeSilently(inputStream); } return var3; }
在 buildProcessEngine(resourceUrl) 中進入ProcessEngineConfiguration processEngineConfiguration = ProcessEngineConfiguration.createProcessEngineConfigurationFromInputStream(inputStream);核心程式碼
public static ProcessEngineConfiguration createProcessEngineConfigurationFromInputStream(InputStream inputStream) { return createProcessEngineConfigurationFromInputStream(inputStream, "processEngineConfiguration"); } public static ProcessEngineConfiguration createProcessEngineConfigurationFromInputStream(InputStream inputStream, String beanName) { return BeansConfigurationHelper.parseProcessEngineConfigurationFromInputStream(inputStream, beanName); }
從以上程式碼可以看出是在獲取通過spring容器管理的id為processEngineConfiguration的bean物件。即org.activiti.engine.impl.cfg.StandaloneProcessEngineConfiguration(配置檔案中配置)。之後Spring會解析xml配置檔案例項化org.activiti.engine.impl.cfg.StandaloneProcessEngineConfiguration物件

ProcessEngineConfigurationImpl類結構.png
在例項化org.activiti.engine.impl.cfg.StandaloneProcessEngineConfiguration的同時,也會對其父類進行初始化,點選ProcessEngineConfigurationImpl類進入檢視
protected RepositoryService repositoryService = new RepositoryServiceImpl(); protected RuntimeService runtimeService = new RuntimeServiceImpl(); protected HistoryService historyService = new HistoryServiceImpl(this); protected IdentityService identityService = new IdentityServiceImpl(); protected TaskService taskService = new TaskServiceImpl(this); protected FormService formService = new FormServiceImpl(); protected ManagementService managementService = new ManagementServiceImpl(); protected DynamicBpmnService dynamicBpmnService = new DynamicBpmnServiceImpl(this);
也就是在進行各種服務類物件的初始化。在這裡完成了對流程引擎配置物件的初始化,注意上述buildProcessEngine(resourceUrl)中在初始化流程引擎配置物件之後,通過流程引擎配置物件來build processEngine,var3 = processEngineConfiguration.buildProcessEngine();這裡方法的實現是在各種配置類的父類(ProcessEngineConfigurationImpl)中進行了實現
ProcessEngineConfigurationImpl.java
public ProcessEngine buildProcessEngine() { this.init(); ProcessEngineImpl processEngine = new ProcessEngineImpl(this); if (this.isActiviti5CompatibilityEnabled && this.activiti5CompatibilityHandler != null) { Context.setProcessEngineConfiguration(processEngine.getProcessEngineConfiguration()); this.activiti5CompatibilityHandler.getRawProcessEngine(); } this.postProcessEngineInitialisation(); return processEngine; }
該操作完成了以下操作:
-
呼叫init方法初始化了各種屬性值
這裡呢就是對一些諸如資料來源、配置器、流程圖片生成器、表示式管理器等一系列的初始化。
-
例項化ProcessEngineImpl類
那麼這裡就是例項化流程引擎的重頭戲了。看程式碼實現
public ProcessEngineImpl(ProcessEngineConfigurationImpl processEngineConfiguration) { this.processEngineConfiguration = processEngineConfiguration; this.name = processEngineConfiguration.getProcessEngineName(); this.repositoryService = processEngineConfiguration.getRepositoryService(); ....這裡就是在填充7大服務物件 this.dynamicBpmnService = processEngineConfiguration.getDynamicBpmnService(); this.asyncExecutor = processEngineConfiguration.getAsyncExecutor();//非同步作業執行器 this.commandExecutor = processEngineConfiguration.getCommandExecutor();//命令執行器 this.sessionFactories = processEngineConfiguration.getSessionFactories(); this.transactionContextFactory = processEngineConfiguration.getTransactionContextFactory();//事務 ... if (processEngineConfiguration.isUsingRelationalDatabase() && processEngineConfiguration.getDatabaseSchemaUpdate() != null) { this.commandExecutor.execute(processEngineConfiguration.getSchemaCommandConfig(), new SchemaOperationsProcessEngineBuild());//這裡就是通過databaseSchemaUpdate值進行資料庫生成策略 } ... ProcessEngines.registerProcessEngine(this);//註冊流程引擎 if (this.asyncExecutor != null && this.asyncExecutor.isAutoActivate()) { this.asyncExecutor.start();//啟動非同步執行器 } if (processEngineConfiguration.getProcessEngineLifecycleListener() != null) { processEngineConfiguration.getProcessEngineLifecycleListener().onProcessEngineBuilt(this);//觸發流程引擎生命週期監聽器 } processEngineConfiguration.getEventDispatcher().dispatchEvent(ActivitiEventBuilder.createGlobalEvent(ActivitiEventType.ENGINE_CREATED)); }
上述程式碼看出,在對一些屬性裝配完成之後,操作引擎表(具體策略以及如何生成看這裡 activiti原始碼剖析之操作引擎表 )之後註冊流程引擎,也就是將processEngineImpl例項物件註冊進ProssEngines中,到這裡想必已經明白了文章開始程式碼,ProcessEngines是如何獲取到processEngine的。
到這裡,大致已經明白是ProcessEngine流程引擎是如何初始化並且註冊進processEngines流程引擎管理物件了。
希望大家指正,內容也會隨著學習深入與實踐的過程中進行改善
