瘋狂Activiti6.0連載(19)Activiti整合Spring

 本文節選自《瘋狂Workflow講義(第2版)》

京東購買地址:https://item.jd.com/12246565.html

工作流Activiti6電子書http://blog.csdn.net/boxiong86/article/details/78488562

工作流Activiti6教學視頻http://blog.csdn.net/boxiong86/article/details/78608585

 

Activiti整合Spring

Activiti的配置文件就是一份Spring配置文件,但是默認情況下,只將ProcessEngineConfiguration作爲一個bean讀取和使用如果想使用Spring的更多功能(例如聲明式事務管理),可以與Spring容器進行進一步的整合,將ProcessEngineConfiguration和其他的對象都交由Spring進行管理,Spring容器中的其他組件,可以通過依賴注入的方式來使用Activiti的這些對象,例如前面章節講述的多個Service

SpringProcessEngineConfiguration

一個ProcessEngineConfiguration實例表示流程引擎的配置,Activiti提供了StandaloneProcessEngineConfigurationStandaloneInMemProcessEngineConfiguration等類,在流程引擎的配置文件中,可以使用這些子類作爲beanclass,這些類的描述見本書的流程引擎配置章節

如果需要和Spring整合,就要使用ActivitiSpring模塊中的SpringProcessEngineConfiguration作爲流程引擎配置該類類繼承ProcessEngineConfigurationImpl在配置這個類時,可以爲ProcessEngineConfiguration注入TransactionManager,也可以在配置中指定自動部署的資源文件及部署模式,代碼清單16-6SpringProcessEngineConfiguration的部分代碼。

代碼清單16-6org.activiti.spring.SpringProcessEngineConfiguration

public class SpringProcessEngineConfiguration extends ProcessEngineConfigurationImpl {

 

    protected PlatformTransactionManager transactionManager;

    protected String deploymentName = "SpringAutoDeployment";

    protected Resource[] deploymentResources = new Resource[0];

 

    @Override

    public ProcessEngine buildProcessEngine() {

        ProcessEngine processEngine = super.buildProcessEngine();

        ProcessEngines.setInitialized(true);

        autoDeployResources(processEngine);

       return processEngine;

     } 

    ...省略其他源代碼

}

SpringProcessEngineConfiguration中有一個transactionManager屬性,使用這個類作爲流程引擎beanclass,可以在配置文件中指定TransactionManager,另外還有一個deploymentResources屬性,可以爲流程引擎的bean指定流程文件資源。

如果Activiti不與Spring進行整合,那麼默認情況下,將會使用myBatis的事務管理,使用了SpringProcessEngineConfiguration後,在配置中必須指定一個SpringTransactionManagerSpringProcessEngineConfiguration的配置如代碼清單16-7所示。

代碼清單16-7codes\16\16.2\integrate-spring\resource\activiti.cfg.xml

    <!--配置數據源-->

    <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/act" />

        <property name="username" value="root" />

        <property name="password" value="123456" />

    </bean>

 

    <!--配置事務管理器-->

    <bean id="transactionManager"

        class="org.springframework.jdbc.datasource.DataSourceTransactionManager">

        <property name="dataSource" ref="dataSource" />

    </bean>

 

    <!--流程引擎的配置bean -->

    <bean id="processEngineConfiguration" class="org.activiti.spring.SpringProcessEngineConfiguration">

        <property name="dataSource" ref="dataSource"/>

        <property name="databaseSchemaUpdate" value="true" />

        <property name="transactionManager" ref="transactionManager"/>

        <property name="deploymentResources" value="bpmn/EngineConfigurationTest.bpmn" />

    </bean>

在代碼清單16-7中,配置了三個bean,其中使用了Spring的數據源來設置“dataSourcebean,使用了SpringDataSourceTransactionManager作爲事務管理器,在事務管理器中注入了數據源,在配置processEngineConfiguration時,將數據源和事務管理器注入

本例的數據源使用了SpringSimpleDriverDataSource,在實際應用中,可以選擇C3P0DBCP等數據源連接池,如果業務系統中同時使用了Hibernate框架,可以再加入SessionFactory等配置。

在本例中,還爲processEngineConfiguration注入了deploymentResources屬性,將一份流程文件交給SpringProcessEngineConfiguration,讓其自動進行流程文件部署,而不需要再向前面章節那樣,通過編碼的方式進行流程文件部署,如果需要部署classpath下的多個流程文件,可以使用value="classpath*:/bpmn/*.bpmn”這樣的配置,如果使用了多份已知的流程文件,也可以使用以下的配置:

       <property name="deploymentResources">

            <list>

                <value>/bpmn/EngineConfigurationTest.bpmn</value>

                <value>/bpmn/EngineConfigurationTest2.bpmn</value>

            </list>

        </property>

對於一些流程較爲固定的系統,可以使用配置deploymentResources這種方式來加載流程文件,而對於一些流程多變的系統,筆者建議還是通過編碼的方式來加載,流程文件的路徑或者內容均可以作爲加載方法的參數,實現動態加載。

資源的部署模式

根據前面小節可知,在流程引擎配置時可加入deploymentResources配置,讓Spring容器在初始化時自動幫我們部署指定的流程文件如果希望對部署模式進行配置,可以使用deploymentMode屬性。該屬性可配置爲以下值:

     default默認值,在進行自動部署時,全部的資源將會被看作一次部署,只產生一條件部署數據(Depoyment)。

     single-resource每一個資源文件都會進行單獨一次部署,多個文件將會產生多條部署數據。

     resource-parent-folder根據每個資源文件的所在目錄作爲一次部署,例如某個目錄下有多份資源文件,那麼這些資源文件將會被當作一次部署,產生一條件部署數據。

ProcessEngineFactoryBean

前面的章節中,一般情況使用ProcessEnginesgetDefaultProcessEngine方法得到默認的ProcessEngine實例。如果將創建ProcessEngine的過程也交由Spring容器代爲完成,可以使用ProcessEngineFactoryBeanProcessEngineFactoryBean也是ActivitiSpring模塊提供的類,主要用於維護一個ProcessEngine實例,向ProcessEngineFactoryBean設置(注入)一個流程引擎配置(ProcessEngineConfiguration)實例它就會自動創建ProcessEngine在得到Spring上下文後,通過getBean方法得到ProcessEngineFactoryBeanbean,實際上得到的是一個ProcessEngine實例,這是由於ProcessEngineFactoryBean類實現了FactoryBean接口,在getBean時會調用FactoryBeangetObject方法返回一個具體的bean實例,而ProcessEngineFactoryBeangetObject方法,返回的是一個ProcessEngine實例。代碼清單16-8ProcessEngineFactoryBean的配置。

代碼清單16-8codes\16\16.2\integrate-spring\resource\activiti.cfg.xml

    <!--流程引擎的bean -->

    <bean id="processEngine" class="org.activiti.spring.ProcessEngineFactoryBean">

        <property name="processEngineConfiguration" ref="processEngineConfiguration" />

   </bean>

需要注意的是,processEnginebeanclass並不是ProcessEngine的實現類,通過getBean方法拿到的,纔是一個ProcessEngine實例。16.2.1小節,配置了processEngineConfigurationbean,在本小節配置了processEnginebean,那麼啓動流程引擎的話,就可以直接使用Spring的方式,如代碼清單16-9所示。

代碼清單16-9

codes\16\16.2\integrate-spring\src\org\crazyit\activiti\EngineConfigurationTest.java

    public static void main(String[] args) {

        //創建Spring上下文

        ApplicationContext ctx = new ClassPathXmlApplicationContext(

                new String[] { "activiti.cfg.xml" });

        //獲取processEngine bean

        ProcessEngine engine = (ProcessEngine)ctx.getBean("processEngine");

        System.out.println("流程引擎實現類:" + engine.getClass().getName());

    }

代碼清單16-9,像普通的Spring應用一樣,創建Spring上下文,將Activiti的配置文件當作一份普通的Spring配置文件,再獲取processEnginebean,本例中輸出ProcessEngine以及TaskService的實例,運行代碼清單16-9,結果如下:

流程引擎實現類:org.activiti.engine.impl.ProcessEngineImpl

bean中注入Activiti服務

通過上一小節,將ProcesseEngine交由SpringIoC容器進行管理,那Activiti的服務同樣可以交由Spring進行管理Activiti的各個服務組件,均在ProcessEngineConfigurationImpl進行創建(使用new關鍵字),通過ProcesseEngine對象的getXXXService可以得到這些服務的實例。因爲這些服務對象的創建由Activiti完成,所以Spring並不需要管理它們的創建過程,代碼清單16-10中配置了這些服務對象的bean

代碼清單16-10codes\16\16.2\integrate-spring\resource\activiti.cfg.xml

    <!--服務組件的bean -->

    <bean id="repositoryService" factory-bean="processEngine"factory-method="getRepositoryService" />

    <bean id="runtimeService" factory-bean="processEngine"factory-method="getRuntimeService" />

    <bean id="taskService" factory-bean="processEngine"factory-method="getTaskService" />

    <bean id="historyService" factory-bean="processEngine"   factory-method="getHistoryService" />

    <bean id="managementService" factory-bean="processEngine"       factory-method="getManagementService" />

根據代碼清單16-10可知,各個Activiti服務組件,通過實例工廠方法創建bean,此時各個bean不再設置class屬性,而由factory-bean屬性來指定工廠beanid,並且使用factory-method確定產生bean實例的工廠方法。使用這種模式,bean的創建不再由Spring完成,Spring只會負責調用指定的工廠方法來創建實例Spring會對這些實例進行管理

Spring中配置好這些bean後,如果要在自己的業務bean中使用Activiti的這些服務,直接使用依賴注入就可以實現,如:

    <bean id="myService" class="myClass">

        <property name="runtimeService" ref="runtimeService"></property>

    </bean>

當然,還需要在業務類中爲相應的Activiti服務對象加入setter方法。

Activiti中使用Springbean

在其他的業務bean中可以使用Activiti的服務,那麼在流程元素中,同樣可以使用這些業務bean的方法。根據前面章節可知,Activiti中的Service Task、任務監聽器和流程監聽器等,可以使用JUEL表達式來調用某個類的方法,同樣的,也可以使用JUEL表達式來調用bean的方法,但前提是要讓Activiti知道這些bean的存在。代碼清單16-11是一份整合了ActivitiSpring配置文件內容。

代碼清單16-11codes\16\16.2\integrate-spring\resource\activiti.use.bean.xml

<beans xmlns="http://www.springframework.org/schema/beans"

    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"

    xsi:schemaLocation="http://www.springframework.org/schema/beans

    http://www.springframework.org/schema/beans/spring-beans.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/act" />

        <property name="username" value="root" />

        <property name="password" value="123456" />

    </bean>

    <!--配置事務管理器-->

    <bean id="transactionManager"

        class="org.springframework.jdbc.datasource.DataSourceTransactionManager">

        <property name="dataSource" ref="dataSource" />

    </bean>

    <!--流程引擎的配置bean -->

    <bean id="processEngineConfiguration" class="org.activiti.spring.SpringProcessEngineConfiguration">

        <property name="dataSource" ref="dataSource" />

        <property name="databaseSchemaUpdate" value="true" />

        <property name="transactionManager" ref="transactionManager" />

        <!--processEngineConfiguration注入bean -->

        <property name="beans">

            <map>

                <entry key="myService" value-ref="myService" />

            </map>

        </property>

    </bean>

    <!--流程引擎的bean -->

    <bean id="processEngine" class="org.activiti.spring.ProcessEngineFactoryBean">

        <property name="processEngineConfiguration" ref="processEngineConfiguration" />

    </bean>

    <!--服務組件的bean -->

    <bean id="repositoryService" factory-bean="processEngine"

        factory-method="getRepositoryService" />

    <bean id="runtimeService" factory-bean="processEngine"

        factory-method="getRuntimeService" />

    <bean id="taskService" factory-bean="processEngine"

        factory-method="getTaskService" />

    <bean id="historyService" factory-bean="processEngine"

        factory-method="getHistoryService" />

    <bean id="managementService" factory-bean="processEngine"

        factory-method="getManagementService" />

    <!--業務組件bean -->

    <bean id="myService" class="org.crazyit.activiti.spring.impl.MyServiceImpl"></bean>

</beans>

除了前面所介紹的幾個bean外,代碼清單16-11中的粗體字代碼,爲processEngineConfiguration注入了beans屬性,beans屬性是ProcessEngineConfigurationImpl類的一個屬性,類型是Map<Object, Object>,在本例的配置文件中,爲其注入一個叫做myServicebeanmyService是一個普通的業務組件,本例中它只提供了一個業務方法,MyServiceImpl的實現如代碼清單16-12所示。

代碼清單16-12

codes\16\16.2\integrate-spring\src\org\crazyit\activiti\spring\impl\MyServiceImpl.java

public class MyServiceImpl implements MyService {

 

    public void serviceMethod(String name) {

        System.out.println("MyService的實現類處理業務方法:" + name);

    }

 

}

MyServiceImpl類中只有一個serviceMethod方法,有一個name參數,該方法只會在控制檯輸出一句話。新建一個簡單的流程,該流程中只含有一個Service Task,流程文件內容如代碼清單16-13所示。

代碼清單16-13codes\16\resource\bpmn\ActivitiUseBean.bpmn

    <process id="process1" name="process1">

        <startEvent id="startevent1" name="Start"></startEvent>

        <serviceTask id="servicetask1" name="Service Task"

            activiti:expression="#{myService.serviceMethod(name)}"></serviceTask>

        <endEvent id="endevent1" name="End"></endEvent>

        <sequenceFlow id="flow1" name="" sourceRef="startevent1"

            targetRef="servicetask1"></sequenceFlow>

        <sequenceFlow id="flow2" name="" sourceRef="servicetask1"

            targetRef="endevent1"></sequenceFlow>

    </process>

注意代碼清單16-13中的粗體字代碼,在流程中定義了一個Service Task,這個Service沒有配置activiti:class屬性,而使用了activiti:expresson屬性,值爲#{myService.serviceMethod(name)},表示使用名稱爲myServicebeanserviceMethod方法,參數爲name,這裏name參數是流程參數。代碼清單16-14爲運行代碼。

代碼清單16-14codes\16\16.2\integrate-spring\resource\bpmn\ActivitiUseBean.bpmn

        ApplicationContext ctx = new ClassPathXmlApplicationContext(

                new String[] { "activiti.use.bean.xml" });

        //得到Activiti的服務組件

        RepositoryService repositoryService = (RepositoryService) ctx

                .getBean("repositoryService");

        RuntimeService runtimeService = (RuntimeService) ctx

                .getBean("runtimeService");

        //部署流程文件

        repositoryService.createDeployment()

                .addClasspathResource("bpmn/ActivitiUseBean.bpmn").deploy();

        //初始化流程參數

        Map<String, Object> vars = new HashMap<String, Object>();

        vars.put("name", "crazyit");

        //啓動流程

        runtimeService.startProcessInstanceByKey("process1", vars);

本例的運行代碼,與前面章節的Activiti運行代碼類似,只是ProcessEngine的創建由Spring完成,本例中直接使用ApplicationContextgetBean方法就可以拿到Activiti的服務組件,流程文件部署、流程參數設置和流程啓動均與前面章節的案例一致。代碼清單16-14中的粗體字代碼,啓動流程,並設置流程參數,參數名爲“name”,值爲“crazyit”,運行代碼清單16-14,輸出結果如下

MyService的實現類處理業務方法:crazyit

根據結果可知,Activiti流程在運行時,調用了Springbean方法。除了Service Task外,流程監聽器和任務監聽器等地方,均可以使用這種方式來調bean的業務方法。

 

 

 

京東購買地址:https://item.jd.com/12246565.html

工作流Activiti6電子書http://blog.csdn.net/boxiong86/article/details/78488562

工作流Activiti6教學視頻http://blog.csdn.net/boxiong86/article/details/78608585

本書代碼共享地址:https://gitee.com/yangenxiong/CrazyActiviti

發佈了66 篇原創文章 · 獲贊 10 · 訪問量 6萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章