搜索

68.2. 与 CDI 集成

download PDF

流程引擎支持自动与 CDI 集成。您可以在 CDI 框架中使用大多数 API,而无需任何修改。

进程引擎还提供一些专门用于 CDI 容器的专用模块。最重要的模块是 jbpm-services-cdi,它为处理引擎服务提供 CDI 封装器。您可以使用这些打包程序在 CDI 应用程序中集成进程引擎。模块提供以下一组服务:

  • DeploymentService
  • ProcessService
  • UserTaskService
  • RuntimeDataService
  • DefinitionService

这些服务可用于在任何其他 CDI Bean 中注入。

68.2.1. CDI 部署服务

DeploymentService 服务在运行时环境中部署并取消部署部署单元。当您使用这个服务部署单元时,部署单元就可以执行,并创建一个 RuntimeManager 实例。您还可以使用 DeploymentService 检索以下对象:

  • 给定部署 ID 的 RuntimeManager 实例
  • 代表给定部署 ID 的完整部署单元的 DeployedUnit 实例
  • 部署服务已知的所有部署单元列表

默认情况下,部署服务不会将部署单元的信息保存到任何持久性存储。在 CDI 框架中,使用该服务的组件可以保存和恢复部署单元信息,例如使用数据库、文件系统或存储库。

部署服务会在部署和取消部署中触发 CDI 事件。使用服务的组件可以处理这些事件来存储部署,并在取消部署时将其从存储中移除。

  • 部署单元时会触发带有 @Deploy qualifier 的 DeploymentEvent
  • 带有 @Undeploy qualifier 的 DeploymentEvent 在单元的 undeployment 上触发

您可以使用 CDI 观察程序机制来获取这些事件的通知。

以下示例收到单元部署中的通知,并可以保存部署:

部署事件处理示例

    public void saveDeployment(@Observes @Deploy DeploymentEvent event) {
        // Store deployed unit information
        DeployedUnit deployedUnit = event.getDeployedUnit();
    }

以下示例在部署单元时收到通知,并可从存储中删除部署:

处理非部署事件的示例

    public void removeDeployment(@Observes @Undeploy DeploymentEvent event) {
        // Remove deployment with the ID event.getDeploymentId()
    }

DeploymentService 服务有几个实现,因此您必须使用限定符来指示 CDI 容器注入特定的实施。每一实施部署都必须存在 DeploymentUnit匹配

流程引擎提供 KmoduleDeploymentService 实施。这种实现旨在与 KmoduleDeploymentUnits 合作,它们是 KJAR 文件中所含的小描述符。这个实现是大多数用例中典型的解决方案。此实施的限定符是 @Kjar

68.2.2. CDI 的表单供应商服务

FormProviderService 服务提供对表单的访问,通常显示在用户界面中用于进程表单和用户任务表单的用户界面。

该服务依赖于隔离形式的供应商的概念,可提供不同功能并由不同的技术提供支持。FormProvider 接口描述了表单供应商的合同。

FormProvider 接口的定义

public interface FormProvider {

    int getPriority();

    String render(String name, ProcessDesc process, Map<String, Object> renderContext);

    String render(String name, Task task, ProcessDesc process, Map<String, Object> renderContext);
}

FormProvider 接口的实现必须定义优先级值。当 FormProviderService 服务需要呈现表单时,它会按优先级顺序调用可用提供程序。

优先级越低,提供商获得的优先级越高。例如,在优先级为 10 的供应商之前,评估优先级为 5 的供应商。对于每个所需表单,服务按照其优先级顺序迭代可用的提供程序,直至其中之一来提供内容。在最糟糟的情况中,返回一个简单的基于文本的表单。

进程引擎提供 FormProvider 的以下实现:

  • 提供 Form Modeller 工具中创建的表单的供应商,优先级为 2
  • 基于 FreeMarker 的实施,它支持流程和任务表单,优先级为 3
  • 默认表单供应商返回简单的基于文本的表单,如果不存在其他供应商提供任何内容,其使用方法为 1000

68.2.3. CDI 运行时数据服务

RuntimeDataService 服务提供对在运行时可用的数据的访问,包括以下数据:

  • 要执行的可用进程,带有各种过滤器
  • 活跃的进程实例,带有不同的过滤器
  • 进程实例历史记录
  • 进程实例变量
  • 进程实例的活跃和完成节点

RuntimeDataService 的默认实现会观察部署事件,并索引所有部署的进程以将其公开给调用组件。

68.2.4. CDI 定义服务

DefinitionService 服务提供对作为 BPMN2 XML 定义一部分存储的进程详细信息的访问。

注意

在使用提供信息的任何方法前,调用 buildProcessDefinition() 方法,以使用从 BPMN2 内容检索的进程信息填充存储库。

BPMN2DataService 实现提供对以下数据的访问:

  • 给定进程定义过程的整体描述
  • 在进程定义中找到的所有用户任务的集合
  • 有关用户任务节点定义的输入的信息
  • 有关为用户任务节点定义的输出的信息
  • 在给定进程定义中定义的可重用进程的 ID(call 活动)
  • 有关在给定进程定义中定义的进程变量的信息
  • 有关包含在进程定义中的所有组织实体(用户和组)的信息。根据具体进程定义,用户和组返回的值可包含以下信息:

    • 实际用户或组名称
    • 用于在运行时获取实际用户或组名称的进程变量,例如: #{manager}

68.2.5. CDI 集成配置

要在 CDI 框架中使用 jbpm-services-cdi 模块,您必须提供一些 bean 来满足所含服务实施的依赖项。

根据使用场景,需要几个 Bean:

  • 实体管理器和实体管理器工厂
  • 用于人工任务的用户组回调
  • 身份提供程序将经过身份验证的用户信息传递给服务

在 JEE 环境中运行(如红帽 JBoss EAP)时,以下制作者 bean 满足 jbpm-services-cdi 模块的所有要求。

制作者 bean 满足 JEE 环境中的 jbpm-services-cdi 模块的所有要求

public class EnvironmentProducer {

    @PersistenceUnit(unitName = "org.jbpm.domain")
    private EntityManagerFactory emf;

    @Inject
    @Selectable
    private UserGroupInfoProducer userGroupInfoProducer;

    @Inject
    @Kjar
    private DeploymentService deploymentService;

    @Produces
    public EntityManagerFactory getEntityManagerFactory() {
        return this.emf;
    }

    @Produces
    public org.kie.api.task.UserGroupCallback produceSelectedUserGroupCalback() {
        return userGroupInfoProducer.produceCallback();
    }

    @Produces
    public UserInfo produceUserInfo() {
        return userGroupInfoProducer.produceUserInfo();
    }

    @Produces
    @Named("Logs")
    public TaskLifeCycleEventListener produceTaskAuditListener() {
        return new JPATaskLifeCycleEventListener(true);
    }

    @Produces
    public DeploymentService getDeploymentService() {
        return this.deploymentService;
    }

    @Produces
    public IdentityProvider produceIdentityProvider {
        return new IdentityProvider() {
             // implement IdentityProvider
        };
    }
}

应用的 Bean.xml 文件必须为用户组 info 回调启用正确的替代选择。这种替代选择基于 @Selectable qualifier。

Bean.xml 文件'中,为用户组信息回调的定义

<beans xmlns="http://java.sun.com/xml/ns/javaee" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
  xsi:schemaLocation="http://java.sun.com/xml/ns/javaee https://docs.jboss.org/cdi/beans_1_0.xsd">

  <alternatives>
    <class>org.jbpm.kie.services.cdi.producer.JAASUserGroupInfoProducer</class>
  </alternatives>

</beans>

注意

org.jbpm.kie.services.cdi.producer.JAASUserGroupInfoProducer 是一个示例值。这个值通常适合于红帽 JBoss EAP,因为它可重复利用应用服务器上的安全设置,无论服务器使用哪种安全方法,如 LDAP 或数据库。

另外,您还可以提供一些其他制作者来提供 WorkItemHandlersProcessAgendaWorkingMemory 事件监听程序。您可以通过实现以下接口来提供这些组件:

处理引擎与 CDI 集成的工作项目处理程序制作界面

/**
 * Enables providing custom implementations to deliver WorkItem name and WorkItemHandler instance pairs
 * for the runtime.
 * <br/>
 * This interface is invoked by the RegisterableItemsFactory implementation (in particular InjectableRegisterableItemsFactory
 * in the CDI framework) for every KieSession. Always return new instances of objects to avoid unexpected
 * results.
 *
 */
public interface WorkItemHandlerProducer {

    /**
     * Returns map of work items(key = work item name, value = work item handler instance)
     * to be registered on KieSession
     * <br/>
     * The following parameters might be given:
     * <ul>
     *  <li>ksession</li>
     *  <li>taskService</li>
     *  <li>runtimeManager</li>
     * </ul>
     *
     * @param identifier - identifier of the owner - usually the RuntimeManager. This parameter allows the producer to filter out
     * and provide valid instances for a given owner
     * @param params - the owner might provide some parameters, usually KieSession, TaskService, RuntimeManager instances
     * @return map of work item handler instances (always return new instances when this method is invoked)
     */
    Map<String, WorkItemHandler> getWorkItemHandlers(String identifier, Map<String, Object> params);
}

用于处理引擎与 CDI 集成的事件监听程序制作者接口

/**
 * Enables defining custom producers for known EventListeners. There might be several
 * implementations that might provide a different listener instance based on the context in which they are executed.
 * <br/>
 * This interface is invoked by the RegisterableItemsFactory implementation (in particular, InjectableRegisterableItemsFactory
 * in the CDI framework) for every KieSession. Always return new instances of objects to avoid unexpected results.
 *
 * @param <T> type of the event listener - ProcessEventListener, AgendaEventListener, WorkingMemoryEventListener
 */
public interface EventListenerProducer<T> {

    /**
     * Returns list of instances for given (T) type of listeners
     * <br/>
     * Parameters that might be given are:
     * <ul>
     *  <li>ksession</li>
     *  <li>taskService</li>
     *  <li>runtimeManager</li>
     * </ul>
     * @param identifier - identifier of the owner - usually RuntimeManager. This parameter allows the producer to filter out
     * and provide valid instances for given owner
     * @param params - the owner might provide some parameters, usually KieSession, TaskService, RuntimeManager instances
     * @return list of listener instances (always return new instances when this method is invoked)
     */
    List<T> getEventListeners(String identifier, Map<String, Object>  params);
}

实施这两个接口的 Bean 会在运行时收集并在 RuntimeManager 类构建 KieSession 实例时调用。

68.2.5.1. 作为 CDI Bean 的运行时管理器

您可以将 RuntimeManager 类作为 CDI Bean 注入应用程序中的任何其他 CDI Bean。必须正确生成 RuntimeEnvironment 类,以启用 RuntimeManager 实例的正确初始化。

以下 CDI 限定符引用现有的运行时管理器策略:

  • @Singleton
  • @PerRequest
  • @PerProcessInstance

有关运行时管理器的详情,请参考 第 66.2 节 “运行时管理器”

注意

虽然您可以直接注入 RuntimeManager 类,但对于大多数框架用例(如 CDI、EJB 或 Spring)的解决方案正在使用服务。流程引擎服务使用运行时管理器实施许多最佳实践。

要使用运行时管理器,您必须将 RuntimeEnvironment 类添加到 第 68.2.5 节 “CDI 集成配置” 部分中定义的 producer 中。

提供 RuntimeEnvironment 类的 producer bean

public class EnvironmentProducer {

    //Add the same producers as for services

    @Produces
    @Singleton
    @PerRequest
    @PerProcessInstance
    public RuntimeEnvironment produceEnvironment(EntityManagerFactory emf) {

        RuntimeEnvironment environment = RuntimeEnvironmentBuilder.Factory.get()
                .newDefaultBuilder()
                .entityManagerFactory(emf)
                .userGroupCallback(getUserGroupCallback())
                .registerableItemsFactory(InjectableRegisterableItemsFactory.getFactory(beanManager, null))
                .addAsset(ResourceFactory.newClassPathResource("BPMN2-ScriptTask.bpmn2"), ResourceType.BPMN2)
                .addAsset(ResourceFactory.newClassPathResource("BPMN2-UserTask.bpmn2"), ResourceType.BPMN2)
                .get();
        return environment;
    }
}

在本例中,单一制作者方法可以通过在方法级别上指定所有运行时管理器策略,为所有运行时管理器策略提供 RuntimeEnvironment 类。

当完整的制作者可用时,RuntimeManager 类可以注入到应用程序的 CDI bean 中:

注入 RuntimeManager

public class ProcessEngine {

    @Inject
    @Singleton
    private RuntimeManager singletonManager;

    public void startProcess() {

        RuntimeEngine runtime = singletonManager.getRuntimeEngine(EmptyContext.get());
        KieSession ksession = runtime.getKieSession();

        ProcessInstance processInstance = ksession.startProcess("UserTask");

        singletonManager.disposeRuntimeEngine(runtime);
    }
}

如果您注入 RuntimeManager 类,则应用程序中只能有一个 RuntimeManager 实例。在典型的情形中,使用 DeploymentService 服务根据需要创建 RuntimeManager 实例。

作为 DeploymentService 的替代方案,您可以注入 RuntimeManageronnectionFactory y 类,然后应用程序就可以使用它来创建 RuntimeManager 实例。在这种情况下,仍需要 EnvironmentProducer 定义。以下示例显示了一个简单的 ProcessEngine bean。

ProcessEngine bean 示例

public class ProcessEngine {

    @Inject
    private RuntimeManagerFactory managerFactory;

    @Inject
    private EntityManagerFactory emf;

    @Inject
    private BeanManager beanManager;

    public void startProcess() {
        RuntimeEnvironment environment = RuntimeEnvironmentBuilder.Factory.get()
                .newDefaultBuilder()
                .entityManagerFactory(emf)
                .addAsset(ResourceFactory.newClassPathResource("BPMN2-ScriptTask.bpmn2"), ResourceType.BPMN2)
                .addAsset(ResourceFactory.newClassPathResource("BPMN2-UserTask.bpmn2"), ResourceType.BPMN2)
                .registerableItemsFactory(InjectableRegisterableItemsFactory.getFactory(beanManager, null))
                .get();

        RuntimeManager manager = managerFactory.newSingletonRuntimeManager(environment);
        RuntimeEngine runtime = manager.getRuntimeEngine(EmptyContext.get());
        KieSession ksession = runtime.getKieSession();

        ProcessInstance processInstance = ksession.startProcess("UserTask");

        manager.disposeRuntimeEngine(runtime);
        manager.close();
    }

}

Red Hat logoGithubRedditYoutubeTwitter

学习

尝试、购买和销售

社区

关于红帽文档

通过我们的产品和服务,以及可以信赖的内容,帮助红帽用户创新并实现他们的目标。

让开源更具包容性

红帽致力于替换我们的代码、文档和 Web 属性中存在问题的语言。欲了解更多详情,请参阅红帽博客.

關於紅帽

我们提供强化的解决方案,使企业能够更轻松地跨平台和环境(从核心数据中心到网络边缘)工作。

© 2024 Red Hat, Inc.