68.4. 与 EJB 集成
进程引擎为企业 Java Beans(EJB)提供完整的集成层。这个层支持本地和远程 EJB 互动。
以下模块提供 EJB 服务:
-
jBPM-services-ejb-api:使用特定于 EJB 的接口和对象扩展jbpm-services-api模块的 API 模块 -
jBPM-services-ejb-impl:用于核心服务的 EJB 扩展 -
jBPM-services-ejb-timer:基于 EJB Timer 服务的进程引擎调度程序服务实施 -
jBPM-services-ejb-client:用于远程交互的 EJB 远程客户端实施,默认情况下支持 Red Hat JBoss EAP
EJB 层基于流程引擎服务。虽然您使用远程接口,它提供了与核心模块相同的功能。
主要限制会影响部署服务,如果将其用作远程 EJB 服务,则只支持以下方法:
-
deploy() -
imageink() -
activate() -
deactivate() -
isDeployed()
其他方法将被排除,因为它们返回运行时对象实例,如 RuntimeManager,这无法通过远程接口使用。
所有其他服务都提供与核心模块中包含的版本相同的 EJB 功能。
68.4.1. EJB 服务的实现 复制链接链接已复制到粘贴板!
作为进程引擎核心服务的扩展,EJB 服务提供基于 EJB 的执行语义,并基于各种特定于 EJB 的功能。
-
DeploymentServiceEJBImpl作为带有容器管理的并发的 EJB 单例实施。其锁定类型设置为写入。 -
DefinitionServiceEJBImpl作为带有容器管理的并发的 EJB 单例实施。其整体锁定类型设置为read,对于buildProcessDefinition()方法,锁定类型设置为write。 -
ProcessServiceEJBImpl作为无状态会话 bean 实现。 RuntimeDataServiceEJBImpl作为 EJB 单例实施。对于多数方法,锁定类型被设置为读取。对于以下方法,锁定类型被设置为写入:-
onDeploy() -
onUnDeploy() -
onActivate() -
onDeactivate()
-
-
UserTaskServiceEJBImpl作为无状态会话 bean 实现。
Transactions
EJB 容器管理 EJB 服务中的事务。因此,您不需要在应用程序代码中设置任何事务管理器或用户事务。
用户身份提供程序
默认身份提供程序基于 EJBContext 接口,并依赖于名称和角色的调用者主体信息。IdentityProvider 接口提供与角色相关的两种方法:
-
getRoles()返回空列表,因为EJBContext接口不提供获取特定用户的所有角色的选项 -
具有Role()委派给上下文的isCallerInRole()方法
为确保 EJB 环境可以使用有效信息,您必须遵循标准的 JEE 安全实践来进行身份验证和授权用户。如果没有为 EJB 服务配置验证或授权,则始终假定一个匿名用户。
如果使用不同的安全模型,您可以使用 CDI 样式注入 IdentityProvider 对象用于 EJB 服务。在本例中,创建一个有效的 CDI Bean,它将实现 org.kie.internal.identity.IdentityProvider 接口,并使此 bean 可供您的应用程序注入。这种实施优先于基于 EJBContext的身份提供商。
部署同步
部署同步默认为启用,并且尝试每 3 秒同步任何部署。它作为带有容器管理的并发的 EJB 单例实施。其锁定类型设置为 写入。它使用 EJB 计时器服务来调度同步作业。
EJB 调度程序服务
进程引擎使用调度程序服务来处理基于时间的活动,如计时器事件和期限。在 EJB 环境中运行时,进程引擎使用基于 EJB 计时器服务的调度程序。它为所有 RuntimeManager 实例注册此调度程序。
您可能需要使用特定于应用服务器的配置来支持集群操作。
UserGroupCallback 和 UserInfo 实现选择
UserGroupCallback 和 UserInfo 接口所需的实现可能因不同的应用程序而异。这些接口不能直接注入 EJB。您可以使用以下系统属性来选择现有的实现,或使用这些接口的自定义实现流程引擎:
org.jbpm.ht.callback:此属性为UserGroupCallback接口选择实现:-
MVEL:默认实施,通常用于测试。 -
LDAP:基于 LDAP 的实施。此实施需要在jbpm.usergroup.callback.properties文件中进行额外的配置。 -
db:基于数据库的实施。此实施需要在jbpm.usergroup.callback.properties文件中进行额外的配置。 -
JAAS:从容器请求用户信息的实现。 -
props:基于属性的简单回调。这种实施需要额外属性文件,其中包含所有用户和组。 -
自定义:一个自定义实施。您必须在org.jbpm.ht.custom.callback系统属性中提供实现的完全限定类名称。
-
org.jbpm.ht.userinfo:此属性为UserInfo接口选择实现:-
LDAP:基于 LDAP 的实施。此实施需要在jbpm-user.info.properties文件中进行额外的配置。 -
db:基于数据库的实施。此实施需要在jbpm-user.info.properties文件中进行额外的配置。 -
props:基于属性的简单实施。这种实施需要包含所有用户信息的额外属性文件。 -
自定义:一个自定义实施。您必须在org.jbpm.ht.custom.userinfo系统属性中提供实现的完全限定域名。
-
通常,在应用服务器或 JVM 的启动配置中设置系统属性。在使用服务之前,您还可以在代码中设置属性。例如,您可以提供一个自定义 @Startup bean 来配置这些系统属性。
68.4.2. 本地 EJB 接口 复制链接链接已复制到粘贴板!
以下本地 EJB 服务接口扩展了核心服务:
-
org.jbpm.services.ejb.api.DefinitionServiceEJBLocal -
org.jbpm.services.ejb.api.DeploymentServiceEJBLocal -
org.jbpm.services.ejb.api.ProcessServiceEJBLocal -
org.jbpm.services.ejb.api.RuntimeDataServiceEJBLocal -
org.jbpm.services.ejb.api.UserTaskServiceEJBLocal
您必须使用这些接口作为注入点,并使用 @EJB 标注:
使用本地 EJB 服务接口
@EJB
private DefinitionServiceEJBLocal bpmn2Service;
@EJB
private DeploymentServiceEJBLocal deploymentService;
@EJB
private ProcessServiceEJBLocal processService;
@EJB
private RuntimeDataServiceEJBLocal runtimeDataService;
注入这些接口后,在它们上调用操作方式与核心模块相同。使用本地接口不存在限制。
68.4.3. 远程 EJB 接口 复制链接链接已复制到粘贴板!
以下专用远程 EJB 接口扩展了核心服务:
-
org.jbpm.services.ejb.api.DefinitionServiceEJBRemote -
org.jbpm.services.ejb.api.DeploymentServiceEJBRemote -
org.jbpm.services.ejb.api.ProcessServiceEJBRemote -
org.jbpm.services.ejb.api.RuntimeDataServiceEJBRemote -
org.jbpm.services.ejb.api.UserTaskServiceEJBRemote
您可以以与本地接口相同的方式使用这些接口,但处理自定义类型除外。
您可以通过两种方式定义自定义类型。全局 定义的类型在应用程序类路径上可用,并包含在企业应用程序中。如果您在 部署单元本地 定义类型,则会在项目依赖项中声明该类型(例如,在 KJAR 文件中),并在部署时解析。
全局可用类型不需要任何特殊处理。EJB 容器在处理远程请求时自动提取数据。但是,默认情况下,本地自定义类型对 EJB 容器不可见。
进程引擎 EJB 服务提供了一种使用自定义类型的机制。它们提供以下额外类型:
-
org.jbpm.services.ejb.remote.api.RemoteObject: a serializable wrapper class for single-value 参数 org.jbpm.services.ejb.remote.api.RemoteMap: A dedicatedjava.util.Map实现,以简化接受自定义对象输入的服务方法的远程调用。映射的内部实施包含已序列化的内容,以避免在发送时进行额外的序列化。这种实现不包括在发送数据时通常不使用的
java.util.Map的一些方法。
这些特殊对象使用 ObjectInputStream 对象执行大量序列化。它们消除了在 EJB 客户端/容器中对数据进行序列化的需求。因为不需要序列化,所以不需要与 EJB 容器共享自定义数据模型。
以下示例代码适用于本地类型和远程 EJB 服务:
使用带有远程 EJB 服务的本地类型
// Start a process with custom types via remote EJB
Map<String, Object> parameters = new RemoteMap();
Person person = new org.jbpm.test.Person("john", 25, true);
parameters.put("person", person);
Long processInstanceId = processService.startProcess(deploymentUnit.getIdentifier(), "custom-data-project.work-on-custom-data", parameters);
// Fetch task data and complete a task with custom types via remote EJB
Map<String, Object> data = userTaskService.getTaskInputContentByTaskId(taskId);
Person fromTaskPerson = data.get("_person");
fromTaskPerson.setName("John Doe");
RemoteMap outcome = new RemoteMap();
outcome.put("person_", fromTaskPerson);
userTaskService.complete(taskId, "john", outcome);
类似地,您可以使用 RemoteObject 类将事件发送到进程实例:
// Send an event with a custom type via remote EJB
Person person = new org.jbpm.test.Person("john", 25, true);
RemoteObject myObject = new RemoteObject(person);
processService.signalProcessInstance(processInstanceId, "MySignal", myObject);
68.4.4. 远程 EJB 客户端 复制链接链接已复制到粘贴板!
远程客户端支持通过实施 ClientServiceFactory 接口来提供,该界面是针对应用服务器特定代码的教导:
ClientServiceonnectionFactoryy 接口的 定义
/**
* Generic service factory used for remote lookups that are usually container specific.
*
*/
public interface ClientServiceFactory {
/**
* Returns unique name of given factory implementation
* @return
*/
String getName();
/**
* Returns remote view of given service interface from selected application
* @param application application identifier on the container
* @param serviceInterface remote service interface to be found
* @return
* @throws NamingException
*/
<T> T getService(String application, Class<T> serviceInterface) throws NamingException;
}
您可以使用 ServiceLoader 机制动态注册实现。默认情况下,红帽 JBoss EAP 中仅提供一个实施。
每个 ClientServiceonnectionFactory y 实施都必须提供名称。此名称用于在客户端 registry 中注册。按名称查找实施。
以下代码获取默认的 Red Hat JBoss EAP 远程客户端:
获取默认的 Red Hat JBoss EAP 远程客户端
// Retrieve a valid client service factory
ClientServiceFactory factory = ServiceFactoryProvider.getProvider("JBoss");
// Set the application variable to the module name
String application = "sample-war-ejb-app";
// Retrieve the required service from the factory
DeploymentServiceEJBRemote deploymentService = factory.getService(application, DeploymentServiceEJBRemote.class);
检索服务后,您可以使用其方法。
使用 Red Hat JBoss EAP 和远程客户端时,您可以添加以下 Maven 依赖项来引入所有 EJB 客户端库:
<dependency>
<groupId>org.jboss.as</groupId>
<artifactId>jboss-as-ejb-client-bom</artifactId>
<version>7.4.14.Final</version> <!-- use the valid version for the server you run on -->
<optional>true</optional>
<type>pom</type>
</dependency>