疯狂Activiti6.0连载(19)Activiti整合Spring
疯狂Activiti6.0连载(19)Activiti整合Spring
杨大仙的程序空间 发表于2周前
疯狂Activiti6.0连载(19)Activiti整合Spring
  • 发表于 2周前
  • 阅读 493
  • 收藏 8
  • 点赞 0
  • 评论 0

腾讯云 新注册用户 域名抢购1元起>>>   

摘要: Activiti Spring 整合

本文节选自《疯狂工作流讲义(第2版)》

京东购买地址:https://item.jd.com/12246565.html

疯狂Activiti电子书:https://my.oschina.net/JavaLaw/blog/1570397

工作流Activiti教学视频:https://my.oschina.net/JavaLaw/blog/1577577

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的业务方法。

本文节选自《疯狂工作流讲义(第2版)》

京东购买地址:https://item.jd.com/12246565.html

疯狂Activiti电子书:https://my.oschina.net/JavaLaw/blog/1570397

工作流Activiti教学视频:https://my.oschina.net/JavaLaw/blog/1577577

本书代码目录:https://gitee.com/yangenxiong/CrazyActiviti

标签: Activiti Spring 整合
共有 人打赏支持
粉丝 561
博文 55
码字总数 104403
×
杨大仙的程序空间
如果觉得我的文章对您有用,请随意打赏。您的支持将鼓励我继续创作!
* 金额(元)
¥1 ¥5 ¥10 ¥20 其他金额
打赏人
留言
* 支付类型
微信扫码支付
打赏金额:
已支付成功
打赏金额: