Jbpm Delegation机制源代码分析和实例
来源:互联网 发布:老子西出函谷关 知乎 编辑:程序博客网 时间:2024/06/06 23:56
分析版本
作者:吴大愚
Email:dywu_xa@sina.com
1. 什么是Delegation
在分析Jbpm的Delegation机制之前,我们要先搞明白什么是Delegation。在这里我不细写什么是Delegation,而给出两个链接,这两个连接都是csdn上面的博客文章,讲解了什么是Delegation机制。
《Delegation模式》:http://blog.csdn.net/mildwind/archive/2004/12/15/217553.aspx
《delegation(委托)vs. composition(复合)?》:http://blog.csdn.net/fantasylu/archive/2004/07/22/44901.aspx
如果这两个链接失效的话,大家也可以在我的博客(http://blog.csdn.net/dust_bug)上面找一篇我转载并总结的有关Delegation机制的文章。
简单的说一下什么是Delegation。
在Jbpm的user guide第16.2节中说道“Delegation is the mechanism used to include the users' custom code in the execution of processes.”。
有人这么说“委托(Delegation)模式是一种技术,一个对象在外界来看好像实现了一些行为,但实际上是委托给相关的其他类来实现行为的”(见《Delegation模式》)。还有人说真正的Delegation不是这样的,还必须有更高的要求才是Delegation,他们这么说“To achieve the same effect with delegation, the receiver passes itself to the delegate to let the delegated operation refer to the receiver”(见《delegation(委托)vs. composition(复合)?》)
在Jbpm中的Delegation应该是第一种观点中的Delegation。
2. Jbpm在何处使用Delegation
就像Jbpm的文档中自己写的那样,Jbpm使用Delegation机制是为了在流程执行中能够使用用户自己定制的代码(user’s custom code)。
在jPDL的schema定义中,有四个元素是可以添加用户自己定制的类。那就是action,assignment,controller和handler。这四个元素都有两个共同的属性,class和config-type。其中,action元素中class所指定的类必须实现org.jbpm.graph.def.ActionHandler接口。Assignment元素的class所指定的类必须实现org.jbpm.taskmgmt.def.AssignmentHandler接口。controller元素的class所指定的类必须实现org.jbpm.taskmgmt.def.TaskControllerHandler接口。handler元素的class所指定的类必须实现org.jbpm.graph.node.DecisionHandler接口。
在这四个元素的schema定义中还都有一个没有Name属性的成员“{content}”。Jbpm对它的解释是“the content of the handler can be used as configuration information for your custom handler implementations. This allows the creation of reusable delegation classes.”我会在Delegation的配置类型部分,详细讲解这个内容。
图一是Delegation的相关的类图。我们本文关心的所有的类都在这里。
下面让我们先来分析一下Jbpm是如何实现在流程执行中使用用户自己定制的代码的吧。
3. Delegation类和它所使用到的类
我们先来看一下在Jbpm中Delegation是被谁委托的,又能代表谁做什么事情呢?
3.1. org.jbpm.instantiation. Instantiator接口
instantiation是什么意思呢?查了金山词霸,原来是实例化的意思。那实例化什么呢?
这个接口就一个方法Object instantiate(Class clazz, String configuration);Jbpm并没有给这个方法说明。通过后面的分析,发现实现这个方法的类,在这个方法中都是使用反射机制创建了客户自定义的类的对象。方法的第一个参数clazz就是要创建的类的Class,第二个参数是用来传递流程定义xml文件中相应的部分,用来对客户自定义的类进行配置的。
3.2. 实现Instantiator接口的类
实现这个接口的一共有六个类,分别是FieldInstantiator,BeanInstantiator,ConstructorInstantiator,ConfigurationPropertyInstantiator,DefaultInstantiator和XmlInstantiator。以上六个类都是在org.jbpm.instantiation包中,其中后两个类虽然定义了,但是在jb
在DefaultInstantiator的instantiate方法中就一条核心语句:
return clazz.newInstance();
这条语句也都出现在其他5个类的instantiate()方法中。可以看出这六个类其核心就是采用不同的方式创建客户自定义的类。
下面我以FieldInstantiator类作为例子进行分析。
3.3. FieldInstantiator类
在FieldInstantiator类的instantiate()方法中。以下用伪代码表示:
Object instantiate(Class clazz, String configuration){
根据参数clazz创建一个对象;
If(参数configuration有内容){
将configuration转化成为xml节点形式;
}
遍历xml节点{
调用setPropertyValue()方法,将xml节点的值注入到新创建的对象中去。
}
返回新创建的对象;
}
setPropertyValue(Class clazz, Object newInstance, String propertyName, Element propertyElement)有四个参数。第一个参数clazz是第二个参数newInstance的Class对象。第三个参数propertyName是newInstance的一个成员名称。第四个参数是一个xml对象,其中具有要付给propertyName这个成员的值。
3.4. org.jbpm.instantiation.Delegation类
简单的说Delegation类的作用就是代理上面所提到的四个实现了Instantiator接口的类(FieldInstantiator,BeanInstantiator,ConstructorInstantiator,ConfigurationPropertyInstantiator)来创建客户定制的类的实例。
Delegation类最主要的方法是instantiate()。这个方法功能是调用上面四个类中一个的instantiate()方法,创建一个客户化对象,然后返回这个对象。
下面我们来具体分析一下。
3.4.1. instantiatorCache成员
Delegation类有一个map成员instantiatorCache。在初始化阶段,这个成员会被添加五个元素。这些元素的key为string类型,value为分别实现Instantiator接口的对象。分别为(null, new FieldInstantiator()),("field", new FieldInstantiator()),("bean", new BeanInstantiator()),("constructor", new ConstructorInstantiator()),("configuration-property", new ConfigurationPropertyInstantiator())。instantiatorCache作甚么用呢?它就是用来存储Delegation所有代理的对象。
3.4.2. Instantiate()方法
instantiate()方法主要步骤如下:
Object instantiate(){
根据类的成员className,创建相应的Class对象clazz;
根据类的成员configType,从instantiatorCache找到相应Instantiator接口的的对象,存放在instantiator变量中。
以clazz和类的成员configuration作为参数,调用instantiator的instantiate方法。创建客户化对象;(Delegation模式就是这儿:)
返回创建的对象;
}
有一点要说明,就是Jbpm还支持自定义的实现instantiator接口的类来创建自己的客户化对象。也就是说,我们可以来定义自己的instantiator类,自己实现如何创建客户化类的过程。
3.4.3. read()方法
instantiate()方法中使用到的类的成员className,configType,configuration都是在类的方法read(Element delegateElement, JpdlXmlReader jpdlReader)中得到的。其参数delegateElement就是我们所说的Jbpm中能够使用客户化类的四种元素(action,assignment,controller和handler)之一的xml节点。
我们通过delegateElement可以得到xml节点的class、config-type属性,分别付给类的className和configType成员。而类的configuration成员,存放的就是xml节点内的所有字符 串。
例如,对于一个action类型的xml节点:
<action class=”dust.action.action1Handler” config-type=”field”>
<name>dust</name>
<count>5</count>
</action>
那么经过read()方法,成员class=”dust.action.action1Handler”,成员config-type=”field”,而configuration=” <name>dust</name><count>5</count>”
我们现在基本知道了Delegation类是干什么用的,那么Jbpm是怎么用Delegation类的呢?我下面就分析一下Action中如何使用Delegation创建客户化类的对象并调用的。
4. 在Action中实例分析如何使用Delegation
在org.jbpm.graph.def .Action类中有一个成员actionDelegation,类型为Delegation。在read()方法中,如果<action>元素包含一个class属性,那么就会创建一个Delegation的对象,并赋给成员actionDelegation。然后调用actionDelegation的read()方法。
在Action. execute()方法中,如果actionDelegation不为null,那么就会调用如下的语句:
ActionHandler actionHandler = (ActionHandler)actionDelegation.getInstance();
actionHandler.execute(executionContext);
看明白了吧,首先通过getInstance()创建一个实现了ActionHandler接口的客户化对象,然后调用这个对象的execute()方法。
Yes!We get it! 我们对上了!通过上面的分析,我们终于把jPDL语言中,一个Action元素所指定的客户化类创建出来,并且调用执行客户代码进行了分析。路修通啦J
同样,在org.jbpm.graph.node.Decision类有一个成员Delegation decisionDelegation;在org.jbpm.taskmgmt.def. TaskController类有一个成员Delegation taskControllerDelegation;在org.jbpm.taskmgmt.def. Task类有一个成员Delegation assignmentDelegation;在org.jbpm.taskmgmt.def. Swimlane类有一个成员Delegation assignmentDelegation。这些类型为Delegation的成员的作用都等同于Action类中的actionDelegation。
到此为止,我们把Delegation的内容基本上说完了。但是我前面一直在回避一个方面,那就是四种xml元素的config-type属性所起到的作用。下面我们就来看看在Jbpm中Delegation的配置类型。
5. Delegation的配置类型
在Jbpm的userguide的第
回忆一下,Delegation类有一个map成员instantiatorCache。它五个元素的key,除了null,其余四个正是我们上面列出的四个值。也就是说,在建模的时候,对于<action class=”dust.action.Action1Handler” config-type=”field”>元素, Action类的actionDelegation成员的instantiate()方法就会选择instantiatorCache中的FieldInstantiator对象来实例化dust.action.Action1Handler类。如果config-type=”bean”,那么就会选择BeanInstantiator。依次类推。
如果你不写config-type那么这个时候instantiatorCache的null就起作用了,所以默认还是FieldInstantiator。
那么FieldInstantiator,BeanInstantiator,ConfigurationPropertyInstantiator ,ConstructorInstantiator,四个类创建客户化对象有什么不同呢?
我们先写个类dust.action.Action1Handler,来看看。
public Action1Handler implements ActionHandler{
String name;
int count;
public Action1Handler(){}
public Action1Handler(String configuration){
System.out.println("==Action1Handler contstructor==");
System.out.println("==configuration is:"+configuration+"==");
}
public void setConfiguration(String configuration){
System.out.println("==Action1Handler setConfiguration==");
System.out.println("==configuration is:"+configuration+"==");
}
// getters and setters //////////////////////////////////////////////////////
public void setName(String name){
this.name = name;
}
public String getName(){
return this.name ;
}
public void setCount(int count){
this.count = count;
}
public int getCount(){
return count;
}
public void execute(ExecutionContext executionContext) throws Exception {
// TODO Auto-generated method stub
}
}
下面我们假设流程定义为中有
<action class=”dust.action.Action1Handler” config-type=”field”>
<name>dust</name>
<count>5</count>
</action>
5.1. FieldInstantiator类
当config-type为field时,或者没有config-type属性,会使用FieldInstantiator类。
FieldInstantiator类使用反射机制直接对类的成员进行赋值。
也就是说FieldInstantiator会直接将dust付给name,5付给count。
5.2. BeanInstantiator类
当config-type为bean时,会使用BeanInstantiator类。
BeanInstantiator类必须使用setter属性,来对成员赋值。
即,BeanInstantiator使用setName()和setCount()。如果没有这两个方法,那么就会在日志中报错。
5.3. ConstructorInstantiator类
当config-type为constructor时,会使用ConstructorInstantiator类。
ConstructorInstantiator类会调用客户类的具有一个String类型参数的构造函数。并且将<action>元素的所有内容作为字符串类型的参数,传给构造函数。客户可以在这个构造函数中自己处理这段xml文档。
也就是说Jbpm会调用 public Action1Handler(String configuration){}。
5.4. ConfigurationPropertyInstantiator类
当config-type为configuration-property时,会使用ConfigurationPropertyInstantiator类。
ConfigurationPropertyInstantiator类会调用客户类的具有一个String类型参数的一个名叫setConfiguration()方法。并且将<action>元素的所有内容作为字符串类型的参数,传给setConfiguration方法。客户可以在这个方法中自己处理这段xml文档。
也就是说Jbpm会调用 public void setConfiguration(String configuration){}方法。
在Jbpm执行一个流程实例过程中,当遇到一个Action时,会首先实例化流程定义中的Action元素指定的客户化类。如果没有指定config-type的话,那么会调用客户化类的默认构造函数。然后调用execute()方法。
如果config-type为field或bean的话,那么就会在调用execute()前进行属性赋值;如果config-type为constructor,那么就会调用有参数的构造函数;如果config-type为configuration-property是,会先调用默认构造函数,然后调用setConfiguration()方法。
- Jbpm Delegation机制源代码分析和实例
- delegation机制
- JBPM 3.2.3之【ERROR Delegation 】异常
- jbpm源代码研究(三)-------环境和上下文
- Netconsole实例源代码分析
- 一个Jbpm员工请假流程的实例源代码下载
- JBoss 系列五十八:jBPM Human Task 源代码分析 - I
- JBoss 系列五十九:jBPM Human Task 源代码分析 - II
- jbpm实例
- JBPM (三) 服务和实例介绍
- Delegation
- Lenix消息机制源代码分析
- ReactOS源代码分析APIC机制
- java反射机制和自定义注解原理分析和实例
- java反射机制实例分析
- JBPM (四) 浅析JBPM中的实例变量和任务变量
- linux epoll机制源代码分析一数据结构
- Zookeeper源代码阅读分析之watcher机制
- 二叉树的基本运算实验
- 文章三篇
- Hooking KiFastSystemCall
- OOP在三层系统中的应用
- Thought of js package, namespace or module again
- Jbpm Delegation机制源代码分析和实例
- JSIntegration
- C.M. Coolidge画的狗
- 核心(Core) Javascript 学习手记
- Friendly URLs in Tapestry
- 工作日志2006.11.26
- Tomcat Mysql 。。。学习笔记
- 产生高质量成比例缩略图
- 思