上下文是关于流程变量的。流程变量是维护同流程实例相关信息的键值对。因为上下文必须在数据库中可以存储,所以使用了一些细小的限制。
org.jbpm.context.exe.ContextInstance服务于同流程变量一同工作的中心接口。你可以 serves ProcessInstance 像这样来获得ContextInstance:
ProcessInstance processInstance = ...; |
最基本的操作是:
void ContextInstance.setVariable(String variableName, Object value); |
变量命名是java.lang.String。缺省,jBPM支持下列的值类型:
l java.lang.String
l java.lang.Boolean
l java.lang.Character
l java.lang.Float
l java.lang.Double
l java.lang.Long
l java.lang.Byte
l java.lang.Short
l java.lang.Integer
l java.util.Date
l byte[]
l java.io.Serializable
l hibernate使用的可持久化的类
无类型的null值也能被持久化地存储。
在流程变量中存储所有其他的类型没有什么问题。但当你保存流程实例时它将导致一个异常。
为了在流程变量中配置jBPM存储hibernate持久化对象,查看存储hibernate持久化对象。
变量不必在在流程包中声明。在运行时,你可以在流程变量中放置任何对象。如果那个变量不存在的话,那么它将被创建。这恰好和纯java.util.Map是一样的。
变量可以使用下面的方法来删除:
ContextInstance.deleteVariable(String variableName); |
现在支持自动类型改变。这意味着允许用一个不同类型的值去覆盖一个变量。当然同,你应该尝试去限制类型改变的数量,因为这会创建更多的数据库通信及纯粹的列更新。
变量是流程实例的一部分。在数据库中保存流程实例,让数据库和流程实例同步。变量在数据库中创建、更新和删除相当于流程实例在数据库中保存结果(等于更新)。更多的信息,请查看第7章 持久化。
每一个执行(阅读:令牌(token))有它自己的流程变量集。请求一个变量总是在令牌上完成的。流程变量有一个令牌树(查看:面向图的程序设计)。当请求一个变量而没有指定令牌时,默认的令牌是根令牌。
变量查找递归地通过给定的令牌的父亲完成。这个行为和程序设计语言中的变量范围是相似的。
当一个不存在的变量设置到令牌上时,这个变量在根令牌上被创建。这就意味着每一个变量都有默认的流程范围。为了生成令牌局部(token-local)变量,你不得不明确地创建它:
ContextInstance.createVariable(String name, Object value, Token token); |
变量重载意味着每一个执行路径能够有它自己的一个同名变量复本。它们互不相关而且以后还可以有不同的类型。变量重载如果你通过同一个转换启动多个并发执行路径的话是令人感兴趣的。那么唯一要辨别的是那些执行路径都有它们各自的变量集。
变量重写(variable overriding)意味着嵌套执行路径的变量在更全局的执行路径里重写。通常,嵌套执行路径关联到并发:在分支和合并间的执行路径是到达合并的执行路径的孩子(嵌套的)。例如:如果你在流程实例范围内有一个变量'contact',那么你就能够在嵌套执行路径'shipping' 和 'billing上重写这个变量。
更多关于任务实例变量的信息,请查看12.4 任务实例变量部分。
当一个流程实例在数据库中被持久时,正常变量也作为流程实例的一部分被持久化。某些情形下你可能想在代理(delegation)类中使用一个变量,但是你不想在数据库中存储它。一个例子充当这样的从jBPM的外部传递到代理类的数据库连接。这就能被瞬态变量完成。
瞬态变量的生存期和流程实例java对象相同。
因为它们的天性,瞬态变量不能同令牌关联。所以只有一个为流程实例对象的瞬态变量的映射。
瞬态变量使用它们自己的上下文实例中的方法集来访问,而且不需要在processdefinition.xml中声明。
Object ContextInstance.getTransientVariable(String name); void ContextInstance.setTransientVariable(String name, Object value); |
变量以2步(2-step)方案存储到数据库中:
用户java对象(user-java-object )<-->转换器( converter)<--> 变量实例(variable instance) |
变量被存储在变量实例中。变量实例的成员使用hibernate在数据库中被映射到字段。在jBPM的缺省配置中,变量实例使用6种类型:
l DateInstance(用java.lang.Date字段映射到数据库中的Types.TIMESTAP)
l DoubleInstance(用java.lang.Double字段映射到数据库中的Types.DOUBLE)
l StringInstance(用一个java.lang.String字段映射到数据库中的Types.VARCHAR)
l LongInstance(用一个java.lang.Long字段映射到数据库中的Types.BIGINT)
l HibernateLongInstance(这是hibernate表类型使用的长整数id字段。用一个java.lang.Object字段字映射作一个数据库中hibernate实体引用)
l HibernateStringInstance(这是hibernate表类型使用的字符串id字段。用一个java.lang.Object字段作被映射作一个数据库中hibernate实体引用)
转换器(converter)在java用户对象和能够通过变量实例存储的java对象之间转换。所以当流程变量使用如ContextInstance.setVariable(String variableName, Object value)设置时,这个值将使用转换器可选地被转换。然后被转换的对象将被存储在变量实例(VariableInstance)中。转换器是下面的接口实现:
public interface Converter extends Serializable { boolean supports(Object value); Object convert(Object o); Object revert(Object o); } |
转换器是可选的。转换器必须是jBPM类加载器可用的。
用户java对象被转化并存储在变量实例中的方式被配置在文件org/jbpm/context/exe/jbpm.varmapping.properties中。为了定制这个属性文件,在类路径的根下面放置一个修改过的版本,就像6.3其他配置文件部分一样属性文件的每行指定了2至3相被空格分隔的类名:用户java对象的类名、可选的转换器的类名和变量实例的类名。当你引用你自定义的转换器时,他们也必须在jBPM类路径中而且hibernate映射文件org/jbpm/context/exe/VariableInstance.hbm.xml必须被更新来包含定制的VariableInstance的子类。
例如,看下org/jbpm/context/exe/jbpm.varmapping.xml文件中的下列xml片段。
<jbpm-type> <matcher> <bean class="org.jbpm.context.exe.matcher.ClassNameMatcher"> <field name="className"><string value="java.lang.Boolean" /></field> </bean> </matcher> <converter class="org.jbpm.context.exe.converter.BooleanToStringConverter" /> <variable-instance class="org.jbpm.context.exe.variableinstance.StringInstance" /> </jbpm-type> |
这个片段指定了java.lang.Boolean类型的所有对象必须使用BooleanToStringConverter转换器被转化并且结果对象(一个String字符串)将被存储在StringInstance灵类型的变量实例对象中。
如果没有转换被指定,如下:
<jbpm-type> <matcher> <bean class="org.jbpm.context.exe.matcher.ClassNameMatcher"> <field name="className"><string value="java.lang.Long" /></field> </bean> </matcher> <variable-instance class="org.jbpm.context.exe.variableinstance.LongInstance" /> </jbpm-type> |
那就意味着放在变量中的Long型对象只是存储在LongInstance类型的变量实例中并没有被转化。
:-)