专注于互联网--专注于架构

最新标签
网站地图
文章索引
Rss订阅

首页 »Java教程 » 如何创建搜索引擎:使用Spring来创建一个简单的工作流引擎 »正文

如何创建搜索引擎:使用Spring来创建一个简单的工作流引擎

来源: 发布时间:星期一, 2009年3月16日 浏览:0次 评论:0
摘要  spring是支持控制反转编程机制个相对新框架本文把spring作为简单工作流引擎将它用在了更加通用地方在对工作流简单介绍的后将要介绍在基本工作流场景中基于Spring工作流API使用   许多J2EE应用要求在个和主机分离上下文中执行处理过程在许多情况下这些后台进程执行多个任务些任务依赖于以前任务状态由于这些处理任务的间存在相互依赖关系使用套基于过程思路方法常常不能满足要求开发人员能够利用Spring来容易地将后台进程分离成活动集合Spring容器连接这些活动并将它们组织成简单工作流   在本文中简单工作流被定义成不需要用户干预定顺序执行任意活动集合然而我们并不建议将这种方式代替存在工作流框架些场景中需要更多用户交互例如基于用户输入而进行转向连接或传输这时比较好思路方法是配用个单独开源或者商业工作流引擎个开源项目已经成功地将更复杂工作流设计集成到spring中   如果你手上工作流任务是简单那么和功能完备独立工作流框架相比简单工作流策略就会变得有意义特别地如果已经使用了spring这种快速实现可以保证时间不会变得更加漫长此外考虑到spring轻量级控制反转容器特点spring在资源负载上减少了资源负载   这篇文章简短地从编程主题角度介绍工作流通过使用工作流概念spring被用来作为驱动工作流引擎框架然后讨论了生产部署选项现在让我们从工作流设计模式和相关背景信息来介绍简单工作流思想吧简单工作流  工作流模型是个早在70年代就有人开始研究主题许多开发者都试图创建工作流模型规范标准W.H.M. van der Aalst等人写了工作流模型白皮书(2003年7月)它成功地提炼出组设计模式这些设计模式准确地将大多数通用工作流场景建模当中最普通工作流模式是顺序模式 (Sequence pattern)顺序工作流模式满足了简单工作流设计原则并且由组顺序执行活动组成   UML(统建模语言)活动图通常被用来作为个机制对工作流建模图1显示了个基本使用标准UML活动图对顺序工作流过程建模过程 JAVA中文站社区门户 zP0M'[7F

图 1顺序工作流模式

)n s mzLo:nn+A  顺序工作流是个在J2EE中流行标准工作流模式J2EE应用在后台线程中通常需要些顺序发生事件或者异步事件图2中活动图描述了个简单工作流用来通知感兴趣旅行者他们感兴趣机票价格已经下降事件 JAVA中文站社区门户3lose'iTnN

图 2.机票价格下降简单工作流

hlgW:VU3@@  图1中航线工作流负责创建和发送动态email通知过程中步表示了个活动(activity)在工作流处于活动的前些额外事件必须发生在这个例子中事件是飞行路线费率减少   让我们来简要下航线工作流业务逻辑如果第个活动找不到对费率减少通知感兴趣用户那么整个工作流就被取消如果发现了感兴趣用户那么接下来活动继续执行随后个XSL(扩展样式表)转换生成消息内容的后记录审计信息 (audit information)最后工作流试图通过SMTP服务器发送这个消息如果这个任务没有地完成便在日志中记录成功信息进程结束但是如果在和SMTP服务器通讯时发生了个特别处理例程将要管理这些处理代码将会试着去重新发送消息   考虑这个航线例子个明显问题是:你如何样有效地将顺序处理过程分解为单独活动?这个问题被spring巧妙处理了下面让我们快速地讨论spring反转控制框架控制反转  Spring通过使用spring容器来负责控制对象的间依赖关系使得我们不再对对象的间依赖负责 这种依赖关系实现就是大家所知道控制反转(IoC)或依赖注射参见Martin Fowler's "Inversion of Control Containers and the Dependency Injection Pattern"(martinfowler.com, 2004年2月)得到有关控制反转和依赖注射更加深入讨论通过管理对象的间依赖关系spring就不需要那些只是为了使类能够相互协作而将对象粘合代码 作为spring beans工作流组件  在进步讨论的前现在是简要介绍spring中主要概念恰当时候接口ApplicationContext是从接口BeanFactory继承它被用来作为在spring容器内实际控制实体和容器   ApplicationContext负责对组作为spring beans组bean配置和生命期管理我们通过装配在个基于XML配置文件中spring beans来配置ApplicationContext这个配置文件介绍说明了spring beans互相协作本质特点这样用spring术语来说和其他spring beans交互spring beans就被叫着协作者(collaborators)缺省情况下spring beans是作为单例存在于ApplicationContext中但是单例属性能够被设置为false从而有效地改变他们在spring中原型模式时行为   回到我们例子在飞机票价下降时候个SMTP发送例程抽象就被装配在工作流过程例子中最后活动(例子代码可以在 Resources中得到)由于是第5个活动我们命名它为activity5要发送消息activity5就要求个代理协作者和个错位处理句柄 =org.iocworkflow.test.sequence.ratedrop.SendMessage id=activity5>



  将工作流组件实施成spring beans产生了两个令人喜悦结果就是容易进行单元测试和很大程度上可重用能力IoC容器特点明显地提供了有效单元测试使用像spring这样Ioc容器在测试期间协作者的间依赖能够容易用假替代者替代在这个航线例子中能够容易地从唯测试ApplicationContext中检索出像activity5活动这样spring bean个假SMTP代理SMTP服务器就有可能单独地测试activity5   第 2个意外结果可重用能力是通过像XSL转换这样工作流活动实现个被抽象成工作流活动XSL转换现在能够被任何处理XSL转换工作流所重用装配工作流  在提供API中(从Resources下载)spring控制了些操作者以种工作流方式交互关键接口如下:   Activity: 封装了工作流中个单步业务逻辑   ProcessContext:在工作流活动的间传递具有ProcessContext类型对象实现了这个接口对象负责维护对象在工作流转换中从个活动转换到另个活动状态   ErrorHandler: 提供处理回调思路方法   Processor: 描述个作为主工作流线程执行者bean   下面从例子源码中摘录代码是将航线例子装配为简单工作流过程spring bean配置 =org.iocworkflow.SequenceProcessor id=rateDropProcessor>



org.iocworkflow.test.sequence.ratedrop.RateDropContext

  SequenceProcessor类是个对顺序模式建模具体子类有5个活动被连接到工作流处理器工作流处理器将顺序执行这5个活动   和大多数过程式后台进程相比工作流解决方案真正突出了高度强壮处理处理句柄可以单独地处理每个活动这种类型句柄在单活动级别提供了细致处理如果没有单独处理单个活动处理句柄那么全局工作流处理器处理句柄将会处理出现问题例如如果在工作流处理过程中任意时刻个没有被处理出现了那么它将会向外传播被使用defaultErrorHandler属性装配ErrorHandler Bean处理   更复杂工作流框架将工作流转换的间状态持久化存储到数据库中在这篇文章中我们仅仅对状态转换是自动完成工作流感兴趣状态信息仅仅在实际工作流运行时在ProcessContext中得到在ProcessContext中你仅仅能看到ProcessContext接口两个思路方法: public erface ProcessContext extends Serializable { public boolean stopProcess; public void SeedData(Object seedObject); }   用于航线例子工作流具体ProcessContext类是RateDropContext类RateDropContext类封装了用于执行航线费率降低工作流必须数据   到现在为止经由缺省ApplicationContext作用所有bean例子都已经成了单例但是对于每个航线工作流我们必须创建个新RateDropContext类例子为了处理这种需求需要配置SequenceProcessor采用全限定类名作为processContextClass属性对于每个工作流执行SequenceProcessor使用指定类名从spring检索ProcessorContext类个新例子为了使这种机制能够起作用非单件spring bean或者类型org.iocworkflow.test.sequence.simple.SimpleContext原型必须存在于ApplicationContext中播种工作流  既然我们知道怎样使用spring来组装个简单工作流就让我们集中精力使用种子数据(seed data)举例工作流过程要明白怎样开始工作流看在实际接口Processor上表现思路方法: public erface Processor { public boolean supports(Activity activity); public void doActivities; public void doActivities(Object seedData); public void Activities(List activities); public void DefaultErrorHandler(ErrorHandler defaultErrorHandler); }   大多数情况下工作流需要化激活才能开始开始个处理过程有两个选项:doActivities(ObjectseedData)思路方法或者无参数doActivities()下面代码列表是包含在样例代码中为SequenceProcessor而实现doActivities(): public void doActivities(Object seedData) { //Retrieve injected by Spring List activities = getActivities; //Retrieve a instance of the Workflow ProcessContext ProcessContext context = createContext; (seedData != null) context.SeedData(seedData); //Execute each activity in sequential order for (Iterator it = activities.iterator; it.hasNext;) { Activity activity = (Activity) it.next; try { context = activity.execute(context); } catch (Throwable th) { //Determine an error handler is available at the activity level ErrorHandler errorHandler = activity.getErrorHandler; (errorHandler null) { getDefaultErrorHandler.handleError(context, th); ; } { //Handle error using default handler errorHandler.handleError(context, th); } } //Ensure it's ok to continue the process (processShouldStop(context, activity)) ; } }   在这个航空费用减少例子中工作流过程种子数据包括航线信息和费率减少信息使用容易测试航线工作流例子通过doActivities(Object seedData)思路方法发出种子数据并激活个单工作流过程是简单: BaseProcessor processor = (BaseProcessor)context.getBean("rateDropProcessor"); processor.doActivities(createSeedData);   这些代码是从包含在这篇文章中测试例子中摘录rateDropProcessor Bean是从ApplicationContext中检索来rateDropProcessor实际上是装配成SequenceProcessor例子来处理顺序执行createSeedData()思路方法例子化个对象这个对象封装了化航线工作流所需要所有种子数据 Processor选项  虽然包含在源代码中Processor具体子类仅仅是SequenceProcessor但是许多Processor接口实现也是可以想象得到可以开发其他工作流处理过程子类来控制区别工作流类型例如种像并行切割模式那样有着变化执行路径工作流对于简单工作流来说活动顺序是预先决定了所以SequenceProcessor是好选择尽管没有被包括进来对于使用基于spring简单工作流实现来说排他选择模式是另个好选择当使用排他选择模式时在每个活动执行的后Processor具体类就会讯问ProcessorContext接下来将要执行哪个活动   注:有关并行切割排他选择和其他工作流模式更多信息请参看W.M.P. van der Aalst等人写工作流模式 启动工作流  考虑到工作流过程常常需要异步执行特点使用分离执行线程来启动工作流就变得有意义了对于工作流异步启动而言有好几个选项;我们主要集中在其中两个:积极地检测(actively polling)个队列来启动工作流或者使用通过ESB(enterprise service bus, 企业服务总线)事件驱动方式来启动工作流而Mule就是ESB个开源项目   图3和图4描绘了两种启动策略图3中积极检测在工作流中第个活动经常检查资源情形下发生比如数据源或POP3邮件帐户如果图3中积极检测发现有任务等待处理那么启动就会开始

"m Bbz3k:zl kX 图 3. 通过积极检测来启动工作流JAVA中文站社区门户kp.B%g'@|o._

  另方面图4表示了使用JMS(JAVA消息服务)J2EE应用把事件放到队列上情形个通过ESB配置事件监听器收到图4中事件并且开始工作流这样启动工作流过程 JAVA中文站社区门户 K6n v#p.q@g

图 4. 通过ESB事件来启动工作流

n|,w6Vn9s_/P-Z  使用所提供样例代码让我们更详细看看主动选择启动方式和事件驱动启动方式积极检测  积极检测是种花费较少启动工作流过程方案SequenceProcessor足够灵活以使得能够通过平滑选择工作来进行启动过程尽管并不令人满意在没有时间进行事件驱动子系统配置和部署许多情景中积极检测是明智选择   使用SpringScheduledTimerTask检测模式就能够容易地装配缺点就是必须创建额外活动来进行检测这个检测活动必须被设计来讯问某些实体如数据库表pop邮件帐户或者Web服务然后决定新工作是否等待参和到工作流中   在所提供例子中PollingTestCase类例子化个基于检测工作流过程使用个有着积极检测处理过程和事件驱动启动过程区别的处在于spring支持doActivities()思路方法无参数版本相反地在事件驱动启动中启动处理过程实体通过doActivities(Object seedData)思路方法提供了种子数据来启动工作流检测思路方法个缺点是:资源不定能够被重复地使用依赖于应用环境这种资源消耗是不可接受   下面代码例子演示了使用积极检测来控制工作流启动个活动: public PollForWork implements Activity { public ProcessContext execute(ProcessContext context) throws Exception { //First check work needs to be done boolean workIsReady = lookIntoDatabaseForWork; (workIsReady) { //The Polling Action must also load any seed data ((MyContext) context).SeedData(createSeedData); } { //Nothing to do, terminate the workflow process for this iteration ((MyContext) context).StopEntireProcess(true); } context; } }   此外包含在例子代码单元测试中PollRates类提供了个主动选举启动可以运行例子PollRates模拟了对于航线费率下降重复检查 通过ESB事件驱动启动工作流  理想地个包含了适当种子数据线程能够异步地启动工作流这种情况个例子是收到从JAVA消息服务队列消息个监听JMS队列或者主题客户会收到通知这个通知告知处理应该在onMessage()思路方法中开始工作流然后通过使用Spring和doActivities(Object seedData)思路方法就能够获得工作流处理器Bean   使用ESB实际用于发送启动事件机制能够恰当地从工作流处理器中分离出来开源项目Mule ESB有紧凑地和Spring相集成好处任意传送机制比如JMSJVM或者POP3邮箱都能够发起事件传播 工作流连续运行  工作流引擎后台进程应该能够没有干扰地连续运行对于正在运行基于spring工作流单进程来说好有几个选项个有着()思路方法简单Java类就足够演示和这篇文章伴随着单元测试中例子了个更加可靠用于部署机制是嵌入工作流到某种形式J2EE组件中Spring很好地支持和J2EE兼容web应用归档或者war文件集成基于Java管理附件(JMX)服务归档和JBoss应用服务器(更多信息参见JBoss homepage)支持sar文件是更加合适可部署组件这种更合适可部署组件也能够被用来将部署归档在JBoss 4.0中sar文件已经被大家所知道deployer格式所取代了 例子代码  打包成zip格式例程代码最好是用Apache Maven来使用它们你能够在主源代码目录src/java找到APIsrc/java目录中有 3个单元测试包括:SimpleSequenceTestCaseRateDropTestCase和PoolingTestCase要运行所有这些测试在命令行shell中键入maven test然后在编译和运行的前Maven将会下载所有必需jar文件实际XSL转换将会发生在两个测试中它们结果被管道输出到控制台键入maven test:ui来拉出图形化测试运行器然后选择你想要运行测试并且观察控制台结果 结论  在这篇文章中你已经通过设计模式看到了工作流过程种类在这些模式中我们主要集中介绍了顺序模式通过使用接口我们来对基本工作流组件建模通过装配多个接口实现到Spring实现个顺序工作流最后还讨论了启动和部署工作流区别选项   这里所提出简单工作流技术肯定不是最终和革命性但是使用Spring来实现像工作流这样通用任务是个通过使用IoC容器而获得效率举例由于减少了粘合性代码需要Spring在保持面向对象约束同时减少面向对象操作麻烦程度

TAG: Spring spring 工作流 引擎
0

相关文章

读者评论

发表评论

  • 昵称:
  • 内容: