关于工作流:工作流中容器化的依赖注入Activiti集成CDI实现工作流的可配置型和可扩展型

32次阅读

共计 8230 个字符,预计需要花费 21 分钟才能阅读完成。

Activiti 工作流集成 CDI 简介

  • activiti-cdi 模块提供 activiti 的可配置型和 cdi 扩大
  • activiti-cdi 的个性:

    • 反对 @BusinessProcessScoped beans, 绑定到流程实例的cdi bean
    • 流程为 cdi bean 反对自定义 EL 处理器
    • 应用 注解 为流程实例提供 申明式管制
    • Activiti能够挂接在 cdi 事件总线上
    • 反对 Java EEJava SE, 反对Spring
    • 反对单元测试
  • 要在 maven 我的项目中应用 activiti-cdi, 须要增加依赖:

    <dependency>
          <groupId>org.activiti</groupId>
          <artifactId>activiti-cdi</artifactId>
          <version>5.8</version>
    </dependency>
  • activiti-cdi 5.6以上的版本会主动退出 activiti-entinspring

    设置 activiti-cdi

  • Activiti cdi 能够装置在不同环境中

    查找流程引擎

  • cdi扩大须要拜访到ProcessEngine, 为了实现此性能:

    • 应用 org.activiti.cdi.spi.ProcessEngineLookup 接口在运行期间进行查找
    • cdi模块应用默认的名为 org.activiti.cdi.impl.LocalProcessEngineLookup 的实现, 应用 ProcessEngines 这个工具类来查找ProcessEngine
    • 默认配置下, 应用 ProcessEngines#NAME_DEFAULT 来查找 ProcessEngine. 这个类可能是应用自定义名称的子类
    • ==留神:== 须要把 activiti.cfg.xml 放在 classpath
  • Activiti cdi应用 java.util.ServiceLoader SPI 解决 org.activiti.cdi.spi.ProcessEngineLookup 的实例

    • 为了提供接口的自定义实现, 须要创立一个文本文件, 名为META-INF/services/org.activiti.cdi.spi.ProcessEngineLookup, 在文件中须要指定实现的全类名
    • 如果你没有提供自定义的 org.activiti.cdi.spi.ProcessEngineLookup 实现,activiti 会应用默认的 LocalProcessEngineLookup 实现, 须要做的就是把 activiti.cfg.xml 放到 classpath

      配置 Process Engine

  • 理论的配置依赖于选用的 ProcessEngineLookup 策略
  • 在这里次要联合 LocalProcessEngineLookup 探讨可用的配置, 要求在 classpath 下提供一个 springactiviti.cfg.xml
  • Activiti 提供了不同的 ProcessEngineConfiguration 实现, 次要是依赖理论应用的事务管理策略
  • activiti-cdi模块对事务的要求不严格, 意味着任何事务管理策略都能够应用, 即使是 spring 事务形象层
  • cdi模块提供两种自定义 ProcessEngineConfiguration 实现:

    • org.activiti.cdi.CdiJtaProcessEngineConfiguration: activiti 的 JtaProcessEngineConfiguration 的子类, 用于在 activiti 应用JTA 治理的事务环境
    • org.activiti.cdi.CdiStandaloneProcessEngineConfiguration: activiti 的 StandaloneProcessEngineConfiguration 的子类, 用于在 activiti 应用 简略 JDBC 事务环境
  • JBoss7 下的 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/beans http://www.springframework.org/schema/beans/spring-beans.xsd">
    
          <!-- lookup the JTA-Transaction manager -->
          <bean id="transactionManager" class="org.springframework.jndi.JndiObjectFactoryBean">
                  <property name="jndiName" value="java:jboss/TransactionManager"></property>
                  <property name="resourceRef" value="true" />
          </bean>
    
          <!-- process engine configuration -->
          <bean id="processEngineConfiguration"
                  class="org.activiti.cdi.CdiJtaProcessEngineConfiguration">
                  <!-- lookup the default Jboss datasource -->
                  <property name="dataSourceJndiName" value="java:jboss/datasources/ExampleDS" />
                  <property name="databaseType" value="h2" />
                  <property name="transactionManager" ref="transactionManager" />
                  <!-- using externally managed transactions -->
                  <property name="transactionsExternallyManaged" value="true" />
                  <property name="databaseSchemaUpdate" value="true" />
          </bean>
    </beans>
  • 在 Glassfish 3.1.1, 假如配置好名为 jdbc/activiti 的 datasource:

    <?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/beans http://www.springframework.org/schema/beans/spring-beans.xsd">
    
          <!-- lookup the JTA-Transaction manager -->
          <bean id="transactionManager" class="org.springframework.jndi.JndiObjectFactoryBean">
                  <property name="jndiName" value="java:appserver/TransactionManager"></property>
                  <property name="resourceRef" value="true" />
          </bean>
    
          <!-- process engine configuration -->
          <bean id="processEngineConfiguration"
                  class="org.activiti.cdi.CdiJtaProcessEngineConfiguration">
                  <property name="dataSourceJndiName" value="jdbc/activiti" />
                  <property name="transactionManager" ref="transactionManager" />
                  <!-- using externally managed transactions -->
                  <property name="transactionsExternallyManaged" value="true" />
                  <property name="databaseSchemaUpdate" value="true" />
          </bean>
    </beans>
  • 留神: 下面的配置要引入 spring-context 模块依赖

    <dependency>
          <groupId>org.springframework</groupId>
          <artifactId>spring-context</artifactId>
          <version>3.0.3.RELEASE</version>
    </dependency>

    公布流程

  • 能够应用规范的 activiti-api 公布流程 -RepositoryService
  • activiti-cdi也提供了主动公布 classpathprocesses.xml中列出的流程的形式
  • processes.xml:

    <?xml version="1.0" encoding="utf-8" ?>
    <!-- list the processes to be deployed -->
    <processes>
          <process resource="diagrams/myProcess.bpmn20.xml" />
          <process resource="diagrams/myOtherProcess.bpmn20.xml" />
    </processes>

    基于 CDI 环境的流程执行

  • BPMN 业务流程通常是一个长时间运行的操作, 蕴含了用户和零碎工作的操作
  • 运行过程中, 流程会分成多个独自的工作单元, 由用户和应用逻辑执行
  • activiti-cdi 中, 流程实例能够调配到 cdi 环境中, 关联展示成一个工作单元:

    • 这是十分有用的, 如果工作单元太简单: 比方如果实现的用户工作是不同模式的简单程序, 能够在这个操作中放弃 non-process-scoped 状态
    • 默认配置下, 流程实例调配到 broadest 激活环境, 就会启动交互, 如果交互环境没有激活, 就会返回到申请中

      与流程实例进行关联交互

  • 解决 @BusinessProcessScoped beans, 或注入流程变量时, 实现了激活的 cdi 环境与流程实例的关联
  • Activiti-cdi提供了 org.activiti.cdi.BusinessProcess bean 来管制关联:

    • startProcessByXx(…): 对应 activiti 的 RuntimeService 中的相干办法, 容许启动和随后向关联的业务流程
    • resumeProcessById(String processInstanceId): 容许通过提供的 Id 来关联流程实例
    • resumeTaskById(String taskId): 容许通过提供的 Id 来关联工作, 也能够扩大关联流程实例
  • 一个工作单元实现后 ,completeTask() 办法能够调用来解除流程实例和会话或申请的关联. 这会告诉 activiti 当前任务曾经实现, 并让流程实例继续执行
  • BusinessProcess bean@Named bean, 意思是导出的办法能够通过表达式语言调用:

    • 比方在 JSF 页面中. 上面的 JSF 2 代码启动一个新的交互, 调配给一个用户工作实例,Id 作为一个申请参数传递:

      <f:metadata>
      <f:viewParam name="taskId" />
      <f:event type="preRenderView" listener="#{businessProcess.startTask(taskId, true)}" />
      </f:metadata>

      申明式流程管制

  • Activiti-cdi 容许通过注解申明启动流程实例和实现工作
  • @org.activiti.cdi.annotation.StartProcess注解容许通过 keyname启动流程实例. 流程实例会在注解的办法返回之后启动:

    @StartProcess("authorizeBusinessTripRequest")
    public String submitRequest(BusinessTripRequest request) {
          // do some work
          return "success";
    }
  • 依据 activiti 的配置, 注解办法的代码和启动流程实例会在同一个事务中执行 .@org.activiti.cdi.annotation.CompleteTask事务的应用形式雷同:

    @CompleteTask(endConversation=false)
    public String authorizeBusinessTrip() {
          // do some work
          return "success";
    }

    @CompleteTask注解能够完结以后会话. 默认行为会在 activiti 返回后完结会话. 能够禁用完结会话的性能

    在流程中援用 bean

  • Activiti-cdi应用自定义解析器把 CDI bean 裸露到 activiti El 中, 能够在流程中援用这些bean:

    <userTask id="authorizeBusinessTrip" name="Authorize Business Trip"
                          activiti:assignee="#{authorizingManager.account.username}" />
  • authorizingManager能够是生产者办法提供的bean:

    @Inject @ProcessVariable Object businessTripRequesterUsername;
    
    @Produces
    @Named
    public Employee authorizingManager() {
          TypedQuery<Employee> query = entityManager.createQuery("SELECT e FROM Employee e WHERE e.account.username='"
                  + businessTripRequesterUsername + "'", Employee.class);
          Employee employee = query.getSingleResult();
          return employee.getManager();

    应用 @BusinessProcessScoped beans

  • 应用 activiti-cdi,bean 的生命周期能够绑定到流程实例上:

    • 能够提供一个自定义的环境实现, 命名为BusinessProcessContext.
    • BusinessProcessScoped bean的实例会作为流程变量保留到以后流程实例中
    • BusinessProcessScoped bean须要是 PassivationCapable, 比方序列化
  • 应用流程作用域 bean 的示例如下:

    @Named
    @BusinessProcessScoped
    public class BusinessTripRequest implements Serializable {
          private static final long serialVersionUID = 1L;
          private String startDate;
          private String endDate;
          // ...
    }
  • 有时, 须要应用流程作用域 bean, 没有与流程实例关联:

    • 比方启动流程之前. 如果以后流程实例没有激活 ,BusinessProcessScoped bean实例会临时保留在部分作用域里:

      • 会话
      • 申请
      • 依赖环境
  • 如果作用域起初与业务流程实例关联了,bean 实例会刷新到流程实例里

    注入流程变量

  • 流程变量能够实现用于注入
  • Activiti-CDI反对以下注入流程变量的形式:

    • @BusinessProcessScoped应用 @Inject [附加润饰] 类型 属性名 实现类型平安的流程变量的注入
    • 应用 @ProcessVariable(name) 修饰符实现对类型不平安的流程变量的注入

      @Inject @ProcessVariable Object accountNumber;
      @Inject @ProcessVariable("accountNumber") Object account
  • 为了通过 EL 援用流程变量, 能够应用如下形式:

    • @Named @BusinessProcessScoped beans能够间接援用
    • 其余流程变量能够应用 ProcessVariables bean 来应用

      #{processVariables['accountNumber']}

      接管流程事件

  • Activiti 能够挂在 CDI 的事件总线上, 就能够应用规范 CDI 事件机制来监听流程事件
  • 为了启用 activiti 的 CDI 事件反对, 须要在配置中启用对应的解析监听器:

    <property name="postBpmnParseHandlers">
          <list>
                  <bean class="org.activiti.cdi.impl.event.CdiEventSupportBpmnParseHandler" />
          </list>
    </property>
  • 这样 activiti 就配置成了应用 CDI 事件总线公布事件
  • CDI bean 中处理事件的形式:

    • 应用 @Observes 注解申明特定的事件监听器
    • 事件监听是类型平安的
    • 流程事件类型是org.activiti.cdi.BusinessProcessEvent
  • 一个简略事件监听办法示例:

    public void onProcessEvent(@Observes BusinessProcessEvent businessProcessEvent) {// handle event}
  • 监听器能够监听所有事件. 如果想限度监听器接管的事件类型, 能够增加润饰注解:

    • @BusinessProcess: 限度指定流程定义的事件

      • @Observes @BusinessProcess(“billingProcess”)
    • @StartActivity: 限度指定进入环节的事件

      • @Observes @StartActivity(“shipGoods”)
    • @EndActivity: 限度指定完结环节的事件

      • @Observes @EndActivity(“shipGoods”)
    • @TakeTransition: 限度指定连线的事件
  • 润饰命名能够自由组合:

    • 为了接管 shipmentProcess 流程中所有来到 shipGoods 环节的事件:

      public void beforeShippingGoods(@Observes @BusinessProcess("shippingProcess") @EndActivity("shipGoods") BusinessProcessEvent evt) {// handle event}
  • 默认配置下, 事件监听器是同步调用, 并在同一个事务环境中
  • CDI 事务性监听器能够管制监听器什么时候处理事件:

    • 能够保障监听器只在事件中的事务胜利之后才解决

      public void onShipmentSuceeded(@Observes(during=TransactionPhase.AFTER_SUCCESS) @BusinessProcess("shippingProcess") @EndActivity("shipGoods") BusinessProcessEvent evt) {// send email to customer.}

      Activiti CDI 中的更多功能

  • 流程引擎和服务都能够注入: Inject ProcessEngine,RepositoryService,TaskService,…
  • 以后流程实例和工作能够注入: @Inject ProcessInstance, Task
  • 以后业务标识能够注入: @Inject @BusinessKey String businessKey
  • 以后流程实例 id 能够注入: @Inject @ProcessInstanceId String pid

正文完
 0