使用Infinispan创建自己的Drools和jBPM持久性
我 在這里發表的原始文章:
您好,歡迎來到我打算向您展示如何創建自己的Drools和jBPM持久性實現的帖子。 我已經為流口水對象開發了基于infinispan的持久性方案,并且在此過程中學到了很多東西。 如果您想做某種事情,我打算給您一些指導。
為什么?
如果您正在閱讀本文,那么您可能已經有了一個“為什么”來重新定義流口水使用的持久性方案,但是回顧一些很好的理由來做這樣的事情是很好的。 最重要的是,您可能會認為出于一個或多個原因,為流口水設計的JPA持久性方案無法滿足您的需求。 我發現的一些最常見的是:
給定的模型不足以進行我的設計:為持久化流口水組件(會話,流程實例,工作項等)而創建的當前對象當前盡可能小,以使數據庫具有最佳性能,并且大部分可操作數據存儲在映射到Blob對象的字節數組中。 這種方案足以使drools和jBPM運行時正常運行,但對于您的域可能還不夠。 您可能希望將運行時信息保存在一種方案中,該方案更易于從外部工具查詢,而這樣做則需要豐富數據模型,甚至創建自己的模型。
我正在使用的持久性與JPA不兼容:目前有很多持久性實現不再使用我們曾經知道的數據庫(分布式緩存,鍵值存儲,NoSQL數據庫),并且該模型通常需要額外的映射和特殊功能堅持存放在這樣的倉庫中。 這樣做,有時JPA并不是我們的理想之選
每次加載drools組件時,我都需要從不同的來源加載特殊實體:當我們擁有復雜的對象和/或外部數據庫時,有時我們希望新模型以特殊的方式與我們擁有的對象相關聯。 也許我們想確保我們的會話以特殊的方式綁定到我們的模型,因為這對我們的業務模型有意義。 為此,我們必須更改模型
怎么樣?
為了為我們的會話創建自己的持久性方案,我們需要清楚地了解JPA方案是如何構建的,并將其用作構建自己的持久性方案的模板。 此類圖顯示了如何實現知識會話的JPA持久性方案:
看起來很復雜,對吧? 不用擔心 我們將逐步了解它的工作原理。
首先,您可以看到我們有兩個StatefulKnowledgeSession的實現(或者,如果您使用的是Drools 6,則為KieSession )。 一個完成所有“管腳魔術”的任務是StatefulKnoweldgeSessionImpl ,而我們將要使用的任務是CommandBasedStatefulKnowledgeSession 。 它與持久性無關,但是通過將每個方法調用都包含在命令對象中并將其執行導出到命令服務中,對持久性有很大幫助。 因此,例如,如果您對這種類型的會話調用fireAllRules方法,它將創建一個FireAllRulesCommand對象,并將其交給另一個類執行。
這種基于命令的實現使我們能夠準確地完成在drools環境中實現持久性所需的工作:它使我們能夠在對會話的每次方法調用之前和之后實現操作。 那就是SingleSessionCommandService的地方
該類很方便:此命令服務包含一個StatefulKnowledgeSessionImpl和一個PersistenceContextManager。 每次必須執行命令時,此類都會創建或加載SessionInfo對象,并告訴持久化上下文將其與StatefulKnowledgeSessionImpl的所有狀態一起保存。
那是最復雜的部分:實現會話持久性的部分。 幾乎所有其他內容的持久性都可以通過一組給定的接口輕松完成,這些接口提供了一些方法來實現如何加載與會話相關的所有其他內容(流程實例,工作項和信號)。 只要創建一個合適的經理及其工廠,就可以委托他們將任何東西存儲到任何地方(或者做任何您想做的事情)。
因此,看完所有組件之后,現在是開始思考如何創建自己的實現的好時機。 在此示例中,我們創建了一個基于Infinispan的持久性方案,并將向您展示實現該方案的所有步驟。
步驟1 :(重新)定義模型
在大多數情況下,當我們想以自己的方式持久流口水時,我們可能會想盡辦法做到。 即使我們不希望更改模型,也可能需要向模型添加特殊注釋才能與您的存儲框架一起使用。 另一個原因可能是您想以一種特殊的方式存儲所有事實,以便與其他舊系統進行交叉查詢。 只要您了解所創建的模型,那么每次您在知識會話上調用方法時,持久性方案都會對它進行序列化和反序列化,就可以按照您希望的方式進行字面上的重新定義。因此,請始終嘗試使其保持簡單。
這是我們為這種情況創建的模型:
沒什么花哨的,只是流口水相關的所有事物的扁平化模型。 我們對這種模型不太有想像力,因為我們只是想向您顯示可以更改它。
在該模型中要注意的一件事是,我們仍然保存這些對象的所有內部數據的方式與為JPA持久性存儲數據的方式幾乎相同。 唯一的區別是JPA將其存儲在Blob中,而我們將其存儲在Base64加密的字符串中。 如果要更改字節數組的生成和讀取方式,則必須創建自己的以下接口實現:
- org.kie.api.marshalling.Marshaller進行知識講座
- 流程實例的org.jbpm.marshalling.impl.ProcessInstanceMarshaller
但是提供一個示例可能會花費大量時間,甚至可能需要整本書來解釋,因此我們將跳過。
步驟2:實現PersistenceContext
在某些情況下,重新定義PersistenceContext和PersistenceContextManager就足以實現您的所有持久性要求。 PersistenceContext是一個對象,負責實現工作項和會話對象的持久化,方法是實現持久化工作項和會話對象的方法,并通過ID查詢它們并將它們從特定的存儲實現中刪除。 PersistenceContextManager負責為所有應用程序創建一次或在每個命令的基礎上創建PersistenceContext。 comand服務將在需要時使用它來持久化會話及其對象。
在我們的案例中,我們使用Infinispan緩存作為存儲實現了PersistenceContext和PersistenceContextManager。 不同的PersistenceContextManager實例將可以通過Environment變量訪問所有配置對象。 我們已經使用Environment中已定義的鍵來存儲Infinispan相關的對象:
- EnvironmentName.ENTITY_MANAGER_FACTORY用于存儲基于Infinispan的CacheManager
- EnvironmentName.APP_SCOPED_ENTITY_MANAGER和EnvironmentName.CMD_SCOPED_ENTITY_MANAGER將指向Infinispan緩存對象。
您可以在這里看到該代碼:
在這一點上,我們有一些非常重要的步驟來重新定義我們的流口水持久性。 現在,我們需要知道如何配置我們的知識會議以使用此組件。
步驟3:為我們的工作項目,流程實例和信號創建經理
現在我們有了持久性上下文,我們需要教會會議如何正確使用它們。 知識會話具有一些可以配置的管理器,這些管理器使您可以修改或更改默認行為。 這些經理是:
- org.kie.api.runtime.process.WorkItemManager :它管理工作項目的執行時間,將其與適當的處理程序連接,并在工作項目完成時通知流程實例。
- org.jbpm.process.instance.event.SignalManager :它管理何時向進程發送信號或從進程發送信號。 由于流程實例可能被鈍化,因此需要
- org.jbpm.process.instance.ProcessInstanceManager :它管理在創建,啟動,修改或完成流程實例時要采取的動作。
這些接口的JPA實現已經可以與持久性上下文管理器一起使用,因此大多數時候您不需要擴展它們。 但是,與Infinispan相比,我們必須確保流程實例的持久性要比JPA多,因此我們必須以不同的方式實現它們。
一旦有了這些實例,就需要為每種類型的管理器創建一個工廠。接口名稱相同,但后綴“ Factory”除外。 每個用戶都接收一個知識會話作為參數,從中可以獲取環境對象和所有其他配置。
步驟4:配置知識會話
現在我們已經創建了不同的經理,我們將需要告訴我們的知識會議以使用它們。 為此,您需要使用SingleSessionCommandService實例創建一個CommandBasedStatefulKnowledgeSession實例。 顧名思義,SingleSessionCommandService是一個用于一次針對一個會話執行命令的類。 SingleSessionCommandService的構造函數接收創建適當會話并對其執行持久化方式所需的所有參數。 這些參數是:
- KieBase :具有用于會話運行時的知識定義的知識庫。
- KieSessionConfiguration :我們在其中配置管理器工廠以創建和處理工作項,流程實例和信號。
- 環境 :用于其他目的的一袋變量,我們將在其中配置持久性上下文管理器對象。
- sessionId(可選) :如果存在,則此參數在存儲中查找已存在的會話。 否則,它將創建一個新的。
同樣,在我們的示例中,我們使用的是Infinispan,它不是基于引用的存儲,而是基于值的存儲。 這意味著一旦您對infinispan說要存儲一個值,它將存儲它的一個副本而不是實際對象。 流口水持久性中的某些內容通過基于引用的存儲進行管理,這意味著您可以告訴框架持久化對象,更改其屬性,并在提交事務后查看存儲在數據庫中的那些更改。 使用infinispan不會發生這種情況,因此您必須在命令執行完成后實現對緩存值的更新。 對我們來說幸運的是,SingleSessionCommandService允許我們通過實現攔截器來做到這一點。
攔截器基本上是您自己的命令服務,用于包裝默認命令。 您可以告訴每個命令在每次執行之前或之后添加更多行為。 這里有一些圖表來解釋它是如何工作的:
如您所見,SingleSessionCommandService允許命令服務實例實際調用命令的execute方法。 并且由于命令服務的攔截器擴展,我們可以在鏈中添加任意數量的內容,從而使我們可以在每次需要執行命令時執行下一個序列圖之類的內容:
在我們的例子中,我們創建了幾個攔截器,并將它們添加到SingleSessionCommandService中。 確保在完成命令后存儲對會話對象所做的所有更改。 另一個允許我們對流程實例對象執行相同的操作。
總的來說,這是我們現在需要創建知識會話以實際使用infinispan作為持久性方案的方式:
復雜吧? 不用擔心 還有另外兩類可以簡化配置。
步驟4:創建我們自己的啟動服務
是的,每次我們想要創建自己的自定義持久性知識會話時,我們都可以編寫大量代碼。 這是一個自由的世界(大部分情況下)。 但是,您也可以將此實現包裝在帶有兩個公開方法的單個類中:
- 一個創建新的會話
- 一個加載先前存在的會話
并在內部創建所有配置,并在需要更改一項或多項更改時將其合并。 Drools提供了一個接口來充當此協議的接口,稱為org.kie.api.persistence.jpa.KieStoreServices
我們創建了此接口的自己實現,并且還創建了一個靜態類(稱為InfinispanKnowledgeService)來訪問該接口。 這使我們能夠創建如下會話:
結論
流口水的持久性似乎很難理解和工作,更不用說以自己的方式實現它了。 但是,我希望這對那些需要以特殊方式實現流口水持久性,或者甚至想知道是否可以通過JPA以外的其他方式實現流口水持久性的人有點神秘。
另外,如果您希望看到為使其工作而進行的修改,請參見以下三個請求請求:
- https://github.com/droolsjbpm/droolsjbpm-build-bootstrap/pull/38
- https://github.com/droolsjbpm/drools/pull/198
- https://github.com/droolsjbpm/jbpm/pull/166
在此JIRA票證中指定了向Drools添加此功能的功能請求。 如果您希望將其作為核心drools項目的一部分,可以隨時對其進行投票!
翻譯自: https://www.javacodegeeks.com/2013/05/creating-your-own-drools-and-jbpm-persistence-with-infinispan.html
總結
以上是生活随笔為你收集整理的使用Infinispan创建自己的Drools和jBPM持久性的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: linux编程(在linux下编程)
- 下一篇: 战车大战最新版(战车大战安卓)