您的位置:首页 > 编程语言 > Java开发

疯狂Activiti6.0连载(19)Activiti整合Spring

2017-11-27 20:04 411 查看
 本文节选自《疯狂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提供了StandaloneProcessEngineConfiguration、StandaloneInMemProcessEngineConfiguration等类,在流程引擎的配置文件中,可以使用这些子类作为bean的class,这些类的描述见本书的流程引擎配置章节。

如果需要和Spring整合,就要使用Activiti的Spring模块中的SpringProcessEngineConfiguration类作为流程引擎配置类,该类类继承ProcessEngineConfigurationImpl,在配置这个类时,可以为ProcessEngineConfiguration注入TransactionManager,也可以在配置中指定自动部署的资源文件及部署模式,代码清单16-6为SpringProcessEngineConfiguration的部分源代码。

代码清单16-6:org.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属性,使用这个类作为流程引擎bean的class,可以在配置文件中指定TransactionManager,另外还有一个deploymentResources属性,可以为流程引擎的bean指定流程文件资源。

如果Activiti不与Spring进行整合,那么默认情况下,将会使用myBatis的事务管理,使用了SpringProcessEngineConfiguration后,在配置中必须指定一个Spring的TransactionManager,SpringProcessEngineConfiguration的配置如代码清单16-7所示。

代码清单16-7:codes\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的数据源来设置“dataSource”bean,使用了Spring的DataSourceTransactionManager作为事务管理器,在事务管理器中注入了数据源,在配置processEngineConfiguration时,将数据源和事务管理器注入。

本例的数据源使用了Spring的SimpleDriverDataSource,在实际应用中,可以选择C3P0、DBCP等数据源连接池,如果业务系统中同时使用了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

前面的章节中,一般情况使用ProcessEngines的getDefaultProcessEngine方法得到默认的ProcessEngine实例。如果将创建ProcessEngine的过程也交由Spring容器代为完成,可以使用ProcessEngineFactoryBean。ProcessEngineFactoryBean也是Activiti的Spring模块提供的类,主要用于维护一个ProcessEngine实例,向ProcessEngineFactoryBean设置(注入)一个流程引擎配置(ProcessEngineConfiguration)实例,它就会自动创建ProcessEngine。在得到Spring上下文后,通过getBean方法得到ProcessEngineFactoryBean的bean,实际上得到的是一个ProcessEngine实例,这是由于ProcessEngineFactoryBean类实现了FactoryBean接口,在getBean时会调用FactoryBean的getObject方法返回一个具体的bean实例,而ProcessEngineFactoryBean的getObject方法,返回的是一个ProcessEngine实例。代码清单16-8为ProcessEngineFactoryBean的配置。

代码清单16-8:codes\16\16.2\integrate-spring\resource\activiti.cfg.xml

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

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

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

   </bean>

需要注意的是,processEngine的bean的class并不是ProcessEngine的实现类,通过getBean方法拿到的,才是一个ProcessEngine实例。在16.2.1小节,配置了processEngineConfiguration的bean,在本小节配置了processEngine的bean,那么启动流程引擎的话,就可以直接使用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配置文件,再获取processEngine的bean,本例中输出ProcessEngine以及TaskService的实例,运行代码清单16-9,结果如下:

流程引擎实现类:org.activiti.engine.impl.ProcessEngineImpl


在bean中注入Activiti服务

通过上一小节,将ProcesseEngine交由Spring的IoC容器进行管理,那Activiti的服务同样可以交由Spring进行管理。Activiti的各个服务组件,均在ProcessEngineConfigurationImpl进行创建(使用new关键字),通过ProcesseEngine对象的getXXXService可以得到这些服务的实例。因为这些服务对象的创建由Activiti完成,所以Spring并不需要管理它们的创建过程,代码清单16-10中配置了这些服务对象的bean。

代码清单16-10:codes\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属性来指定工厂bean的id,并且使用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中使用Spring的bean

在其他的业务bean中可以使用Activiti的服务,那么在流程元素中,同样可以使用这些业务bean的方法。根据前面章节可知,Activiti中的Service
Task、任务监听器和流程监听器等,可以使用JUEL表达式来调用某个类的方法,同样的,也可以使用JUEL表达式来调用bean的方法,但前提是要让Activiti知道这些bean的存在。代码清单16-11是一份整合了Activiti的Spring配置文件内容。

代码清单16-11:codes\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>,在本例的配置文件中,为其注入一个叫做myService的bean,myService是一个普通的业务组件,本例中它只提供了一个业务方法,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-13:codes\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)},表示使用名称为myService的bean的serviceMethod方法,参数为name,这里name参数是流程参数。代码清单16-14为运行代码。

代码清单16-14:codes\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完成,本例中直接使用ApplicationContext的getBean方法就可以拿到Activiti的服务组件,流程文件部署、流程参数设置和流程启动均与前面章节的案例一致。代码清单16-14中的粗体字代码,启动流程,并设置流程参数,参数名为“name”,值为“crazyit”,运行代码清单16-14,输出结果如下:

MyService的实现类处理业务方法:crazyit。

根据结果可知,Activiti流程在运行时,调用了Spring的bean方法。除了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



内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签:  Activiti6 Spring