JBPM5 Chapter 4

来源:互联网 发布:淘宝开店得交多少钱 编辑:程序博客网 时间:2024/05/22 12:53

本章介绍了你需要装载(load)及执行(execute)的流程会用到的API。至于如何定义流程的细节,请参照BPMN2.0章节

你需要建立(set up)一个session来与流程引擎交互(如启动一个流程)。一个session需要引用知识库(knowledge base),知识库包含了对于所有相关流程定义的引用,知识库用来查找流程定义。创建一个session,首先需要创建一个知识库,装载所有需要的流程定义(可能从不同的源来装载,如classpath ,文件系统或流程仓库(process repository))然后初始化一个session

一旦你建立(set up)了一个session,你可以用它来开始执行流程。每当一个流程开启,一个新的流程实例被创建以维护特定的流程实例的状态


举个例子,想象一下你正在写一个应用来处理销售订单,你可能会定义一个或多个流程定义来定义订单如何被处理。当启动应用时,你首先需要创建一个知识库(knowledge base)来包含这些流程定义,然后在knowledge base的基础上来创建一个session以至于每当一个新的订单到达时,一个新的流程实例能被启动来处理相应的订单。这个流程实例包含着特定销售请求的流程的状态

一个knowledge base可以被众多session共享并且通常仅在应用启动的时候被创建一次且仅一次(由于需要解析及编译许多流程定义,创建一个knowledge base是嗷嗷重量级的)。Knowledge base是可以动态变化的(所以你可以在运行时增加或删除流程)

Session可以基于knowledge base被创建,被用来执行流程和与引擎交互。你可以创建许多互相独立的session, session的创建相对来说是轻量级的。被创建的session数量取决于你的需要。一般来说,许多简单的案例是创建一个session然后在很多地方调用它。如果你有许多相互独立的处理单元(processing unit)你可以创建许多session(例如你想让一个顾客的流程处理完全独立于另外一个顾客的流程处理,你可以为每个顾客创建相互独立的session)或者你由于可扩展性的原因(scalability)需要创建多个session。如果你不知道咋弄,创建一个包含所有流程定义的knowledge base及一个用来执行所有流程(process)session

4.1 JBPM API

JBPM项目在用户需要访问的API和真正的实现类之间有一个清晰的分离。公共的API暴露了许多普通用户可以安全使用的特性,并且将会在以后的版本中保持持续稳定。专家级用户仍旧可以访问内部实现类,但他们必须知道自己在干嘛并且这些内部API在今后可能会有变化。

如上所述,JBPM API应该被用来(1)创建一个包含一些流程定义的knowledge base (2)创建一个session来启动新的流程实体,与已有的流程实体通讯,注册监听器等。

4.1.1. Knowledge Base

JBPM让你首先创建一个knowledge base。这个knowledge base应该包含你所有的流程定义,这些流程定义之后会被session所用到。用一个knowledge builder来装载从不同源头(如从classpath或从文件系统)所得到的流程,然后用knowledge builder来创建一个新的knowledge base。以下代码片段展示了如何创建一个仅包含一条流程定义的knowledge base

KnowledgeBuilder kbuilder = KnowledgeBuilderFactory.newKnowledgeBuilder();
kbuilder.add(ResourceFactory.newClassPathResource("MyProcess.bpmn"), ResourceType.BPMN2);
KnowledgeBase kbase = kbuilder.newKnowledgeBase();

ResourceFactory有相似的方法来从文件系统、urlinputstreamReader来装载文件

4.1.2. Session

一旦你装载了你的knowledge base,你应该创建一个session与引擎交互。这个session被用来启动一个新的实例,发送事件。以下代码片段展示了如何基于之前创建的knowledge base来创建一个session,启动一个流程(根据ID)。

StatefulKnowledgeSession ksession = kbase.newStatefulKnowledgeSession();
ProcessInstance processInstance = ksession.startProcess("com.sample.MyProcess");

ProcessRuntime接口定义了所有用来与流程交互的session方法,如下所示

/**


     * Start a new process instance.  The process (definition) that should


     * be used is referenced by the given process id.


     * 


     * @param processId  The id of the process that should be started


     * @return the ProcessInstance that represents the instance of the process that was started


     */


    ProcessInstance startProcess(String processId);


    /**


     * Start a new process instance.  The process (definition) that should


     * be used is referenced by the given process id.  Parameters can be passed


     * to the process instance (as name-value pairs), and these will be set


     * as variables of the process instance. 


     * 


     * @param processId  the id of the process that should be started


     * @param parameters  the process variables that should be set when starting the process instance 


     * @return the ProcessInstance that represents the instance of the process that was started


     */


    ProcessInstance startProcess(String processId,


                                 Map<String, Object> parameters);


    /**


     * Signals the engine that an event has occurred. The type parameter defines


     * which type of event and the event parameter can contain additional information


     * related to the event.  All process instances that are listening to this type


     * of (external) event will be notified.  For performance reasons, this type of event


     * signaling should only be used if one process instance should be able to notify


     * other process instances. For internal event within one process instance, use the


     * signalEvent method that also include the processInstanceId of the process instance


     * in question. 


     * 


     * @param type the type of event


     * @param event the data associated with this event


     */


    void signalEvent(String type,


                     Object event);


    /**


     * Signals the process instance that an event has occurred. The type parameter defines


     * which type of event and the event parameter can contain additional information


     * related to the event.  All node instances inside the given process instance that


     * are listening to this type of (internal) event will be notified.  Note that the event


     * will only be processed inside the given process instance.  All other process instances


     * waiting for this type of event will not be notified.


     * 


     * @param type the type of event


     * @param event the data associated with this event


     * @param processInstanceId the id of the process instance that should be signaled


     */


    void signalEvent(String type,


                     Object event,


                     long processInstanceId);


    /**


     * Returns a collection of currently active process instances.  Note that only process


     * instances that are currently loaded and active inside the engine will be returned.


     * When using persistence, it is likely not all running process instances will be loaded


     * as their state will be stored persistently.  It is recommended not to use this


     * method to collect information about the state of your process instances but to use


     * a history log for that purpose.


     * 


     * @return a collection of process instances currently active in the session


     */


    Collection<ProcessInstance> getProcessInstances();


    /**


     * Returns the process instance with the given id.  Note that only active process instances


     * will be returned.  If a process instance has been completed already, this method will return


     * null.


     * 


     * @param id the id of the process instance


     * @return the process instance with the given id or null if it cannot be found


     */


    ProcessInstance getProcessInstance(long processInstanceId);


    /**


     * Aborts the process instance with the given id.  If the process instance has been completed


     * (or aborted), or the process instance cannot be found, this method will throw an


     * IllegalArgumentException.


     * 


     * @param id the id of the process instance


     */


    void abortProcessInstance(long processInstanceId);


    /**


     * Returns the WorkItemManager related to this session.  This can be used to


     * register new WorkItemHandlers or to complete (or abort) WorkItems.


     * 


     * @return the WorkItemManager related to this session


     */


    WorkItemManager getWorkItemManager();

4.1.3 事件

Session提供了方法用来注册和去除监听器。ProcessEventListener被用来监听流程相关的事件,如开启或完成一个流程(process)、进入或离开一个节点(node)等。以下是ProcessEventListener的一些不同的方法。一个事件对象提供了 对相关信息的访问,如与事件相连(link)的流程实体(process instance),节点实体(node instance)。你可以使用这个API注册自己的事件监听器。

public interface ProcessEventListener {


  void beforeProcessStarted( ProcessStartedEvent event );


  void afterProcessStarted( ProcessStartedEvent event );


  void beforeProcessCompleted( ProcessCompletedEvent event );


  void afterProcessCompleted( ProcessCompletedEvent event );


  void beforeNodeTriggered( ProcessNodeTriggeredEvent event );


  void afterNodeTriggered( ProcessNodeTriggeredEvent event );


  void beforeNodeLeft( ProcessNodeLeftEvent event );


  void afterNodeLeft( ProcessNodeLeftEvent event );


  void beforeVariableChanged(ProcessVariableChangedEvent event);


  void afterVariableChanged(ProcessVariableChangedEvent event);


}

JBPM提供了一个监听器用来创建一个审核日志(audit log)(到控制台或者一个文件)。这个审核日志包含了所有运行时可能发生的不同的事件,所以它能很容易知道运行时发生了什么。注意,这个logger仅仅用于debug。如下logger的实现是默认被支持的:

1.Console logger: 这个loggerconsole上写出了所有的事件

2.File logger:这个loggerXML的形式将所有事件写入一个文件。在IDE中将根据这个日志文件展示出在运行时所发生的一个树状事件集

3.线程级的file logger: 由于一个file logger仅仅在关闭logger或事件的数量达到之前定义的数目时才会向硬盘中写入,它无法在运行时用来debug流程。一个threaded file logger每隔一段时间向文件中写入事件,使在debug流程时用它来将流程运行过程可视化成为可能。

KnowledgeRuntimeLoggerFactory能将一个logger加入session中,如下所示。当创建一个console loggerknowledge session必须作为参数传入,它也需要一个日志文件名作为参数,threaded file logger还需要一个事件被保存的间隔时间(milliseconds)。在应用结束时我们应该关闭logger

KnowledgeRuntimeLogger logger =


    KnowledgeRuntimeLoggerFactory.newFileLogger( ksession, "test" );


// add invocations to the process engine here,


// e.g. ksession.startProcess(processId);


...


logger.close();

File-based logger包含了一个XML形式的所有运行时事件的总览。能用安装了Drools Eclipse 插件的eclipse打开,在Eclipse里它展示成一颗事件树。Before envent 和 After Event事件作为此Event事件的子事件

4.2Knowledge-based API

你也许注意到了,JBPM项目暴露的API为一个knowledge API。这意味着它并不仅仅专注于流程,而是潜在的允许其它类型的knowledge被装载。这对仅仅关注于流程的用户的影响非常小。你可以用KnowledgeBaseKnowledgeSession来代替ProcessBaseProcessSession

如果你打算在你的应用中使用商业规则或复杂事件,knowledge-based API允许用户以完全相同的方式加入不同类型的资源(resource)(例如流程和规则)至相同的knowledge base。因为对不同类型的knowledgeAPI和工具是统一的,它让会使用JBPM的用户开始使用Drools Expert(处理商业规则)Drools Fusion(处理事件)