成人免费xxxxx在线视频软件_久久精品久久久_亚洲国产精品久久久_天天色天天色_亚洲人成一区_欧美一级欧美三级在线观看

探秘WF4 Beta2中工作流對象模型

開發 后端
今天我們要討論的是WF4 Beta2中的工作流對象模型,希望本文能對大家了解WF4 Beta2的一些特性有所幫助。

本文將討論WF4 Beta2中的工作流對象模型,在.NET 4.0中工作流是變化比較大的一部分,希望那個通過本文能讓大家對WF4 Beta2有一個全新的認識。

隨著Visual Studio2010 BETA2的發布,大家對.NET 4.0技術的研究熱情隨之高漲。在整個.NET 4.0所引入的新技術中,工作流可謂是變化最大的部分。WF4與WF3幾乎可以看成是兩個完全不同的產品。

對于WF3的編程模型,已有相關的技術書籍介紹了,在網上也可以搜到有關的資源。但對于WF4,卻幾乎找不到任何深入介紹其對象模型的文章。

我以Reflector作為工具,反匯編了WF4的源代碼,通過仔細閱讀,粗步理出了一個頭緒,在本文中進行介紹,期望能起到一個拋磚引玉的作用,幫助大家深入地把握WF4的技術內幕。

呵呵,第一次在博客園發文,希望大家多多鼓勵。

1 Acitvity的繼承樹

在WF4中,Activity類是最頂層的基類。任何一個工作流都由至少一個Activtiy構成。以下是WF4中Activity的繼承樹:

WF4中Activity的繼承樹

 

在真實的工作流中,各個Activity可以相互嵌套,形成一個樹型結構,最底層的葉子通常就是上圖中最底層類(如CodeActivity)的實例。

最頂層的Activity類提供了一個可以供子類重寫的InternalExecute()方法:

  1. internal virtual void InternalExecute(ActivityInstance instance,   
  2. ActivityExecutor executor, BookmarkManager bookmarkManager); 

子類可以重寫此方法,在此方法中實現各種功能,這個方法在WF4內部非常重要,許多東西都與它相關。

為了方便地供開發者自定義業務處理邏輯,諸如CodeActivity之類最底層的類,另定義了一個抽象的Execute()方法:

  1. protected abstract void Execute(CodeActivityContext context); 

當開發者自定義Activity時,就可以直接地重寫此方法。

簡言之,工作流的運行就體現為Activity對象樹中葉子節點Execute方法(或類似的方法,比如DynamicActivity是InternalExecute方法,AsyncCodeActivity是BeginExecute和EndExecute方法)的執行。

2.WF4中工作流的執行原理

首先要明確,在WF4中,如果使用WorkflowInvoker類來啟動工作流時:

  1. WorkflowInvoker.Invoke(new Workflow1()); 

工作流Workflow1將在調用者的線程中執行。這種情況下,工作流的執行類似于方法調用,是最簡單的執行模式。

然而,如果使用WorkflowApplication啟動工作流,工作流實例將在調用者線程之外的另一個線程中運行:

  1. WorkflowApplication wpp = new WorkflowApplication(new Workflow1());  
  2. wpp.Run(); 

而且,這個“另外的工作線程”是線程池中的線程。

不管是由哪個線程負責執行工作流,有一個原則是很重要的:

單個工作流實例是單線程執行的,哪怕諸如Parallel Activity給你一個多分支“并行”運行的假象。

事實上,Parallel Activity采用在單線程中“輪換執行”各分支。當一個分支進入空閑“Idle”時,工作流調度器調度下一分支投入運行。所果所有分支都不包括使本分支進入Idle狀態的Activtity(比如有一個Delay Activity或創建了書簽),則Parallel Activity按從左到右的順序執行各分支。

那么,構成工作流的各個Activity實例是如何執行的?

WF運行時在內部為每個工作流維護了一個工作項隊列。然后,創建一個Scheduler類的實例來負責從此工作項隊列中取出和追加工作項,并執行之。

這里要說說這個工作項隊列,在Scheduler類的代碼中可以找到它的聲明:

  1. private Quack<WorkItem> workItemQueue; 

這里有一個奇怪的Quack<T>泛型類,我仔細看了一下,其實它就是一個泛型隊列,但它有一點特殊之處:

Quack<T>泛型類在內部使用一個數組來保存數據:

  1. private T[] items; 

初始時,為隊列分配可容納4個T類型對象的內存空間,當不斷增加對象而需要擴充空間時,就分配一個“當前所占內存空間*2”的新數組,再將老數組中的內容復制到新數組中。

很明顯,在兩個數組中復制元素會花費系統資源,我不知道為何WF4的設計者這樣設計,估計是他們有其他的考慮。

隊列中的WorkItem對象很有趣,它代表一個將被執行的Activity實例,這里暫時放下,一會兒還會介紹它。

Scheduler對象的工作可以簡述如下:

它從隊列中取出一個WorkItem對象,然后將其委托給線程池中的線程(如果工作流由WorkApplication以異步方式啟動執行)或調用者線程(如果工作流由WorkflowInvoker以同步方式啟動執行)執行。這些線程將負責調用WorkItem所封裝的Activity實例的Execute()方法(或類似的方法,如前所述)。

3 深入分析Activity執行的流程
 一個Activity實例到底是如何執行的?一切得從WorkItem類開始。

WorkItem是一個抽象基類,提供了幾個抽象方法,其中最重要的就是Execute()方法:

  1. internal abstract class WorkItem  
  2. {  
  3. //……  
  4. private ActivityInstance activityInstance;  
  5. public abstract bool Execute(ActivityExecutor executor,   
  6. BookmarkManager bookmarkManager);  

上述聲明中還有兩個很重要的類ActivityInstance和ActivityExecutor。

ActivityInstance代表著正在運行的一個Activity實例,它包容一堆的internal方法可以完成Activity的執行(Execute)取消(Cancel)和放棄(Abort)的功能。 ActivityExecutor則負責調用ActivityInstance中的這些方法。

WorkItem有一堆的子類,這些子類又派生出“孫”類。比如,其中的一個分支如下:

分支如下

 

不管有幾個子孫,后代一般都重寫了WorkItem所定義的Execute()抽象方法。

我們以ExecuteRootWorkItem類為例,顧名思義,這應該是與工作流中最頂層的Activity相對應的WorkItem。它的Execute()方法如下所示:

  1. public override bool Execute(ActivityExecutor executor, BookmarkManager bookmarkManager)  
  2. {  
  3. return base.ExecuteBody(executor, bookmarkManager, this.resultLocation);  

它將調用基類ExecuteActivityWorkItem的ExecuteBody()方法,此方法的關鍵代碼如下:

  1. protected bool ExecuteBody(ActivityExecutor executor, BookmarkManager bookmarkManager, Location resultLocation)  
  2. {  
  3. //……  
  4. base.ActivityInstance.Execute(executor, bookmarkManager);  
  5. //……  
  6. }  

可以看到,它直接跳去執行最頂層基類WorkItem所定義的ActivityInstance對象的Execute()方法。此方法的代碼如下:

  1. internal void Execute(ActivityExecutor executor, BookmarkManager bookmarkManager)  
  2. {  
  3. //……  
  4. this.Activity.InternalExecute(this, executor, bookmarkManager);  

注意ActivityInstance實際上封裝了一個Activity對象:

  1. public sealed class ActivityInstance : ActivityInstanceMap.IActivityReference  
  2. {  
  3. public Activity Activity { getinternal set; }  
  4. //……  

所以,ActivityInstance對象的Execute()方法實際上執行的是Activity對象的InternalExecute()方法。再追蹤下去:

  1. internal virtual void InternalExecute(ActivityInstance instance, ActivityExecutor executor, BookmarkManager bookmarkManager)  
  2. {  
  3. //……  
  4. executor.ScheduleActivity(this.runtimeImplementation, instance, nullnullnull);  

注意:上述代碼是Acitivity對InternalExecute()默認的實現方式,它的子類(比如CodeActivity)通常會重寫它。

可以看到,在ActivityInstance對象的Execute()方法中,執行流程轉給了從前面一路傳送過來的ActivityExecutor對象,由此對象的ScheduleActivity方法負責將Activity插入到工作項隊列中。

ActivityExecutor.ScheduleActivity方法又進行了一個“倒手”,調用自己的ScheduleBody()方法:

  1. private ActivityInstance ScheduleActivity(……)  
  2. {  
  3. //……  
  4. this.ScheduleBody(scheduledInstance, requiresSymbolResolution, argumentValueOverrides, resultLocation);  
  5. }  

在ScheduleBody()方法中,“佛祖”終于現出真身,我們看到了Scheduler的身影:

  1. internal void ScheduleBody(ActivityInstance activityInstance, bool requiresSymbolResolution, IDictionary<stringobject> argumentValueOverrides, Location resultLocation)  
  2. {  
  3. if (resultLocation == null)  
  4. {  
  5. //……  
  6. this.scheduler.PushWork(new ExecuteExpressionWorkItem(activityInstance, requiresSymbolResolution, argumentValueOverrides, resultLocation));  
  7. //……  

在上述代碼中,Scheduler對象將activityInstance轉換為了一個ExecuteExpressionWorkItem,然后將其插入到工作項隊列中等待執行。

現在我們看到,默認情況下,對ExecuteRootWorkItem的執行將導致一個新的ExecuteExpressionWorkItem工作項被插入到工作項隊列中。

4.工作項隊列中的工作項是如何調度執行的?

Scheduler類負責工作項的調度執行。

在Scheduler類的構造函數中,掛接了一個回調函數OnScheduledWork:

  1. static Scheduler()  
  2. {  
  3. //……  
  4. onScheduledWorkCallback = Fx.ThunkCallback(new SendOrPostCallback(Scheduler.OnScheduledWork));  

在OnScheduledWork()函數中,揭露出了任務項調度是如何進行的秘密:

  1. private static void OnScheduledWork(object state)  
  2. {  
  3. //取出隊列中的第一個工作項  
  4. WorkItem firstWorkItem = scheduler.firstWorkItem;  
  5. if ((scheduler.workItemQueue != null) && (scheduler.workItemQueue.Count > 0))  
  6. {  
  7. scheduler.firstWorkItem = scheduler.workItemQueue.Dequeue();  
  8. }  
  9. else 
  10. {  
  11. scheduler.firstWorkItem = null;  
  12. }  
  13. //執行這一工作項  
  14. continueAction = scheduler.callbacks.ExecuteWorkItem(firstWorkItem);  
  15. //……  

下面是ExecuteWorkItem()方法的代碼,可以看到,最后調度器還是委托activityExecutor來執行Activity的:

  1. public Scheduler.RequestedAction ExecuteWorkItem(WorkItem workItem)  
  2. {  
  3. Scheduler.RequestedAction objA = this.activityExecutor.OnExecuteWorkItem(workItem);  
  4. //……  
  5. }  
  6. ActivityExecutor的OnExecuteWorkItem()方法有很多代碼,其中關鍵的就是以下這幾句:  
  7. internal Scheduler.RequestedAction OnExecuteWorkItem(WorkItem workItem)  
  8. {  
  9. //……  
  10. propertyManagerOwner.PropertyManager.SetupWorkflowThread();  
  11. if ((abortException == null) && !workItem.Execute(thisthis.bookmarkManager))  
  12. {  
  13. return Scheduler.YieldSilently;  
  14. }  
  15. }  
  16. //……  

我們終于發現了調用工作項的Execute()方法的語句。

有的朋友可能會疑惑,我們的探索之旅從WorkItem.Execute()方法開始,轉了一圈怎么又回到了WorkItem.Execute()方法?這樣一來,調用工作項的WorkItem.Execute()方法將導致一個工作項被加入到隊列中,然后當此工作項被執行時,它又將一個工作項加入到隊列中,這會不會引發無限遞歸?

事實上這正是我們想要的效果。因為一個工作流實例實際上就是一個層層嵌套的遞歸的結構,這種設計使得執行其頂層Activity對象的Execute()方法時,會將其子Activity所對應的WorkItem加入到隊列中加以遞歸執行。

很明顯,對于那些不包容子Activity的Activity,我們應該“打斷”這種遞歸執行的過程。WF4是怎么做到的?

以一個實例來說明更好。 請看以下自定義的Activity:

  1. public sealed class Prompt : CodeActivity  
  2. {  
  3. public InArgument<string> Text { getset; }  
  4. protected override void Execute(CodeActivityContext context)  
  5. {  
  6. Console.Write(Text.Get(context));  
  7. }  

注意上述Activity重寫了基類CodeActivity的Execute()方法,此方法一執行完畢就會返回。

前面說過,對工作項隊列中WorkItem.Execute()方法的調用,最終將轉換為對ActivityInstance對象的Execute()方法的調用。而ActivityInstance又包容了最終的Activity對象實例,并將調用轉給這一最終對象的InternalExecute()方法,為方便起見,重貼此方法代碼如下:

  1. internal void Execute(ActivityExecutor executor, BookmarkManager bookmarkManager)  
  2. {  
  3. //……  
  4. this.Activity.InternalExecute(this, executor, bookmarkManager);  
  5. }  

在我們的自定義Activity中,沒有重寫CodeActivity的InternalExecute()方法(事實上也不可能,因為此方法是Sealed的),所以,被調用的實際上是基類CodeActivity的InternalExecute()方法。以下是CodeActivity的InternalExecute()方法代碼:

  1. internal sealed override void InternalExecute(ActivityInstance instance, ActivityExecutor executor, BookmarkManager bookmarkManager)  
  2. {  
  3. //……  
  4. this.Execute(context);  
  5. //……  

非常清楚,它應用了多態特性,調用子類重寫的Execute()方法,注意,它并沒有調用最頂層Activity類所提供的InternalExecute()方法。

所以,問題的關鍵在于最頂層基類Activity的InternalExecute()方法,默認情況下,此方法將會通過 ActivityExecutor.ScheduleActivity()方法的調用將一個工作項加入到隊列中,但CodeActivity沒調用Activity基類的InternalExecute()方法而是重寫了此方法,所以就打斷了“遞歸”調用鏈。

5.小結

不知道朋友們是不是有點昏了,沒辦法,WF4內部就是有這么多的彎彎繞。   

簡單地說:工作流執行時,所有需要被執行的Activity會被封裝為一個WorkItem,被放到一個工作項隊列中,然后由WF4調度器(其實就是Scheduler類的實例)負責從此隊列中取出工作項執行。

工作項的執行可以由線程池中的線程承擔。,也可以由調用者線程來承擔。

WF4內部的工作原理非常復雜,事實上我們也沒有必要了解其每個技術細節。但如果能了解其大致的內部原理還是非常有用的,它能幫助我們避開陷阱,真正地把技術用好。

對于技術,不僅要知其然,還要知其所以然。才能真正擁有了自由。

原文標題:探索WF4 Beta2的工作流對象模型

鏈接:http://www.cnblogs.com/bitfan/archive/2009/10/29/1592591.html

【編輯推薦】

  1. 淺談WF 4.0 Beta1中的 跟蹤機制
  2. WF4.0 Beta1中的規則引擎變化
  3. 淺談WF 4.0 beta1的跟蹤配置
  4. 詳解工作流架構與實現
  5. 詳解WF4.0 Beta2中的Switch<T>活動
責任編輯:彭凡 來源: 博客園
相關推薦

2009-10-22 08:54:56

WF4 Beta 2

2009-12-01 10:08:23

WF4屬性

2009-10-28 09:23:27

WF4.0 Beta2

2010-01-14 09:35:10

WF4.0

2009-06-15 10:20:47

WF 4.0 Beta跟蹤機制

2013-10-10 15:08:36

UbuntuUbuntu 13.1gnome

2009-06-22 09:36:06

WF 4.0 beta跟蹤配置

2012-06-12 13:23:58

LinuxLinux Deepi

2009-11-25 11:31:36

Visual Stud

2021-08-13 10:09:36

鴻蒙HarmonyOS應用

2022-10-26 08:00:43

Activiti工作流BPM

2013-06-25 10:13:11

iOS7WWDC蘋果

2021-10-14 11:34:05

技術工作流引擎

2009-11-18 09:14:49

Visual Stud

2013-04-23 10:28:08

IBeamMDAAWF

2024-04-25 08:00:00

DevOps架構軟件開發

2009-12-14 09:40:50

VS 2008 Bet

2011-09-27 10:40:48

Ubuntu 11.1

2011-12-13 20:47:33

iOS 5.1

2016-11-09 16:43:40

蘋果iOS 10.2
點贊
收藏

51CTO技術棧公眾號

主站蜘蛛池模板: 99re99 | 国产福利资源在线 | 盗摄精品av一区二区三区 | 区一区二区三在线观看 | 天堂一区二区三区四区 | 黄色片免费 | 亚洲综合国产精品 | 天天干天天操天天射 | 另类亚洲视频 | 一区视频| 欧美久久久久 | 欧美精品三区 | 国产精品久久久久久久久久免费 | 羞羞免费网站 | 91在线精品播放 | 中文字幕欧美在线观看 | 久久中文免费视频 | 亚洲成人一区 | 久久国产精品一区二区 | 欧美电影在线观看网站 | 久久精品国产亚洲a | 一区二区三区四区国产精品 | 伊人青青久久 | 中文字幕91 | 天天曰天天曰 | 亚洲协和影视 | 成人福利视频网站 | 伊人热久久 | 日韩字幕| 成人在线精品 | 成人国产精品久久 | 隔壁老王国产在线精品 | 日韩人体视频 | 国产午夜精品久久久久免费视高清 | 韩日在线视频 | 国产精品成人久久久久a级 久久蜜桃av一区二区天堂 | 91一区二区 | 精品国产91久久久久久 | 99精品国自产在线观看 | 国产一区二区 | 天天天久久久 |