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(); }
以下示例在部署单元时收到通知,并可从存储中删除部署:
处理非部署事件的示例
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 或数据库。
另外,您还可以提供一些其他制作者来提供 WorkItemHandlers
和 Process
、Agenda
、WorkingMemory
事件监听程序。您可以通过实现以下接口来提供这些组件:
处理引擎与 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(); } }