﻿<?xml version="1.0" encoding="utf-8" standalone="yes"?><rss version="2.0" xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:trackback="http://madskills.com/public/xml/rss/module/trackback/" xmlns:wfw="http://wellformedweb.org/CommentAPI/" xmlns:slash="http://purl.org/rss/1.0/modules/slash/"><channel><title>语源科技BlogJava-囧囧之猪</title><link>http://www.blogjava.net/fullqin/</link><description /><language>zh-cn</language><lastBuildDate>Sun, 12 Apr 2026 06:02:38 GMT</lastBuildDate><pubDate>Sun, 12 Apr 2026 06:02:38 GMT</pubDate><ttl>60</ttl><item><title>【原】通过jbpm源码分析jbpm引擎内核工作原理</title><link>http://www.blogjava.net/fullqin/archive/2008/09/16/229236.html</link><dc:creator>囧囧之猪</dc:creator><author>囧囧之猪</author><pubDate>Tue, 16 Sep 2008 11:28:00 GMT</pubDate><guid>http://www.blogjava.net/fullqin/archive/2008/09/16/229236.html</guid><wfw:comment>http://www.blogjava.net/fullqin/comments/229236.html</wfw:comment><comments>http://www.blogjava.net/fullqin/archive/2008/09/16/229236.html#Feedback</comments><slash:comments>5</slash:comments><wfw:commentRss>http://www.blogjava.net/fullqin/comments/commentRss/229236.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/fullqin/services/trackbacks/229236.html</trackback:ping><description><![CDATA[<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; Jbpm，他是jboss下的一个开源项目，是个基于petri net理论为基础的工作流引擎。本文主要通过jbpm源代码分析下jbpm引擎内核工作原理。<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; Jbpm是基于微内核引擎的基础上扩展开发出来的工作流平台，其运行的核心包是在org.jbpm.graph下，在该包下又分有action、def、exe、log、node几个包，jbpm内核引擎实现逻辑主要存放在def、exe这两个包下，其他的包是基于此内核扩展出来的动作、模型和日志。<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 下面我们通过一个简单的例子来逐步的分析jbpm是如何工作的。看下面jbpm自带演示的一个hello流程（视乎大家都喜欢从hello实现开始^_^），代码如下：<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;public void testHelloWorldProcess() {<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;ProcessDefinition processDefinition = ProcessDefinition.parseXmlString(<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;"&lt;process-definition&gt;" +<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;" &lt;start-state&gt;" +<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;" &lt;transition to='s' /&gt;" +<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;" &lt;/start-state&gt;" +<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;" &lt;state name='s'&gt;" +<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;" &lt;transition to='end' /&gt;" +<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;" &lt;/state&gt;" +<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;" &lt;end-state name='end' /&gt;" +<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;"&lt;/process-definition&gt;"<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;);</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;ProcessInstance processInstance =new ProcessInstance(processDefinition);<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Token token = processInstance.getRootToken();<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;assertSame(processDefinition.getStartState(), token.getNode());<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;token.signal();<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;assertSame(processDefinition.getNode("s"), token.getNode());<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;token.signal();<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;assertSame(processDefinition.getNode("end"), token.getNode());<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 首先，我们定义个流程模板（ProcessDefinition），就是上面代码的ProcessDefinition processDefinition = ProcessDefinition.parseXmlString(&#8230;.);这段，在括号中是jbpm定义的流程，其中包括三个环节，分别是starts-state、state和end-state。parseXmlString（）方法的主要功能是解析这段xml语言返回个流程模板对象（processDefinition）。<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 接着，通过流程实例类（ProcessInstance）来实例化个流程实例，通过传进来的流程模板对象创建ProcessInstance processInstance =new ProcessInstance(processDefinition)。我们来看看new ProcessInstance(processDefinition)到底做了什么，通过查看ProcessInstance的源代码，可以看到其中主要的一段是<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;public ProcessInstance( ProcessDefinition processDefinition ) {<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;//略去其他代码<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;this.processDefinition = processDefinition; //将流程模板对象付给流程实例<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;this.rootToken = new Token(this); //创建跟令牌<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;//略去其他代码<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 我们继续跟进Token这个类<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;public Token(ProcessInstance processInstance) {<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; //主要一句如下<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; this.node = processInstance.getProcessDefinition().getStartState();<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;这样就实现了令牌绑定到开始节点。至此，一个流程实例就创建起来了，并且该流程实例走到了开始节点，即令牌所处的位置。<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;我们接着往下走token.signal()<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;public void signal() {<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;signal(node.getDefaultLeavingTransition(), new ExecutionContext(this));<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;//这里的getDefaultLeavingTransition()如果有多条路径，则去第一条路径<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; }<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;void signal(Transition transition, ExecutionContext executionContext) {<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; //省略其他代码<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; node.leave(executionContext, transition);<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp;&nbsp;&nbsp; //省略其他代码<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &nbsp; }<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;这里的node就是刚才令牌所在的开始节点，我们来看看jbpm是如何将令牌从开始节点移到下个节点的。<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;public void leave(ExecutionContext executionContext, Transition transition) {<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; Token token = executionContext.getToken();<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; token.setNode(this);//此时令牌还在开始节点<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; executionContext.setTransition(transition);<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; //略去部分代码<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;executionContext.setTransitionSource(this);<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; transition.take(executionContext);//实现令牌的转移<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;我们来看看transition.take(..)方法做了什么<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;public void take(ExecutionContext executionContext) {<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; //略去部分代码<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; to.enter(executionContext);//离开开始节点，进入到下个节点<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;大家可能会有点疑问，这个to节点是什么是否初始化的？其实在signal时有句node.getDefaultLeavingTransition()，这句返回Transition对象，该对象就已经初始化了to节点的对象。我们在跟进to.enter(..)<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;public void enter(ExecutionContext executionContext) {<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; Token token = executionContext.getToken();<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; token.setNode(this);//此时令牌就到了名字为&#8220;s&#8221;的state节点<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; token.setNodeEnter(new Date());<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; executionContext.setTransition(null);<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; executionContext.setTransitionSource(null);<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; execute(executionContext);<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;在这段代码中的注释这句，真正实现了令牌从开始节点到下个节点了。<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;至此，jbpm工作流引擎的内部工作原理就介绍完了，其实这就是工作流引擎最核心的部分了，就是如何从一个环节转移到另一个环节。或许你会说&#8220;这么简单，我马上就可以写一个&#8221;，其实不然，上面我们所用的例子是十分简单的例子，其实在工作流联盟规范中还有其他复杂的节点模型，如split，join，subflow等。不过幸运的是这些复杂的节点模型jbpm都为我们提供了他自己的默认的实现，这些节点模型都在org.jbpm.graph.node包下。jbpm引擎中很好的抽象了节点模型Node类，大部分的复杂节点模型都继承自Node，我们也可以定制自己的节点，只要实现Node类的execute()方法即可方便的实现。其实从上面分析的代码可以看出，Node类主要的逻辑处理是在leave()、enter()和execute()三个方法，大家可以看下ProcessState，join，fork这些节点模型是如何实现的。<br />
以上简单介绍了jbpm引擎内核的工作原理，如有不对的地方还望指正。<br />
</p>
 <img src ="http://www.blogjava.net/fullqin/aggbug/229236.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/fullqin/" target="_blank">囧囧之猪</a> 2008-09-16 19:28 <a href="http://www.blogjava.net/fullqin/archive/2008/09/16/229236.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>从基于db的workflow转战到jbpm</title><link>http://www.blogjava.net/fullqin/archive/2008/09/15/229013.html</link><dc:creator>囧囧之猪</dc:creator><author>囧囧之猪</author><pubDate>Mon, 15 Sep 2008 10:21:00 GMT</pubDate><guid>http://www.blogjava.net/fullqin/archive/2008/09/15/229013.html</guid><wfw:comment>http://www.blogjava.net/fullqin/comments/229013.html</wfw:comment><comments>http://www.blogjava.net/fullqin/archive/2008/09/15/229013.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/fullqin/comments/commentRss/229013.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/fullqin/services/trackbacks/229013.html</trackback:ping><description><![CDATA[<p><span style="font-family: 宋体">&nbsp;&nbsp;&nbsp; 开始接触工作流是两年前，那时刚进公司，自己也算是个新手，到公司后被分配到做</span>IT<span style="font-family: 宋体">网管的项目组，做了些东西，后来成立了个新的项目组，我被分配到这个新组成的项目组，也就是从这以后开始接触工作流的。当时对工作流是一点概念都没有，慢慢从公司开发的基于</span>db<span style="font-family: 宋体">的工作流平台开始接触工作流，并基于此工作流平台结合业务开发了几个模块。<br />
</span><span style="font-family: 宋体">&nbsp;&nbsp;&nbsp; 公司的这个基于</span>db<span style="font-family: 宋体">的工作流平台还是实现了许多功能：<br />
</span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 1<span style="font-family: 宋体">、基于</span>web<span style="font-family: 宋体">的流程设计器，主要是基于</span>IE<span style="font-family: 宋体">的</span>vml<span style="font-family: 宋体">语言开发的，可以设计出如下图的流程模板。<br />
<img alt="" src="http://www.blogjava.net/images/blogjava_net/fullqin/34626/r_4.gif" border="0" /><br />
&nbsp;&nbsp;&nbsp;&nbsp;<span style="font-family: 宋体; mso-ascii-font-family: 'Times New Roman'; mso-hansi-font-family: 'Times New Roman'">此流程模板包括开始环节，结束环节以及人工处理的两个环节（专家组处理和发起人确认），实现环节的自循环以及回朔，分别在&#8220;专家组处理&#8221;环节和&#8220;发起人确认&#8221;环节上实现。基于此流程运行中的实例图如下：</span></p>
<img alt="" src="http://www.blogjava.net/images/blogjava_net/fullqin/34626/r_instance.gif" border="0" /><br />
&nbsp;&nbsp;&nbsp; 2<span style="font-family: 宋体">、环节的扭转<br />
</span>&nbsp;&nbsp;&nbsp; A<span style="font-family: 宋体">、串行<br />
</span><span style="font-family: 宋体">&nbsp;&nbsp;&nbsp; 像上图中介绍的就是实现了串行的功能。<br />
</span>&nbsp;&nbsp;&nbsp; B<span style="font-family: 宋体">、并行</span><span style="font-size: 10.5pt; font-family: 宋体">如图<br />
<img alt="" src="http://www.blogjava.net/images/blogjava_net/fullqin/34626/r_5.gif" border="0" /><br />
&nbsp;&nbsp;&nbsp; C<span style="font-family: 宋体">、多实例（即平常所说的会签）<br />
</span><span style="font-family: 宋体">&nbsp;&nbsp;&nbsp; 实现了包括所有会签都完成后才往下个环节走和几个会签后就可往下个环节走的功能，流程的模板如图：<br />
<img alt="" src="http://www.blogjava.net/images/blogjava_net/fullqin/34626/r_3.gif" border="0" /><br />
&nbsp;&nbsp;&nbsp; <span style="font-family: 宋体; mso-ascii-font-family: 'Times New Roman'; mso-hansi-font-family: 'Times New Roman'">其中环节模板上带&#8220;</span><span lang="EN-US">M</span><span style="font-family: 宋体; mso-ascii-font-family: 'Times New Roman'; mso-hansi-font-family: 'Times New Roman'">&#8221;的环节就表示是多实例的环节。<br />
</span><span style="font-size: 10.5pt; font-family: 宋体; mso-ascii-font-family: 'Times New Roman'; mso-hansi-font-family: 'Times New Roman'; mso-bidi-font-size: 12.0pt; mso-font-kerning: 1.0pt; mso-bidi-font-family: 'Times New Roman'; mso-ansi-language: EN-US; mso-fareast-language: ZH-CN; mso-bidi-language: AR-SA">&nbsp;&nbsp;&nbsp; 运行中的实例如图：<br />
<img alt="" src="http://www.blogjava.net/images/blogjava_net/fullqin/34626/r_1.gif" border="0" /><br />
&nbsp;&nbsp;&nbsp; D<span style="font-family: 宋体">、子流程</span><span style="font-size: 10.5pt; font-family: 宋体">子流程是在一个虚拟环节中实现的，即该环节不是人工环节。如图：<br />
<img alt="" src="http://www.blogjava.net/images/blogjava_net/fullqin/34626/r_ss.gif" border="0" /><br />
&nbsp;&nbsp;&nbsp; <span style="font-size: 10.5pt; font-family: 宋体; mso-ascii-font-family: 'Times New Roman'; mso-hansi-font-family: 'Times New Roman'; mso-bidi-font-size: 12.0pt; mso-font-kerning: 1.0pt; mso-bidi-font-family: 'Times New Roman'; mso-ansi-language: EN-US; mso-fareast-language: ZH-CN; mso-bidi-language: AR-SA">基本上一个简单的工作流平台的功能都差不多实现了，不过在使用过程中还是发现了许多的弊端，毕竟系统的逻辑大部分是基于数据库函数实现的，这使得大部分的逻辑都要依赖于数据库，而外围的一些基于</span><span lang="EN-US" style="font-size: 10.5pt; font-family: 'Times New Roman'; mso-bidi-font-size: 12.0pt; mso-font-kerning: 1.0pt; mso-ansi-language: EN-US; mso-fareast-language: ZH-CN; mso-bidi-language: AR-SA; mso-fareast-font-family: 宋体">java</span><span style="font-size: 10.5pt; font-family: 宋体; mso-ascii-font-family: 'Times New Roman'; mso-hansi-font-family: 'Times New Roman'; mso-bidi-font-size: 12.0pt; mso-font-kerning: 1.0pt; mso-bidi-font-family: 'Times New Roman'; mso-ansi-language: EN-US; mso-fareast-language: ZH-CN; mso-bidi-language: AR-SA">的逻辑实现就比较难实现了，举个例子：在和外系统做接口时，当某个环节竣工后要向外系统发信息，而信息是通过</span><span lang="EN-US" style="font-size: 10.5pt; font-family: 'Times New Roman'; mso-bidi-font-size: 12.0pt; mso-font-kerning: 1.0pt; mso-ansi-language: EN-US; mso-fareast-language: ZH-CN; mso-bidi-language: AR-SA; mso-fareast-font-family: 宋体">url</span><span style="font-size: 10.5pt; font-family: 宋体; mso-ascii-font-family: 'Times New Roman'; mso-hansi-font-family: 'Times New Roman'; mso-bidi-font-size: 12.0pt; mso-font-kerning: 1.0pt; mso-bidi-font-family: 'Times New Roman'; mso-ansi-language: EN-US; mso-fareast-language: ZH-CN; mso-bidi-language: AR-SA">的方式传递的，这个用</span><span lang="EN-US" style="font-size: 10.5pt; font-family: 'Times New Roman'; mso-bidi-font-size: 12.0pt; mso-font-kerning: 1.0pt; mso-ansi-language: EN-US; mso-fareast-language: ZH-CN; mso-bidi-language: AR-SA; mso-fareast-font-family: 宋体">java</span><span style="font-size: 10.5pt; font-family: 宋体; mso-ascii-font-family: 'Times New Roman'; mso-hansi-font-family: 'Times New Roman'; mso-bidi-font-size: 12.0pt; mso-font-kerning: 1.0pt; mso-bidi-font-family: 'Times New Roman'; mso-ansi-language: EN-US; mso-fareast-language: ZH-CN; mso-bidi-language: AR-SA">实现是很容易的，而用数据库函数就无法直接实现了（据目前自己掌握的技术判断，不知是否有办法实现，望知道者告知），现在变通的一个做法是在数据库里保存信息，然后通过</span><span lang="EN-US" style="font-size: 10.5pt; font-family: 'Times New Roman'; mso-bidi-font-size: 12.0pt; mso-font-kerning: 1.0pt; mso-ansi-language: EN-US; mso-fareast-language: ZH-CN; mso-bidi-language: AR-SA; mso-fareast-font-family: 宋体">quartz</span><span style="font-size: 10.5pt; font-family: 宋体; mso-ascii-font-family: 'Times New Roman'; mso-hansi-font-family: 'Times New Roman'; mso-bidi-font-size: 12.0pt; mso-font-kerning: 1.0pt; mso-bidi-font-family: 'Times New Roman'; mso-ansi-language: EN-US; mso-fareast-language: ZH-CN; mso-bidi-language: AR-SA">定时的扫描该表，有数据则通过</span><span lang="EN-US" style="font-size: 10.5pt; font-family: 'Times New Roman'; mso-bidi-font-size: 12.0pt; mso-font-kerning: 1.0pt; mso-ansi-language: EN-US; mso-fareast-language: ZH-CN; mso-bidi-language: AR-SA; mso-fareast-font-family: 宋体">httpclient</span><span style="font-size: 10.5pt; font-family: 宋体; mso-ascii-font-family: 'Times New Roman'; mso-hansi-font-family: 'Times New Roman'; mso-bidi-font-size: 12.0pt; mso-font-kerning: 1.0pt; mso-bidi-font-family: 'Times New Roman'; mso-ansi-language: EN-US; mso-fareast-language: ZH-CN; mso-bidi-language: AR-SA">给外系统发送信息。还有模型本身只有开始环节，结束环节，虚拟环节和人工执行环节，使得客户提的要按业务路由的功能就无法实现了，因为缺少个判断环节模板，就是</span><span lang="EN-US" style="font-size: 10.5pt; font-family: 'Times New Roman'; mso-bidi-font-size: 12.0pt; mso-font-kerning: 1.0pt; mso-ansi-language: EN-US; mso-fareast-language: ZH-CN; mso-bidi-language: AR-SA; mso-fareast-font-family: 宋体">jbpm</span><span style="font-size: 10.5pt; font-family: 宋体; mso-ascii-font-family: 'Times New Roman'; mso-hansi-font-family: 'Times New Roman'; mso-bidi-font-size: 12.0pt; mso-font-kerning: 1.0pt; mso-bidi-font-family: 'Times New Roman'; mso-ansi-language: EN-US; mso-fareast-language: ZH-CN; mso-bidi-language: AR-SA">中的</span><span lang="EN-US" style="font-size: 10.5pt; font-family: 'Times New Roman'; mso-bidi-font-size: 12.0pt; mso-font-kerning: 1.0pt; mso-ansi-language: EN-US; mso-fareast-language: ZH-CN; mso-bidi-language: AR-SA; mso-fareast-font-family: 宋体">decision</span><span style="font-size: 10.5pt; font-family: 宋体; mso-ascii-font-family: 'Times New Roman'; mso-hansi-font-family: 'Times New Roman'; mso-bidi-font-size: 12.0pt; mso-font-kerning: 1.0pt; mso-bidi-font-family: 'Times New Roman'; mso-ansi-language: EN-US; mso-fareast-language: ZH-CN; mso-bidi-language: AR-SA">环节模板，所以在创建下个环节的时候大部分都是人为的主观去判断到底是走上图中的&#8220;方案审核&#8221;还是&#8220;任务分配&#8221;环节。这使得运用流程整合业务逻辑时并没有完全的实现流程的自动化。<br />
&nbsp;&nbsp;&nbsp; <span style="font-size: 10.5pt; font-family: 宋体; mso-ascii-font-family: 'Times New Roman'; mso-hansi-font-family: 'Times New Roman'; mso-bidi-font-size: 12.0pt; mso-font-kerning: 1.0pt; mso-bidi-font-family: 'Times New Roman'; mso-ansi-language: EN-US; mso-fareast-language: ZH-CN; mso-bidi-language: AR-SA">其实还有很多的缺陷，只是我们都是通过变相的方式给予了实现，可是客户有些需求在该平台上还是无法实现的。鉴于此，就开始寻找开源的工作流引擎，在</span><span lang="EN-US" style="font-size: 10.5pt; font-family: 'Times New Roman'; mso-bidi-font-size: 12.0pt; mso-font-kerning: 1.0pt; mso-ansi-language: EN-US; mso-fareast-language: ZH-CN; mso-bidi-language: AR-SA; mso-fareast-font-family: 宋体">osworkflow</span><span style="font-size: 10.5pt; font-family: 宋体; mso-ascii-font-family: 'Times New Roman'; mso-hansi-font-family: 'Times New Roman'; mso-bidi-font-size: 12.0pt; mso-font-kerning: 1.0pt; mso-bidi-font-family: 'Times New Roman'; mso-ansi-language: EN-US; mso-fareast-language: ZH-CN; mso-bidi-language: AR-SA">、</span><span lang="EN-US" style="font-size: 10.5pt; font-family: 'Times New Roman'; mso-bidi-font-size: 12.0pt; mso-font-kerning: 1.0pt; mso-ansi-language: EN-US; mso-fareast-language: ZH-CN; mso-bidi-language: AR-SA; mso-fareast-font-family: 宋体">jbpm</span><span style="font-size: 10.5pt; font-family: 宋体; mso-ascii-font-family: 'Times New Roman'; mso-hansi-font-family: 'Times New Roman'; mso-bidi-font-size: 12.0pt; mso-font-kerning: 1.0pt; mso-bidi-font-family: 'Times New Roman'; mso-ansi-language: EN-US; mso-fareast-language: ZH-CN; mso-bidi-language: AR-SA">、</span><span lang="EN-US" style="font-size: 10.5pt; font-family: 'Times New Roman'; mso-bidi-font-size: 12.0pt; mso-font-kerning: 1.0pt; mso-ansi-language: EN-US; mso-fareast-language: ZH-CN; mso-bidi-language: AR-SA; mso-fareast-font-family: 宋体">shark</span><span style="font-size: 10.5pt; font-family: 宋体; mso-ascii-font-family: 'Times New Roman'; mso-hansi-font-family: 'Times New Roman'; mso-bidi-font-size: 12.0pt; mso-font-kerning: 1.0pt; mso-bidi-font-family: 'Times New Roman'; mso-ansi-language: EN-US; mso-fareast-language: ZH-CN; mso-bidi-language: AR-SA">等的开源工作流引擎中选择了</span><span lang="EN-US" style="font-size: 10.5pt; font-family: 'Times New Roman'; mso-bidi-font-size: 12.0pt; mso-font-kerning: 1.0pt; mso-ansi-language: EN-US; mso-fareast-language: ZH-CN; mso-bidi-language: AR-SA; mso-fareast-font-family: 宋体">jbpm</span><span style="font-size: 10.5pt; font-family: 宋体; mso-ascii-font-family: 'Times New Roman'; mso-hansi-font-family: 'Times New Roman'; mso-bidi-font-size: 12.0pt; mso-font-kerning: 1.0pt; mso-bidi-font-family: 'Times New Roman'; mso-ansi-language: EN-US; mso-fareast-language: ZH-CN; mso-bidi-language: AR-SA">。为什么会选择</span><span lang="EN-US" style="font-size: 10.5pt; font-family: 'Times New Roman'; mso-bidi-font-size: 12.0pt; mso-font-kerning: 1.0pt; mso-ansi-language: EN-US; mso-fareast-language: ZH-CN; mso-bidi-language: AR-SA; mso-fareast-font-family: 宋体">jbpm</span><span style="font-size: 10.5pt; font-family: 宋体; mso-ascii-font-family: 'Times New Roman'; mso-hansi-font-family: 'Times New Roman'; mso-bidi-font-size: 12.0pt; mso-font-kerning: 1.0pt; mso-bidi-font-family: 'Times New Roman'; mso-ansi-language: EN-US; mso-fareast-language: ZH-CN; mso-bidi-language: AR-SA">呢？原因还是蛮多的，具体列出几条如下几条：<br />
</span>&nbsp;&nbsp;&nbsp; 1、&nbsp;<span style="font-family: 宋体">基于</span>petri net<span style="font-family: 宋体">理论实现的工作流。<br />
</span>&nbsp;&nbsp;&nbsp; 2、&nbsp;<span style="font-family: 宋体">引擎核心以微内核的方式实现（主要逻辑都在</span>graph<span style="font-family: 宋体">包下）。<br />
</span>&nbsp;&nbsp;&nbsp; 3、&nbsp;<span style="font-family: 宋体">基于</span>hibernate<span style="font-family: 宋体">实现持久化。<br />
</span>&nbsp;&nbsp;&nbsp; 4、&nbsp;<span style="font-family: 宋体">很容易的和</span>spring<span style="font-family: 宋体">实现整合，通过</span>spring-modules<span style="font-family: 宋体">实现整合。<br />
</span><span style="font-size: 10.5pt; font-family: 宋体">等。最后附上一个最复杂的流程图（像蜘蛛网更贴切^_^）<br />
</span></span></span></span></span></span></span><img alt="" src="http://www.blogjava.net/images/blogjava_net/fullqin/34626/r_2.gif" border="0" />&nbsp; 
 <img src ="http://www.blogjava.net/fullqin/aggbug/229013.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/fullqin/" target="_blank">囧囧之猪</a> 2008-09-15 18:21 <a href="http://www.blogjava.net/fullqin/archive/2008/09/15/229013.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>【原】在window上使用svn管理版本</title><link>http://www.blogjava.net/fullqin/archive/2008/08/02/219629.html</link><dc:creator>囧囧之猪</dc:creator><author>囧囧之猪</author><pubDate>Sat, 02 Aug 2008 14:16:00 GMT</pubDate><guid>http://www.blogjava.net/fullqin/archive/2008/08/02/219629.html</guid><wfw:comment>http://www.blogjava.net/fullqin/comments/219629.html</wfw:comment><comments>http://www.blogjava.net/fullqin/archive/2008/08/02/219629.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/fullqin/comments/commentRss/219629.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/fullqin/services/trackbacks/219629.html</trackback:ping><description><![CDATA[<p><span style="font-family: 宋体">环境：</span></p>
<p style="text-indent: 21pt"><span style="font-family: 宋体">操作系统：</span>window xp sp2</p>
<p style="text-indent: 21pt">SVN<span style="font-family: 宋体">的版本：</span>1.5<span style="font-family: 宋体">（</span>http://www.collab.net/downloads/subversion/<span style="font-family: 宋体">）</span></p>
<p style="text-indent: 21pt">TortoiseSVN<span style="font-family: 宋体">的版本：</span>1.5<span style="font-family: 宋体">（</span>http://sourceforge.net/projects/tortoisesvn/<span style="font-family: 宋体">）</span></p>
<p>SVN<span style="font-family: 宋体">服务器端安装配置</span></p>
<p style="margin-left: 18pt; text-indent: -18pt; tab-stops: list 18.0pt">1、&nbsp;<span style="font-family: 宋体">安装</span>SVN<span style="font-family: 宋体">服务器端</span></p>
<p style="text-indent: 18pt">A<span style="font-family: 宋体">、到</span>svn<span style="font-family: 宋体">的官方网下载</span>svn<span style="font-family: 宋体">服务器端软件到本地，然后安装，按提示一步一步安装完成。</span>1.5<span style="font-family: 宋体">版本默认的会将</span>svn<span style="font-family: 宋体">添加为</span>window<span style="font-family: 宋体">的服务的选项，勾选上即可随操作系统的启动而启动</span>svn<span style="font-family: 宋体">的服务。而</span>1.5<span style="font-family: 宋体">以前的版本则需要手动添加的</span>window<span style="font-family: 宋体">的服务中，用</span>window<span style="font-family: 宋体">的</span>sc<span style="font-family: 宋体">命令，至于</span>sc<span style="font-family: 宋体">命令如何用读者可以查看</span>sc<span style="font-family: 宋体">的帮助。</span></p>
<p style="text-indent: 18pt">B<span style="font-family: 宋体">、安装完后打开</span>window<span style="font-family: 宋体">的服务管理器，将</span>svn<span style="font-family: 宋体">的服务启动，全名为</span>Svnversion Server<span style="font-family: 宋体">。打开命令行运行命令</span>svnadmin --version<span style="font-family: 宋体">，可以看到</span>svn<span style="font-family: 宋体">安装的版本信息，至此</span>svn<span style="font-family: 宋体">的安装完成。</span></p>
<p style="text-indent: 18pt">C<span style="font-family: 宋体">、安装</span>svn<span style="font-family: 宋体">客户端端软件</span>TortoiseSVN<span style="font-family: 宋体">，按步骤安装下来即可。</span></p>
<p>2<span style="font-family: 宋体">、</span>SVN<span style="font-family: 宋体">服务器端的配置</span></p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <span style="font-family: 宋体">第一点只介绍了</span>svn<span style="font-family: 宋体">的安装，要让其能够使用，我们还需要些配置，像版本库的建立，用户的访问权限等。</span></p>
<p style="text-indent: 21pt">A<span style="font-family: 宋体">、创建版本库。</span></p>
<p style="text-indent: 21pt"><span style="font-family: 宋体">打开命令行执行</span>svnadmin create path<span style="font-family: 宋体">，其中</span>path<span style="font-family: 宋体">表示你要建立的版本库的存放路径,此路径也是svn在window的服务上注册是指向的路径，笔者的路径为</span>D:\svn_repository<span style="font-family: 宋体">，即</span>svnadmin create D:\svn_repository<span style="font-family: 宋体">。运行该命令后，可以发现在</span>D:\svn_repository<span style="font-family: 宋体">的目录下，创建了些文件和文件夹，至此创建版本库成功。</span></p>
<p style="text-indent: 21pt">B<span style="font-family: 宋体">、配置用户的访问权限。</span></p>
<p style="text-indent: 21pt"><span style="font-family: 宋体">在刚才的目录下有个文件夹</span>conf<span style="font-family: 宋体">，</span>svn<span style="font-family: 宋体">的配置文件就在此目录中。打开该文件夹下的</span>svnserver.conf<span style="font-family: 宋体">文件，我们可以看到</span>svn<span style="font-family: 宋体">的配置信息的一些属性，这里行前凡是有</span>#<span style="font-family: 宋体">的都表示被注释掉了，你可以把</span>#<span style="font-family: 宋体">去掉让该行的属性生效，或者自己在最后添加新的行来生效</span>svn<span style="font-family: 宋体">的属性。</span></p>
<p><span style="font-family: 宋体">在这我们关心的属性说明如下：</span></p>
<p>anon-access = read&nbsp;<span style="font-family: 宋体">表示匿名的用户可以什么样的方式访问版本库，有</span>none<span style="font-family: 宋体">、</span>read<span style="font-family: 宋体">、</span>write<span style="font-family: 宋体">三个值可选，文件中为</span>read<span style="font-family: 宋体">说明匿名用户可以只读的方式访问版本库。</span></p>
<p>auth-access = write&nbsp;<span style="font-family: 宋体">表示验证通过的用户具有什么权限，有</span>none<span style="font-family: 宋体">、</span>read<span style="font-family: 宋体">、</span>write<span style="font-family: 宋体">三个值可选，文件中为</span>write<span style="font-family: 宋体">表示可写，当然也可读了。</span></p>
<p>password-db = passwd&nbsp;<span style="font-family: 宋体">表示用户的密码存放的地方。</span></p>
<p>authz-db = authz&nbsp;<span style="font-family: 宋体">表示版本库中访问路径的规则，即谁只能访问哪个目录下的文件，其他目录下的文件无法访问。</span></p>
<p><span style="font-family: 宋体">现在我们将</span>auth-access<span style="font-family: 宋体">、</span>password-db<span style="font-family: 宋体">、</span>authz-db<span style="font-family: 宋体">三个属性的前面的</span>#<span style="font-family: 宋体">去掉，使其生效，注意三个属性前不能有空格。</span></p>
<p><span style="font-family: 宋体">然后我们编辑</span>passwd<span style="font-family: 宋体">和</span>authz<span style="font-family: 宋体">这两个文件的信息。</span></p>
<p style="text-indent: 21pt">a<span style="font-family: 宋体">、在</span>passwd<span style="font-family: 宋体">文件中的</span>[users]<span style="font-family: 宋体">下添加能访问版本库的用户名和密码，如该文件中的事例。我们添加</span>admin = admin</p>
<p style="text-indent: 21.75pt">b<span style="font-family: 宋体">、在</span>authz<span style="font-family: 宋体">文件中，</span>[groups]<span style="font-family: 宋体">下可以配置组信息，即将几个人加入到一个组中。</span>[/foo/bar]<span style="font-family: 宋体">下添加人员的规则表示谁可访问</span>/foo/bar<span style="font-family: 宋体">路径下的信息。我们在</span>[/foo/bar]<span style="font-family: 宋体">下添加</span></p>
<p>[/]</p>
<p>admin = rw</p>
<p><span style="font-family: 宋体">至此，我们配置了</span>admin<span style="font-family: 宋体">的账号，该账号具有根目录下的所有文件的读写操作权限。</span></p>
<p>3<span style="font-family: 宋体">、创建我们的项目</span></p>
<p style="text-indent: 21.75pt"><span style="font-family: 宋体">在</span>D:"test<span style="font-family: 宋体">下新建</span>project<span style="font-family: 宋体">文件夹，在</span>project<span style="font-family: 宋体">下新建</span>trunk<span style="font-family: 宋体">，</span>tags<span style="font-family: 宋体">，</span>branches<span style="font-family: 宋体">三个文件夹，打开命令行，将目录转到</span>D:\test<span style="font-family: 宋体">下，运行</span>svn import &#8211;m addproject --username admin --password admin --config-dir /project svn://localhost<span style="font-family: 宋体">回车显示如下：</span></p>
<p>Adding project</p>
<p>Adding project/trunk</p>
<p>Adding project/branches</p>
<p>Adding project/tags</p>
<p>Committed revision 1.</p>
<p><span style="font-family: 宋体">表示我们的项目</span>project<span style="font-family: 宋体">创建成功。</span></p>
<p><span style="font-family: 宋体">这里说明下</span>trunk<span style="font-family: 宋体">、</span>tags<span style="font-family: 宋体">、</span>branches<span style="font-family: 宋体">三个文件夹的作用：</span></p>
<p>trunk<span style="font-family: 宋体">：表示开发时版本存放的目录，即在开发阶段的代码都提交到该目录上。</span></p>
<p>branches<span style="font-family: 宋体">：表示发布的版本存放的目录，即项目上线时发布的稳定版本存放在该目录中。</span></p>
<p>tags<span style="font-family: 宋体">：表示标签存放的目录。</span></p>
<p><span style="font-family: 宋体">在这需要说明下分三个目录的原因，如果项目分为一期、二期、三期等，那么一期上线时的稳定版本就应该在一期完成时将代码</span>copy<span style="font-family: 宋体">到</span>branches<span style="font-family: 宋体">上，这样二期开发的代码就对一期的代码没有影响，如新增的模块就不会部署到生产环境上。而</span>branches<span style="font-family: 宋体">上的稳定的版本就是发布到生产环境上的代码，如果用户使用的过程中发现有</span>bug<span style="font-family: 宋体">，则只要在</span>branches<span style="font-family: 宋体">上修改该</span>bug<span style="font-family: 宋体">，修改完</span>bug<span style="font-family: 宋体">后再编译</span>branches<span style="font-family: 宋体">上最新的代码发布到生产环境即可。</span>tags<span style="font-family: 宋体">的作用是将在</span>branches<span style="font-family: 宋体">上修改的</span>bug<span style="font-family: 宋体">的代码合并到</span>trank<span style="font-family: 宋体">上时创建个版本标识，以后</span>branches<span style="font-family: 宋体">上修改的</span>bug<span style="font-family: 宋体">代码再合并到</span>trunk<span style="font-family: 宋体">上时就从</span>tags<span style="font-family: 宋体">的</span>version<span style="font-family: 宋体">到</span>branches<span style="font-family: 宋体">最新的</span>version<span style="font-family: 宋体">合并到</span>trunk<span style="font-family: 宋体">，以保证前期修改的</span>bug<span style="font-family: 宋体">代码不会在合并。</span></p>
<p><span style="font-family: 宋体">至此我们就可以使用</span>svn<span style="font-family: 宋体">来管理我们的代码了。</span></p>
<img src ="http://www.blogjava.net/fullqin/aggbug/219629.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/fullqin/" target="_blank">囧囧之猪</a> 2008-08-02 22:16 <a href="http://www.blogjava.net/fullqin/archive/2008/08/02/219629.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item></channel></rss>