在擁擠的公交車上讀完《工作流管理(模型、方法和系統)》,自從搬完家,上班的路途突然變得遙遠。
這本書確實是按照它的副標題組織的,分別介紹工作流的建模模型、應用工作流開發的方法以及部分商業的工作流產品。
對petri網的介紹是這本書的重點,如果想對petri網有個大概的了解而又不愿意接觸深奧的數學,那么可以一讀。本書隨后分析了如何對流程模型進行分
析,包括對建模正確性與否的定量分析以及對資源運行效率的定性分析。至于介紹的工作流產品,因為年代久遠,可讀性不高。應用工作流開發的方法就更是理論
了,不過作為一本2000年的書,里面提到的一些原則還是很有敏捷的意思,例如和客戶在一起、迭代開發、交流的重要性等等。
讀完這本書,加上先前的范玉順的書,突然就明白為什么BPEL會如此之流行,原因在于它們都非常強調BPR的概念,即業務流程重組。也就是從一開始,工作
流系統就是瞄準BPR這個目標來的,想利用工作流系統將整個企業的業務流程都管理起來。目標如此遠大,整合自然是不能避免,整合包括了對人員的整合,也包
括了對IT系統的集成。如此以來,恍然大悟:BPEL這種強調服務集成的執行語言無怪乎會大紅大紫了。至于說國內最普遍的工作流應用:將工作流引擎嵌入應
用系統中,分離流程邏輯與業務邏輯,則自然登不了大雅之堂了。一句話說,就是國內應用工作流的層次太低。或者反過來也可以理解:現在的所謂BPM軟件都眼
高手低,不太適合國內的應用。
可是問題依舊存在,即BPEL根本上說是一種執行語言,要業務人員理解簡直是強人所難,所以BPMN應運而生。好吧,BPMN有了,自然BPMN到
BPEL的映射就出現了,可惜這終究是一廂情愿,一種是業務建模語言,一種是計算機執行語言,中間的代溝比70、80還寬。就像科比,籃筐在他眼里比大海
還廣闊。
此外,BPEL的應用還存在一個天然的障礙,即應用集成從來都不是一件輕松的事情。將接口用web
service包裝一下就SOA了?就面向服務了?這鬼話你也信,那可真是你服務,你全家才服務呢。應用集成不輕松,所謂的企業敏捷性:能夠根據外部環境
的變化迅速調整服務編排流程那自然是鏡中月,水中花了。君不見,無數程序員們在開口大罵:靠,流程又要調整,早吃屎了?!
所以結論有三:
1、國內的嵌入式工作流應用還是什么適用就用什么吧,和XPDL\BPEL都無關;
2、一心要SOA、要BPEL。那別指望它能減少工作量,也別指望流程能夠迅速修改;
3、要對企業流程進行敏捷管理,那就考慮文檔化,別考慮執行。
posted @
2009-02-19 14:20 ronghao 閱讀(1780) |
評論 (7) |
編輯 收藏
大概花了三天的時間讀完這本書,書本身也不厚,讀起來很快。這本書出版于2001年,所以對它也沒有抱有很大的期望,但是還不錯,特別是前三章,很有些驚喜。后面關于工作流仿真的描述也很到位。但是關于技術實現,則大都略過了。
總結一下里面個人覺得不錯的部分。
第一章很不錯,強調為什么需要工作流管理系統。
企業經營環境的變化:過去企業市場競爭主要圍繞著如何提高生產率進行,現在則是圍繞新產品的競爭而展開。新產品的價格總是高于其價值,通過競爭,價格才逐漸接近價值,產品失去獨占期,同時也意味著產品生命周期的結束。與產品生命周期縮短所對應的,是客戶定制產品數量的增加。
在這種情況下,傳統串行的產品研制會延長產品的上市時間,同時串行過程也是在企業以功能為核心劃分組織機構下的必然產物。
敏捷制造提出的背景:用戶需求多樣化、個性化,所有企業都將處于一種連續改變、不可預見的市場環境中,此時問題的核心在于是否抓住機遇、快速響應市場、開發新產品。敏捷制造的基本思想是,企業能夠對持續變化、不可預測的市場需求做出快速反應,強調面向市場的敏捷性。實現敏捷制造的關鍵是對企業進行敏捷化改造和重組。其中企業組織結構發生重大的變化,傳統的企業組織結構是功能部門制,即按照不同的功能和職能設立不同的部門,上下級之間形成一個樹型的結構。這種結構的缺點在于:每個單元都由上一級的功能單元進行管理,出現問題時,每一級都會把責任推到上一級,這樣會造成部門職責不清。柔性底,一個生產流程往往跨越多個部門,部門之間的協調成本很高,扯皮。需要建立起面向流程的組織機構,按照企業要實現的主要業務流程來配置組織機構,以項目來組織人員,減少內部不必要的溝通協調成本,提高對市場的響應速度。
由此,需要工作流系統來對企業的流程進行分析和梳理。然后圍繞這些流程來進行企業的業務重組和改造。
第二章的亮點在于如何實施工作流系統。
工作流的實施不同于普通的業務處理系統,它首先需要在戰略層次上對企業的業務目標進行分析,確定企業的戰略目標和組織要求,然后再進入到具體的實施階段,分為三個階段:模型建立階段、模型實例化階段和模型執行階段。實施工作流的目的在于提高企業的柔性,能夠根據市場的變化不斷改進其業務流程。其中作者強調了工作流的兩個重要職責:集成和仿真。工作流系統本身是一個完成流程建模和流程管理的軟件系統,但是為了在企業的實際業務中得到有效的應用,它必須和企業已有的或購買的其他業務系統實現集成,通過集成來提高整個企業 的應用水平和應用效率。
第三章分析工作流系統的組成以及WFMC定義的五個接口。很清晰。
第四章到第八章描述具體商業產品的大概技術實現、XPDL規范和分布式的工作流,由于現在已經是B/S軟件的天下,所以里面的分布式在這里顯得理所當然。這部分可以跳過。
第九章講述作者實現的一個工作流系統CIMFlow。亮點在于分布式工作流機的設計方案。
核心思想是:多個工作流機分配給多個部門,與這個部門相關的流程或流程節點就由這個部門專屬的工作流機執行,部門可以各自獨立修改這些流程或流程節點。另外為了集中管理,再設置一個主控工作流機,集中管理這些部門工作流機。這樣可以提高流程的柔性。很贊的思想,但是實現無疑復雜了。
第十章講如何在企業流程重組中應用工作流。偶覺得,這本書一旦上升到企業運營的層次講解工作流,馬上就很贊了,O(∩_∩)O~。其中關于流程仿真部分很是好看,顛覆了自己對流程仿真的觀點。以前認為是流程仿真是確保流程建模的邏輯正確,屬于軟件測試的范疇。這里的仿真卻是為企業決策提供數據。需要注意的是對資源的定義。資源包括了人、業務系統、運營成本等等,很廣義的概念。
最后一章再次強調工作流集成能力的重要意義。不禁讓我想起了BPEL。
合上書,我想,這是在講工作流嗎,( ⊙o⊙ )?,咋和我印象中的工作流不一樣哩。我想,作者更強調的應該是一種高端的業務流程管理,它既不是現有的工作流、也不是BPM軟件,然而又不是BPG,因為它管理的流程是可以馬上執行的。只能這么想,作為7年前作者對工作流的理解,期望太多。
如果有電子版,值得一讀,如果買紙版,就沒有必要了。
posted @
2009-02-09 18:07 ronghao 閱讀(2394) |
評論 (3) |
編輯 收藏
在溫暖的辦公室里寫下這些字的時候,外邊的天氣很好,目光從明亮的窗戶扔出去剛好能夠觸到西直門,所以這應該算是北京的好天氣。回想起去年的這個時候,也是坐在辦公室里,在上地,不遠處的信息環島,運通105在緩緩挪動。我很喜歡運通105,盡管有很多車可以選擇,但是運通的司機總是很生猛,他能夠罵罵咧咧地迅速變線超車,也能夠搶在綠燈的最后一秒秒穿過路口,上他的車你需要確實坐穩扶好。下雨的時候會去坐車,平時則是騎車,那輛自行車幾乎每個月都要修理一次,最近一次是剎車時用力過大結果閘應聲而斷了。11月換了份工作,坐城鐵上班,自行車開始生銹,每天上班時經過車棚,看見布滿灰塵的自行車,突然就有一種極不真實的感覺,我認識它嗎,為什么它會顯得如此之陌生,生活,似乎在一瞬間就完成了轉換。
我是一個懷舊的人,經常會沉浸在過去的某種情緒里不能自拔。今年又似乎過得太快,我還沒來得及回憶,已悄然流逝。過完年就考慮著要不要換一份工作,公司的效益不好,產品的BUG太多,似乎也看不見前景。然而三月份岳母的生病打斷了這一想法,請假回家了一個禮拜,先是手術,然后化驗,結果出來,是癌癥,然后就是化療。每月發完工資,我和老婆都會去郵局,給她家里匯錢,然后打電話安慰她的母親,在電話那頭,岳母總是帶有愧疚,覺得她拖累了我們。我喜歡她的母親,和我媽媽一樣,都是很樸實的農村人。過年去她家,還沒起床,岳母已經把早飯端到床頭,糖水煮雞蛋,一個壓著一個,八個,盡管盡了最大的努力,但終究還是沒有吃完。
四月份公司策略發生變化,停止業務平臺的開發,以維護為主,同時重新開發工作流,我一直認為單獨的工作流產品是有前途的,平臺則不然,市場上這類產品已經非常的多,并且都沒有什么亮點,如果說解決某一業務類型的問題尚還合適,那么夸大到通用的地步就只能是市場忽悠罷了。至于技術性的平臺,我想,在國內,只能是叫好不叫座。再說說工作流,作為很多系統的基礎設施,我覺得是越來越普及,同時,也會越來越廉價。
那是快樂的一段時光,功能調研、TDD、制定開發計劃,每天都很充實。但是第一個版本遲遲不能發布,終于等到八月,開發被迫終止。原因是人員的流失非常嚴重,到最后只剩我一人在支撐。作為小公司,如何留住開發人員,這是個很大的問題。其實,我想,有時候不僅僅只是薪水的問題,還有很多因素,例如代碼的封閉、人員之間的交流等等。給我印象很深,一次討論實現時,我堅持了hibernate xml映射的形式,同事想引入注解,我反對,理由是會給團隊帶來新的技術學習成本,而我們的重點應該是快速實現引擎本身。后來,同事離職,老板找我談話時提到了這件事情。這讓我汗了很長時間。還有很多溝通的方式需要學習。
開始招人,始終找不到合適的人。有人給我的博客留言想面試,是一個四川的小伙子,汶川地震當了一個月志愿者回來沒有多久,身上似乎還有沙子、混凝土的味道。一下子就喜歡上他,很勤奮、積極,雖然工作經驗不多、也只是大專,但是給人的感覺很向上。有時,真的,覺得工作經驗并不是很重要(行業經驗除外),但是一定要有精神。離開公司時,我想,這也算是我給公司做出的貢獻。
汶川地震時,坐在辦公室里,3樓,沒有任何感覺,就看到樓下突然聚集了越來越多的人們。QQ同學群發來消息:地震了!哪兒地震了?通州?四川?不,是心里!接下來幾天里,看著電視里的不間斷報道,眼淚就下來了。我是堅持要對政府批評的那部分人,我認為雖然有進步,但是還不夠,一直到今天,政府失職的地方實在是太多。其實,政府一直缺少的就不是贊美,而是批評。我厭惡專家,他們在08年集體華麗地轉身,變成磚家。一直在關注冉云飛的博客,每周,他都會有四川掮客周刊,然而,最近,他也被和諧了。
8月份在北京受孕,工作流開發停止,剛好看看書,也從公司的角度思考一下發展。小公司,生存是第一位的,工作流開發需要投入,暫時沒有產出,中斷可以理解。但是,作為一個技術性公司,如果沒有技術那就失去了競爭力,長遠的發展是個問題。真是矛盾。中小公司,99%的成敗取決于老板。大公司靠財務,小公司靠銷售。我覺得公司的銷售和市場有些問題:好吧,就算是產品功能不強大,那售前那么少,怎么解釋。是客戶在沒了解你的產品前,就把你的產品給cut了?或者,他們根本就不知道有這么一個產品?你是僅僅提供一個產品,還是提供一整套的解決方案?解決方案僅僅基于自己的產品?有那么多的工作流應用經驗,這個能不能以服務的方式提供收益?盈利模式是什么?技術、編碼,這些此時都不重要了。
去年的這個時候為自己寫下了08年的展望。第一是結婚,10月份的時候實現了。第二個是開發一個基于js的工作流設計器,沒有完成,也不打算去做了。第三個是工作上是否有新的挑戰,是的,11月終于換了工作,去了自己一直想去的公司,但是要是原公司能夠有足夠的成本支持工作流的開發,也許現在還在那里,畢竟是自己負責的第一個產品,有很多的想法在里面,并且已經完成了第一個版本目標的80%,有這么個說法,很多產品倒在最后一里路上,我的體會很深。第四是多看看非技術書、善待家人,這點做得還不夠,年底和朋友一起翻譯了《Spring Recipes》,每天晚上都翻到12點,經常忘記給家里打電話。有次父親給我打過來,說,吃飯了沒。我看看表,11點了,說,都11點了怎么會還沒吃飯?父親用很驚訝的語氣說,哦,我還以為你忙得連飯都沒空吃呢,原來還是不忙啊。父親是在怪我沒給他打電話呢。
有過很多矛盾,年底前最終還是決定開發一個工作流的開源系統,想法是前公司的老大提出的,基于jbpm,實際我并不是很喜歡jbpm的一些實現,我想自己實現引擎,但是考慮到用戶,這無疑是最好的選擇。明年的愿望就是:把這個開源的工作流系統做下去,發布出來。
再就是,要鍛煉身體,又胖了。
posted @
2008-12-29 17:03 ronghao 閱讀(499) |
評論 (0) |
編輯 收藏
當面對一個完整的工作流系統時,你可能會被它眾多的功能所困惑:流程流轉模式、時間服務、組織適配、表單權限等等。但是如果我們轉換一種思路,首先從用戶使用的角度來進行分析,工作流系統的組成就會變得異常清晰。實際在現實開發中,整個系統也是由用戶的業務需求一步步迭代而來。
一、
從用戶的角度分析工作流系統的組成
這里的用戶分為兩類:一類是應用系統開發人員(以后簡稱開發人員),一類是應用系統的最終用戶(以后簡稱最終用戶)。對于最終用戶而言,工作流系統往往是不能直接使用的,它需要由IT部門的開發人員嵌入到應用系統中。開發人員才是工作流系統的直接使用者,這造成了問題:工作流系統更多關注于開發人員的需求,例如如何快速開發、如何更好的嵌入業務邏輯等等,而最終用戶的需求被或多或少的忽略了。

這里從最終用戶的角度進行分析。
1、
面向開發人員的流程設計器
最終用戶通過流程設計器對業務流程進行描述,實際是一個流程建模的過程。理論上,業務分析師完成這個業務流程建模的過程,并且業務分析師往往被假定為非技術人員。對于業務分析而言,流程建模通常是抽象的,一定程度上是模糊的,建模的目的在于通過圖形的形式向其他人解釋一個業務的過程,圖形只是一種方式,采用它只是它更易于理解和易于溝通,實際類似于DSL。實際上企業的規章制度、文字描述的執行流程都是對業務流程具體的描述方式。
對于工作流而言,這個建模所產生的流程是需要被引擎執行的。這就要求流程中每一個節點的定義都是要有明確含義的,它需要被計算機明確而準確的解釋。同時,出于集成業務系統的需要,流程模型定義往往帶有很多額外的屬性。
所以現實中的流程設計器往往屬性配置繁多。導致最終用戶在打開設計器后根本無從修改和建模,他需要關注很多與業務無關的配置,無意中的修改往往產生流程無法運行的后果。
2、
工作項列表
即任務列表。工作流系統通過工作項列表進行人工任務的分配。最終用戶通過該列表簽收、處理每天的工作,工作以工作項的形式展現。對于工作項,用戶有著多種業務操作:簽收、完成提交、收回、回退等等。對于分配給他人的工作項,也存在著多種業務操作:催辦、提醒、時間限定等等。
3、
流程追蹤
用戶在處理工作項時,對該工作在流程中所處的位置進行查看,了解當前流程的狀態和執行情況。一般情況下,流程追蹤以圖形化的方式展現。用戶通過不同的圖標和標示來區分流程中各個節點的狀態和參與者信息。
4、
流程實例管理
包括流程實例、節點實例、工作項實例的管理。改變狀態,包括了掛起、重新啟動、終止、跳轉等等。主要目的在于對流程人為執行錯誤進行人工干預以及對流程信息的監控。
二、
系統架構
從用戶的角度分析完工作流系統的組成,這里從開發人員的角度分析工作流系統的架構。系統架構里的每一部分是如何與用戶使用的部分進行對應,以及每一部分在實現時需要注意的事項。
1、
整體構成
如圖,各模塊分層組織,位于上層的模塊依賴于底層的模塊。正如你所看到的,流程定義模型位于整個工作流系統的最低層,因為它是整個工作流系統的基礎。

流程定義模型:定義對流程進行描述的所有對象。因為對流程進行描述的本質就是利用這些模型進行建模,所以這些模型對象的實現直接決定著工作流系統對流程的描述能力。
組織結構適配器:工作流系統在與業務系統進行集成時,需要進行組織適配,通過這一過程將業務系統里的組織機構導入到工作流系統里。具體實現時,工作流系統需要建立起自己的組織機構模型(包含在流程定義模型里),要適應多種業務系統,往往需要建立多套模型,根據具體情況進行切換。有多種方式完成這個適配,最簡單的方式是利用SQL配置讀取數據進行語義轉換。
流程設計器:供用戶使用的可視化圖形工具。每種圖形都對應著一種流程定義模型。具體的實現有Swing、SWT,但是基于AJAX的WEB設計器無疑會提供更好的可用性。
流程執行引擎:將流程定義模型解釋為流程實例模型。利用這些流程實例模型完成流程的調度和執行。在工作流系統里,執行引擎是整個系統的核心。實現時不僅需要考慮各種流程調度的實現,還要考慮執行的效率、緩存、日志等等。
工作項引擎:解析參與者定義模型和工作項定義模型,生成相應的工作項。對用戶對工作項的操作作出響應。
WEB應用:工作流系統的WEB展現。包括了工作項列表、流程追蹤以及流程實例管理的操作和顯示。
流程仿真:對建立好的流程模型進行運行仿真,模擬流程模型的執行過程。目的在于發現流程建模過程中的疏漏,發現由此導致的流程不能運行。
時間服務:提供對整個流程實例執行時間和任務執行時間的控制,根據規則觸發相應的時間事件,例如任務超時、任務預警等等。根據規則自動觸發啟動新的流程實例。
業務集成:提供工作流系統與業務系統的契合方式。典型的實現包括通過注冊事件監聽器和提供接口抽象類調用業務系統代碼、提供API給業務系統調用、工作項驅動業務表單和腳本引擎執行業務邏輯腳本等等。特定于工作項驅動業務表單,為方便開發,絕大多數的工作流廠商都提供了電子表單的實現。
2、
基于事件的流程執行引擎
流程執行引擎的主要職責就是負責流程的調度和執行。
首先需要將流程定義模型解釋為流程實例模型,在定義模型和實例模型之間建立起對應關系。一個簡單的對應關系如下圖所示:

執行引擎將流程定義模型的屬性讀取到相應的實例模型里,由實例模型完成流程的調度和執行。當然,上圖只是一個簡單的描述,實際情況要復雜的多,特別是節點定義(ActivityDefinition),根據實際應用,往往存在著多種類型,典型的有開始節點(StartDefinition)、任務節點(TaskDefinition)、自動節點(AutoDefinition)、分裂節點(SplitDefinition)、匯聚節點(JoinDefinition)、結束節點(EndDefinition)等等。這些節點的實例根據類型的不同執行不同的邏輯。其中,分裂節點實例和匯聚節點實例負責流程的調度,它們決定流程的流向,通常情況下,它們會調用一個腳本引擎執行一段腳本來決定流程的流向,同時,也會提供對外暴露的接口,由業務系統實現,接口返回的結果決定流程的流向。任務節點實例和自動節點實例則負責流程的執行,為保證流程執行引擎職責的清晰以及對外圍設施的松耦合,它們只是發布相關的事件,通過事件發布/訂閱機制來觸發具體的邏輯執行。

典型的事件有流程啟動事件、流程結束事件、進入節點事件、離開節點事件、時間事件等。例如,任務節點實例的進入節點事件將會觸發工作項引擎生成工作項(Workitem),并觸發時間服務器開始計時。
3、
基于充血模型的工作項引擎
對最終用戶而言,大部分的業務操作都集中在對工作項的操作上。常見的包括工作項的提交、收回、委派、追加和退回。這些操作從系統設計的角度不僅涉及到工作項(Workitem)對象內部狀態的變化,而且影響到流程執行引擎的調度以及相關的其他工作項對象狀態。
工作項引擎的職責包括兩部分。第一,監聽任務節點實例的進入事件,生成工作項實例。第二,處理上面提到的各種工作項操作。

實現時,工作項生成器根據任務參與者的執行模式典型的分為四種情況:
競爭參與,當有多個參與者參與該任務時,產生競爭,誰先開始這項工作,就由誰負責完成該工作。此時,工作項生成器生成多個工作項實例,在某個工作項完成時會終止其余工作項。
順序參與,多個參與者按照指定的順序完成該工作。A完成之后由B完成,B完成之后再交給C完成。此時,工作項生成器生成多個工作項實例,根據順序依次激活各個工作項。
共同參與,多個參與者同時對工作進行處理。此時,工作項生成器生成多個工作項實例并全部激活。
智能決策,存在多個參與者的情況下,工作項生成器能夠根據一定的指標(由數據分析,例如人員的處理效率,工作負載等等)和規則來決定該節點的參與者并為其生成相應工作項。這里涉及到算法。
對于工作流系統而言,各種流程實例對象都是充血模型。特定于各種工作項操作的處理,此時的工作項對象亦設計為充血模型,將業務邏輯封裝到領域模型里,簡化領域模型之間的交互,省去頻繁的get/set。由領域模型再委派到具體的處理類里。
Client->(Business Facade)->Domain Model->service->Data Access(DAO)
4、
工作項驅動業務表單的業務集成方式
最終用戶對任務的處理,必然由工作項對應著某一業務表單。用戶在工作項列表里選擇自己需要辦理的工作項,由工作項導航到業務表單。
特定于WEB系統,業務表單的導航由url完成。在流程定義模型設計時,將url設置入節點屬性,生成工作項時將此url保存在工作項對象屬性里。點擊工作項詳細信息時即打開該url,完成到業務表單的導航。業務表單頁面通常需要引入處理工作項邏輯的父頁面或者導入定制的js庫,這些父頁面或js庫由工作流產品提供。這樣,對于業務表單編寫,工作流邏輯是透明的。
posted @
2008-11-07 11:20 ronghao 閱讀(2199) |
評論 (0) |
編輯 收藏
系統要集群,使用SNA方案。
一、 緩存的處理
緩存要使用統一的緩存服務器,集中式緩存。
原先的實現采用ehcache。
在spring里的配置,以資源緩存為例:
<!-- EhCache Manager -->
<bean id="cacheManager" class="org.springframework.cache.ehcache.EhCacheManagerFactoryBean">
<property name="configLocation">
<value>classpath:ehcache.xml</value>
</property>
</bean>
<bean id="resourceCacheBackend"
class="org.springframework.cache.ehcache.EhCacheFactoryBean">
<property name="cacheManager" ref="cacheManager"/>
<property name="cacheName" value="resourceCache"/>
</bean>
<bean id="resourceCache"
class="com.framework.extcomponent.security.authentication.services.acegi.cache.EhCacheBasedResourceCache"
autowire="byName">
<property name="cache" ref="resourceCacheBackend"/>
</bean>
cacheManager負責對ehcache進行管理,初始化、啟動、停止。
resourceCacheBackend負責實際執行緩存操作,put 、get、remove。
resourceCache實現具有業務語義的業務應用層面的緩存操作,內部調用resourceCacheBackend操作。
現在采用memcached。
關于客戶端,采用文初封裝的客戶端,地址在http://code.google.com/p/memcache-client-forjava/。
使用spring的FactoryBean進行二次封裝。同理:
memcachedManager負責對memcached進行管理,初始化、啟動、停止。
代碼:
/**
* User: ronghao
* Date: 2008-10-14
* Time: 10:36:30
* 管理Memcached 的CacheManager
*/
public class MemcachedCacheManagerFactoryBean implements FactoryBean, InitializingBean, DisposableBean {
protected final Log logger = LogFactory.getLog(getClass());
private ICacheManager<IMemcachedCache> cacheManager;
public Object getObject() throws Exception {
return cacheManager;
}
public Class getObjectType() {
return this.cacheManager.getClass();
}
public boolean isSingleton() {
return true;
}
public void afterPropertiesSet() throws Exception {
logger.info("Initializing Memcached CacheManager");
cacheManager = CacheUtil.getCacheManager(IMemcachedCache.class,
MemcachedCacheManager.class.getName());
cacheManager.start();
}
public void destroy() throws Exception {
logger.info("Shutting down Memcached CacheManager");
cacheManager.stop();
}
}
配置:
<bean id="memcachedManager"
class="com.framework.extcomponent.cache.MemcachedCacheManagerFactoryBean"/>
resourceCacheBackend負責實際執行緩存操作,put 、get、remove。
代碼:
/**
* User: ronghao
* Date: 2008-10-14
* Time: 10:37:16
* 返回 MemcachedCache
*/
public class MemcachedCacheFactoryBean implements FactoryBean, BeanNameAware, InitializingBean {
protected final Log logger = LogFactory.getLog(getClass());
private ICacheManager<IMemcachedCache> cacheManager;
private String cacheName;
private String beanName;
private IMemcachedCache cache;
public void setCacheManager(ICacheManager<IMemcachedCache> cacheManager) {
this.cacheManager = cacheManager;
}
public void setCacheName(String cacheName) {
this.cacheName = cacheName;
}
public Object getObject() throws Exception {
return cache;
}
public Class getObjectType() {
return this.cache.getClass();
}
public boolean isSingleton() {
return true;
}
public void setBeanName(String name) {
this.beanName=name;
}
public void afterPropertiesSet() throws Exception {
// If no cache name given, use bean name as cache name.
if (this.cacheName == null) {
this.cacheName = this.beanName;
}
cache = cacheManager.getCache(cacheName);
}
}
配置:
<bean id="resourceCacheBackend"
class="com.framework.extcomponent.cache.MemcachedCacheFactoryBean">
<property name="cacheManager" ref="memcachedManager"/>
<property name="cacheName" value="memcache"/>
</bean>
resourceCache同上,替換新的實現類MemcachedBasedResourceCache即可。
二、 Session失效的處理
采用memcached作為httpsession的存儲,并不直接保存httpsession對象,自定義SessionMap,SessionMap直接繼承HashMap,保存SessionMap。
會話膠粘:未失敗轉發的情況下沒必要在memcached保存的SessionMap和httpsession之間復制來復制去,眉來眼去。
利用memcached計數器保存在線人數。
系統權限采用了acegi,在acegi的攔截器鏈里配置snaFilter
<bean id="filterChainProxy"
class="org.acegisecurity.util.FilterChainProxy">
<property name="filterInvocationDefinitionSource">
<value>
CONVERT_URL_TO_LOWERCASE_BEFORE_COMPARISON
PATTERN_TYPE_APACHE_ANT
/**=snaFilter,httpSessionContextIntegrationFilter,logoutFilter,authenticationProcessingFilter,basicProcessingFilter,securityContextHolderAwareRequestFilter,exceptionTranslationFilter,filterInvocationInterceptor
</value>
</property>
</bean>
注意需要配置在第一個。
snaFilter的職責:
1、 沒有HttpSession時,創建HttpSession;
2、 創建Cookie保存HttpSession id;
3、 如果Cookie保存的HttpSession id與當前HttpSession id一致,說明是正常請求;
4、 如果Cookie保存的HttpSession id與當前HttpSession id不一致,說明是失敗轉發;失敗轉發的處理:
4.1、根據Cookie保存的HttpSession id從memcached獲取SessionMap;
4.2、SessionMap屬性復制到當前HttpSession;
4.3、memcached刪除SessionMap。
5、 判斷當前請求url是否是登出url,是則刪除SessionMap,在線人數減1.
代碼:
public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse,
FilterChain filterChain) throws IOException, ServletException {
final HttpServletRequest hrequest = (HttpServletRequest) servletRequest;
final HttpServletResponse hresponse = (HttpServletResponse) servletResponse;
String uri = hrequest.getRequestURI();
logger.debug("開始SNA攔截-----------------" + uri);
HttpSession httpSession = hrequest.getSession();
String sessionId = httpSession.getId();
//如果是登出,則直接干掉sessionMap
if (uri.equals(logoutUrl)) {
logger.debug("remove sessionmap:" + sessionId);
//在線人數減1
getCache().addOrDecr("userCount",1);
getCache().remove(sessionId);
} else {
String cookiesessionid = getSessionIdFromCookie(hrequest, hresponse);
if (!sessionId.equals(cookiesessionid)) {
createCookie(sessionId, hresponse);
SessionMap sessionMap = getSessionMap(cookiesessionid);
if (sessionMap != null) {
logger.debug("fail over--------sessionid:" + sessionId + "cookiesessionid:" + cookiesessionid);
initialHttpSession(sessionMap, httpSession);
cache.remove(cookiesessionid);
}
}
}
filterChain.doFilter(hrequest, hresponse);
}
利用HttpSessionAttributeListener監聽httpsession的屬性變化,同步到memecached中的sessionmap。
public void attributeAdded(HttpSessionBindingEvent event) {
HttpSession httpSession = event.getSession();
String attrName = event.getName();
Object attrValue = event.getValue();
String sessionId = httpSession.getId();
logger.debug("attributeAdded sessionId:" + sessionId + "name:" + attrName + ",value:" + attrValue);
SessionMap sessionMap = getSessionMap(sessionId);
if (sessionMap == null){
//在線人數加1
getCache().addOrIncr("userCount",1);
sessionMap = new SessionMap();
}
logger.debug("name:" + attrName + ",value:" + attrValue);
sessionMap.put(attrName, attrValue);
getCache().put(sessionId, sessionMap);
}
public void attributeRemoved(HttpSessionBindingEvent event) {
HttpSession httpSession = event.getSession();
String attrName = event.getName();
String sessionId = httpSession.getId();
logger.debug("attributeRemoved sessionId:" + sessionId + "name:" + attrName);
SessionMap sessionMap = getSessionMap(sessionId);
if (sessionMap != null) {
logger.debug("remove:" + attrName);
sessionMap.remove(attrName);
getCache().put(sessionId, sessionMap);
}
}
public void attributeReplaced(HttpSessionBindingEvent event) {
attributeAdded(event);
}
利用HttpSessionListener,sessionDestroyed事件時根據sessionid刪除memcached里的sessionMap(如果存在)。不再擔心httpsession的過期問題。
public void sessionDestroyed(HttpSessionEvent event) {
HttpSession httpSession = event.getSession();
String sessionId = httpSession.getId();
logger.debug("session Removed sessionId:" + sessionId);
SessionMap sessionMap = getSessionMap(sessionId);
if (sessionMap != null) {
logger.debug("remove sessionmap:" + sessionId);
//在線人數減1
getCache().addOrDecr("userCount",1);
getCache().remove(sessionId);
}
}
三、 文件保存的處理
和緩存類似,采用集中式的文件服務。對于linux,采用nfs。參考文檔http://linux.vbird.org/linux_server/0330nfs.php#What_NFS_perm。關鍵在于對權限的分配。
應用程序本身不用修改。
posted @
2008-10-28 20:41 ronghao 閱讀(2507) |
評論 (3) |
編輯 收藏