官术网_书友最值得收藏!

4.3 元素解析環(huán)境準(zhǔn)備

4.3.1 文檔轉(zhuǎn)換器

3.6節(jié)詳細(xì)講解了流程文檔內(nèi)容與BpmnModel實(shí)例對象的相互轉(zhuǎn)化,該轉(zhuǎn)換過程涉及流程文檔中的元素解析,下面詳細(xì)講解引擎解析流程文檔的具體處理步驟,首先定義一個流程文檔oneTaskProcess.bpmn20.xml,該流程文檔的內(nèi)容如代碼清單4-3所示,流程定義圖如圖4-5所示。

圖4-5 文檔定義圖

代碼清單4-3 oneTaskProcess.bpmn20.xml

上述流程文檔中定義了開始節(jié)點(diǎn)start、任務(wù)節(jié)點(diǎn)operationTask、usertask和結(jié)束節(jié)點(diǎn)End。

注意

所有元素的屬性id值必須在流程文檔中全局唯一。

下面定義一個類,該類主要用于解析流程文檔,如代碼清單4-4所示。

代碼清單4-4 ExtensionOperationProcessTest.java

將上面代碼中convertToBpmnModel方法的處理邏輯進(jìn)行如下總結(jié)。

(1)第3~4行獲取流程文檔的文件流。流程文檔的文件流獲取方式有很多,可以使用絕對定位的方式獲取,也可以從網(wǎng)絡(luò)資源加載獲取,本案例使用類加載器的方式獲取流程文檔的文件流。

(2)包裹文件流。第5行將獲取到的InputStream類型的輸入流,然后將其包裹為Activiti引擎可識別的StreamSource。

(3)第6行實(shí)例化BpmnXMLConverter類,該類非常重要,負(fù)責(zé)調(diào)度元素的解析工作,并維護(hù)元素解析器與元素之間的對應(yīng)關(guān)系。

(4)第7~8行調(diào)用BpmnXMLConverter實(shí)例對象的convertToBpmnModel方法解析元素,該方法最終返回BpmnModel類型的實(shí)例對象bpmnModel,并將元素解析之后的結(jié)果填充到bpmnModel對象中。配合下面的時序圖(如圖4-6所示),可能會更加容易理解。

圖4-6 BpmnXMLConverter類的convertToBpmnModel方法時序圖

上面的代碼中,構(gòu)造了StreamSource實(shí)例對象,這樣后續(xù)進(jìn)行資源處理時就可以通過StreamSource實(shí)例對象獲取文件流信息,那么StreamSource文件流是如何封裝的呢?

4.3.2 封裝流程文檔數(shù)據(jù)流

StreamSource接口的定義如代碼清單4-5所示。

代碼清單4-5 StreamSource.java

StreamSource接口繼承InputStreamProvider接口,該接口只定義了一個方法getInputStream(),該方法返回InputStream實(shí)例對象,不同來源的資源文件都有相應(yīng)的StreamSource實(shí)現(xiàn):如byte數(shù)組(BytesStreamSource)、InputStream資源(InputStreamSource)、URL網(wǎng)絡(luò)資源(UrlStreamSource)、classpath資源(ResourceStreamSource)等,該類的類圖如圖4-7所示。

圖4-7 資源文件處理相關(guān)類圖

在實(shí)際項(xiàng)目開發(fā)中,資源文件的定位以及數(shù)據(jù)流的獲取需要經(jīng)常使用,如果不打算自己實(shí)現(xiàn)則可以直接通過Activiti提供的相關(guān)類進(jìn)行操作,如代碼清單4-6所示。

代碼清單4-6 ExtensionOperationProcessTest.java

獲取到inputStream實(shí)例對象之后,就可以按照平時的開發(fā)方式進(jìn)行相關(guān)實(shí)現(xiàn)。StreamSource接口可以對需要操作的資源文件進(jìn)行統(tǒng)一處理,其實(shí)現(xiàn)原理非常簡單,以ResourceStreamSource類中的getInputStream方法為例,該方法的實(shí)現(xiàn)方式便是直接調(diào)用classLoader提供的底層方法進(jìn)行操作。

StreamSource接口定義了getInputStream方法,并提供了一系列訪問不同資源的實(shí)現(xiàn)類,而BpmnXMLConverter類中的convertToBpmnModel方法需要InputStreamProvider類型的參數(shù),這樣的設(shè)計(jì)是典型的策略模式,了解了StreamSource類的相關(guān)設(shè)計(jì)原理之后,接下來深入探究BpmnXMLConverter類的初始化過程。

4.3.3 初始化元素解析器

代碼清單4-4實(shí)例化了BpmnXMLConverter類,實(shí)例化該類的同時流程引擎做了什么工作呢?首先進(jìn)入BpmnXMLConverter類,該類的相關(guān)定義如代碼清單4-7所示。

代碼清單4-7 BpmnXMLConverter.java

BpmnXMLConverter類中并沒有相關(guān)構(gòu)造方法,所以接下來分析該類的靜態(tài)代碼塊,首先明確一點(diǎn),該類的靜態(tài)代碼塊主要用于初始化類中的各種屬性值,且類中的靜態(tài)代碼塊只會被執(zhí)行一次,由于實(shí)例化BpmnXMLConverter類的同時該類已經(jīng)被JVM加載,所以會首先執(zhí)行第5~9行代碼,該代碼則直接調(diào)用第10行以及第13行定義的方法,最終將流程元素以及其對應(yīng)的解析器添加convertersToBpmnMap和convertersToXMLMap集合。

流程文檔中的大部分元素與之對應(yīng)的解析器均是一一對應(yīng)關(guān)系,但對于dataObject類型的元素來說,就需要特殊處理一下,因?yàn)樵擃愋偷脑貎H僅是數(shù)據(jù)類型不同而已,其他屬性定義幾乎完全相同,常用數(shù)據(jù)類型的有String、Boolean、Integer等,因此沒有必要為每一種具體的數(shù)據(jù)類型單獨(dú)定義一個解析器,只需要在dataObject元素對應(yīng)的解析器中根據(jù)數(shù)據(jù)類型進(jìn)行區(qū)分處理即可,附帶的好處就是可以將不同數(shù)據(jù)類型的元素解析工作集中起來管理,這樣也可以控制不同數(shù)據(jù)類型的元素按照指定的先后順序進(jìn)行解析。

注意

ValuedDataObjectXMLConverter類負(fù)責(zé)解析dataObject元素。

第5~9行代碼執(zhí)行完之后,開始實(shí)例化第1~2行中的各種內(nèi)置元素解析器,例如signal元素的解析器SignalParser。第14行使用convertersToBpmnMap集合存儲元素以及元素對應(yīng)的解析器,該集合為Map數(shù)據(jù)結(jié)構(gòu),key為String類型,存儲流程文檔中定義的元素名稱,對應(yīng)converter.getXMLElementName()方法的返回值(流程文檔中元素的名稱), value為元素對應(yīng)的解析器,例如解析結(jié)束事件(endEvent)元素的時候可以直接從convertersToBpmnMap集合中查找key為endEvent的值,這樣就可以查詢到EndEventXMLConverter類。

思考一個問題:為什么使用Map數(shù)據(jù)結(jié)構(gòu)存儲,而不是其他數(shù)據(jù)結(jié)構(gòu)方式存儲,例如List方式存儲,關(guān)于這樣設(shè)計(jì)的動機(jī)和意圖可以參考4.4.1節(jié)的講解。

4.3.4 文檔轉(zhuǎn)換器功能

了解了BpmnXMLConverter類的初始化過程之后,接下來分析該類的功能結(jié)構(gòu),如圖4-8所示。

圖4-8 BpmnXMLConverter類功能結(jié)構(gòu)圖

圖4-8描述了BpmnXMLConverter類中的核心方法,下面細(xì)化講解該類中的方法所提供的功能。

(1)convertToBpmnModel方法:解析流程文檔中的元素,最終將元素解析結(jié)果封裝為BaseElement實(shí)例對象,該方法最終返回BpmnModel實(shí)例對象。可以將BpmnModel實(shí)例對象理解為流程文檔解析之后的內(nèi)存對象,流程文檔中所有元素的解析結(jié)果均存儲在該實(shí)例對象中,開發(fā)人員可以直接通過該實(shí)例對象獲取流程文檔中定義的所有元素信息。

(2)convertToXML方法:將BpmnModel實(shí)例對象轉(zhuǎn)化為流程文檔內(nèi)容,該方法的操作與convertToBpmnModel方法的操作完全相反,convertToBpmnModel方法則將流程文檔內(nèi)容轉(zhuǎn)化為BpmnModel實(shí)例對象。

(3)validateModel方法:使用BPMN20.xsd文件以及該文件所引入的其他XSD文件來驗(yàn)證流程文檔中定義的元素是否符合其約束。

(4)addConverter方法:向BpmnXMLConverter類中的convertersToBpmnMap和convertersToXMLMap集合添加元素解析器,開發(fā)人員可以通過該方法添加自定義元素解析器從而替換引擎默認(rèn)的元素解析器。該方法非常重要。

4.3.5 元素解析環(huán)境準(zhǔn)備

接下來詳細(xì)分析BpmnXMLConverter類中convertToBpmnModel方法的實(shí)現(xiàn)邏輯,如代碼清單4-8所示。

代碼清單4-8 BpmnXMLConverter.java

上文詳細(xì)講解了STAX解析XML的處理流程,有了前面的學(xué)習(xí)基礎(chǔ),相信可以很輕松地掌握convertToBpmnModel方法的執(zhí)行邏輯,下面對該方法的執(zhí)行邏輯加以總結(jié)。

(1)第2行實(shí)例化XMLInputFactory工廠。

(2)第3~6行為XMLInputFactory實(shí)例對象添加防護(hù)措施,防止外部DTD或者XSD文件入侵。

(3)第9行根據(jù)inputStreamProvider對象中的文件流實(shí)例化InputStreamReader類。

(4)第10行創(chuàng)建XMLStreamReader實(shí)例對象。

(5)第12行如果開啟了Schema文件驗(yàn)證,則需要驗(yàn)證流程文檔中定義的元素是否符合XSD文件約束要求。

(6)流程文檔驗(yàn)證之后,第18~19行需要重新打開InputStreamReader流并實(shí)例化XMLStreamReader類,因?yàn)镾chema文件驗(yàn)證完畢之后該流已經(jīng)被關(guān)閉了,因此需要重新打開該流。

(7)以上所有步驟操作無誤之后,第22行直接委托convertToBpmnModel(xtr)方法解析流程文檔元素,配合時序圖如圖4-9所示,可能會更容易理解。

圖4-9 調(diào)用BpmnXMLConverter類的convertToBpmnModel方法時序圖

(8)第23~26行關(guān)閉文件流。

4.3.6 驗(yàn)證流程文檔格式

從代碼清單4-8的處理邏輯可以看出,只有validateSchema參數(shù)值為true的情況下才會開啟流程文檔元素的驗(yàn)證工作,開啟流程文檔元素驗(yàn)證之后,根據(jù)enableSafeBpmnXml參數(shù)值執(zhí)行不同的邏輯,具體實(shí)現(xiàn)如代碼清單4-9所示。

代碼清單4-9 BpmnXMLConverter.javaschema驗(yàn)證XML

通過分析上面代碼的處理邏輯可知不管使用什么方式驗(yàn)證Schema文件,首先都會調(diào)用createSchema方法創(chuàng)建Schema實(shí)例對象,然后基于該對象獲取驗(yàn)證器,最后直接使用驗(yàn)證器進(jìn)行流程文檔的驗(yàn)證工作,唯一的區(qū)別就是第4行代碼使用StreamSource實(shí)例對象,第10行代碼使用StAXSource實(shí)例對象。下面分析createSchema方法的執(zhí)行邏輯,如代碼清單4-10所示。

代碼清單4-10 BpmnXMLConverter.java創(chuàng)建Schema

創(chuàng)建schema對象的邏輯非常簡單,首先第3行獲取工廠類SchemaFactory,然后第6行或者第9行調(diào)用該工廠類中的newSchema方法創(chuàng)建schema對象,newSchema方法依賴BPMN_XSD資源文件,第5行判斷當(dāng)前類的類加載器classloader屬性值是否存在,如果存在則直接通過該類加載器獲取BPMN_XSD文件流,否則第8行判斷schema是否為空,如果不為空第9行通過BpmnXMLConverter類獲取類加載器,然后再通過該類加載器獲取BPMN_XSD文件流,第11行判斷schema是否為空,如果為空則程序報錯。

通過分析上面代碼的處理邏輯可以看出classloader的使用優(yōu)先級最高,如果開發(fā)人員想要為classloader屬性賦值,只需要自定義一個文檔轉(zhuǎn)換器并繼承BpmnXMLConverter類,然后為其設(shè)置classloader屬性值即可。

注意

BPMN_XSD資源文件對應(yīng)的XSD文件位于activiti-bpmn-converter-5.21.0.jar包中。

在正式環(huán)境建議設(shè)置enableSafeBpmnXml參數(shù)值為true,這樣Activiti引擎解析流程文檔時會立即驗(yàn)證流程文檔中定義的元素是否符合BPMN20.xsd文件的約束要求,方便及早發(fā)現(xiàn)錯誤信息。

主站蜘蛛池模板: 朔州市| 广宗县| 漳浦县| 新巴尔虎左旗| 牡丹江市| 资阳市| 潍坊市| 彰化市| 玛沁县| 大理市| 大连市| 江油市| 广灵县| 南丰县| 东乌| 昌图县| 湘阴县| 襄樊市| 江陵县| 禄劝| 浦城县| 高青县| 安阳市| 湘西| 旺苍县| 西畴县| 女性| 临高县| 秀山| 牟定县| 东莞市| 醴陵市| 神木县| 同心县| 恩平市| 家居| 酉阳| 内乡县| 阿城市| 普定县| 政和县|