68.2. 与 CDI 集成


流程引擎支持自动与 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();
    }
Copy to Clipboard Toggle word wrap

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

处理非部署事件的示例

    public void removeDeployment(@Observes @Undeploy DeploymentEvent event) {
        // Remove deployment with the ID event.getDeploymentId()
    }
Copy to Clipboard Toggle word wrap

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);
}
Copy to Clipboard Toggle word wrap

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
        };
    }
}
Copy to Clipboard Toggle word wrap

应用的 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>
Copy to Clipboard Toggle word wrap

注意

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);
}
Copy to Clipboard Toggle word wrap

用于处理引擎与 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);
}
Copy to Clipboard Toggle word wrap

实施这两个接口的 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;
    }
}
Copy to Clipboard Toggle word wrap

在本例中,单一制作者方法可以通过在方法级别上指定所有运行时管理器策略,为所有运行时管理器策略提供 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);
    }
}
Copy to Clipboard Toggle word wrap

如果您注入 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();
    }

}
Copy to Clipboard Toggle word wrap

返回顶部
Red Hat logoGithubredditYoutubeTwitter

学习

尝试、购买和销售

社区

关于红帽文档

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

让开源更具包容性

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

關於紅帽

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

Theme

© 2025 Red Hat