jBPM4的運行期環境

        萬物生長靠太陽,兒童的生長離不開土壤、空氣和水,當然,也離不開綠壩孃的調教。應用程序也是如此,離不開數據庫連接、事務、日誌、消息等,這些,共同構成了應用程序的運行期環境。
        理想中的環境是什麼樣子的哩。好吧,一句話,召之即來,揮之即去,當需要某個服務時,ok,打個響指,該服務就準備好被調用了,調用完畢後也不用費心費力地擦屁股,不必老是提心吊膽有好事者追問:你擦了嗎,確定擦了?真的確定擦了?直接丟棄給環境降解處理,自然又環保,還有個好名聲叫專注領域邏輯。

一、    運行期環境就是一個餐館
1、    提供必要的服務
作爲一個餐館,必須有廚師做飯我吃,必須有桌子和椅子。作爲運行期環境同樣如此,我要發消息,你得提供我發消息的Service,我要獲取節點任務,你得扔給我TaskService。

2、    提供獲取這些服務的統一方式
好吧,我不會親自到廚房告訴廚師我想吃什麼(因爲我擔心這樣一來我會吃不下去),我也不會親自到收銀臺給錢。這些服務有一個統一的獲取方式:服務員。我想吃什麼和結賬,告訴服務員即可。關鍵是這一方式要統一,要足夠簡單。Spring最懶,把服務給你全部注入了,當然你也可以握住BeanFactory的纖纖細手,一個一個的get。

3、    提供特定於我線程不安全的服務
我點了一盤魚香肉絲,隔壁也點了一盤魚香肉絲,結果服務員讓我們吃同一盤魚香肉絲。我立刻跳起來:靠,你們的服務不是線程安全的嗎?!Hibernate的Session正是屬於這麼一種情況,需要環境進行隔離,我的唯一職責就是吃飯!我的領域邏輯是如何優美的進餐!爲此還要不斷重構我吃飯的姿勢哩。
好不容易吃完飯,付完款,正準備離場。服務員風度翩翩地走到我的身旁,我以爲還有打折券供應,結果是:服務員小姐輕啓朱脣:先生,麻煩您把吃剩的盤子清洗完畢。
崩潰!
像數據庫連接的打開,關閉、事務的打開、提交等都屬於運行期環境應該做的事情。

4、    其他的七七八八
雜事不少,例如統一的事件機制、權限攔截等等。

二、    jBPM4的運行期環境
好吧,先來看看如何建立jBPM4的運行期環境:
EnvironmentFactory environmentFactory = new DefaultEnvironmentFactory();
 
  
 
  Environment environment 
= environmentFactory.openEnvironment();
  
try {
 
     everything available in 
this block 
 
  } 
finally {
    environment.close();
  }


兩個關鍵的類:EnvironmentFactory和Environment。

EnvironmentFactory是全局的,在整個應用程序中保持一個實例即可。

Environment則是每次方法調用則要new一個。

看看Environment的主要方法:
public abstract Object get(String name);
public abstract <T> T get(Class<T> type);


是的,environment爲我們的代碼提供所需要的服務類實例。

那麼,如何獲得environment?
繼續看:
public static Environment getCurrent();

static,我喜歡也。方便、快捷,不管是在地上、車上還是房頂上,隨處都可調用。

那麼,爲什麼Environment每次調用要new呢?
好吧,當你需要獲取數據庫Session的時候,是不是每次都要new呢。Environment提供的服務裏包括了非線程安全的數據庫操作服務。

三、    jBPM4運行期環境的實現

1、JbpmConfiguration
JbpmConfiguration是jBPM4裏最重要的類,它是整個應用程序的入口。它實現了EnvironmentFactory接口。

      JbpmConfiguration加載jBPM總的配置文件,還是大概掃一下這個配置文件:
      <jbpm-configuration xmlns="http://jbpm.org/xsd/cfg">

  
<process-engine-context>
 
    
<repository-service />
    
<repository-cache />
    
<execution-service />
    
<history-service />
    
<management-service />
    
<identity-service />
    
<task-service />

    
<hibernate-configuration>
      
<cfg resource="jbpm.hibernate.cfg.xml" />    
    
</hibernate-configuration>

    
<hibernate-session-factory />
 
  
</process-engine-context>

  
<transaction-context>
    
<repository-session />
    
<pvm-db-session />
    
<job-db-session />
    
<task-db-session />
    
<message-session />
    
<timer-session />
    
<history-session />
  
</transaction-context>

</jbpm-configuration>


配置文件被分爲了兩部分,分別是:process-engine-context和transaction-context。
對應於兩個IOC容器(WireContext)的配置文件。

作爲EnvironmentFactory,JbpmConfiguration持有成品process-engine-context對應的IOC容器(全局的)實例,持有半成品transaction-context的WireDefinition。當調用openEnvironment方法時,JbpmConfiguration會new Environment,然後將process-engine-context IOC填充入environment,同時初始化transaction-context IOC,並將其也填充入environment。這樣通過environment就可以獲得所有所需要的服務,包括全局的和非線程安全的服務實例。也就是environment透過IOC容器提供了查找各種服務的能力。


 

2、與線程綁定的environment
environment初始化之後,避免參數傳遞得一塌糊塗的方式就是將environment與線程綁定。看Environment的代碼:
  static ThreadLocal<Environment> currentEnvironment = new ThreadLocal<Environment>();

  
static ThreadLocal<Stack<Environment>> currentEnvironmentStack = new ThreadLocal<Stack<Environment>>();


是的,在openEnvironment時,有這麼一行代碼:
Environment.pushEnvironment(environment);


這樣environment就與線程綁定了,可以通過Environment.getCurrent()任意調用了。

哪裏有壓迫,哪裏就有放抗。
在environment.close()方法裏:

Environment.popEnvironment();


OK,結束。
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章