萬物生長靠太陽,兒童的生長離不開土壤、空氣和水,當(dāng)然,也離不開綠壩娘的調(diào)教。應(yīng)用程序也是如此,離不開數(shù)據(jù)庫連接、事務(wù)、日志、消息等,這些,共同構(gòu)成了應(yīng)用程序的運行期環(huán)境。
理想中的環(huán)境是什么樣子的哩。好吧,一句話,召之即來,揮之即去,當(dāng)需要某個服務(wù)時,ok,打個響指,該服務(wù)就準備好被調(diào)用了,調(diào)用完畢后也不用費心費力地擦屁股,不必老是提心吊膽有好事者追問:你擦了嗎,確定擦了?真的確定擦了?直接丟棄給環(huán)境降解處理,自然又環(huán)保,還有個好名聲叫專注領(lǐng)域邏輯。
一、 運行期環(huán)境就是一個餐館
1、 提供必要的服務(wù)
作為一個餐館,必須有廚師做飯我吃,必須有桌子和椅子。作為運行期環(huán)境同樣如此,我要發(fā)消息,你得提供我發(fā)消息的Service,我要獲取節(jié)點任務(wù),你得扔給我TaskService。
2、 提供獲取這些服務(wù)的統(tǒng)一方式
好吧,我不會親自到廚房告訴廚師我想吃什么(因為我擔(dān)心這樣一來我會吃不下去),我也不會親自到收銀臺給錢。這些服務(wù)有一個統(tǒng)一的獲取方式:服務(wù)員。我想吃什么和結(jié)賬,告訴服務(wù)員即可。關(guān)鍵是這一方式要統(tǒng)一,要足夠簡單。Spring最懶,把服務(wù)給你全部注入了,當(dāng)然你也可以握住BeanFactory的纖纖細手,一個一個的get。
3、 提供特定于我線程不安全的服務(wù)
我點了一盤魚香肉絲,隔壁也點了一盤魚香肉絲,結(jié)果服務(wù)員讓我們吃同一盤魚香肉絲。我立刻跳起來:靠,你們的服務(wù)不是線程安全的嗎?!Hibernate的Session正是屬于這么一種情況,需要環(huán)境進行隔離,我的唯一職責(zé)就是吃飯!我的領(lǐng)域邏輯是如何優(yōu)美的進餐!為此還要不斷重構(gòu)我吃飯的姿勢哩。
好不容易吃完飯,付完款,正準備離場。服務(wù)員風(fēng)度翩翩地走到我的身旁,我以為還有打折券供應(yīng),結(jié)果是:服務(wù)員小姐輕啟朱唇:先生,麻煩您把吃剩的盤子清洗完畢。
崩潰!
像數(shù)據(jù)庫連接的打開,關(guān)閉、事務(wù)的打開、提交等都屬于運行期環(huán)境應(yīng)該做的事情。
4、 其他的七七八八
雜事不少,例如統(tǒng)一的事件機制、權(quán)限攔截等等。
二、 jBPM4的運行期環(huán)境
好吧,先來看看如何建立jBPM4的運行期環(huán)境:
EnvironmentFactory environmentFactory = new DefaultEnvironmentFactory();

Environment environment = environmentFactory.openEnvironment();
try {
everything available in this block 
} finally {
environment.close();
}
兩個關(guān)鍵的類:EnvironmentFactory和Environment。
EnvironmentFactory是全局的,在整個應(yīng)用程序中保持一個實例即可。
Environment則是每次方法調(diào)用則要new一個。
看看Environment的主要方法:
public abstract Object get(String name);
public abstract <T> T get(Class<T> type);
是的,environment為我們的代碼提供所需要的服務(wù)類實例。
那么,如何獲得environment?
繼續(xù)看:
public static Environment getCurrent();
static,我喜歡也。方便、快捷,不管是在地上、車上還是房頂上,隨處都可調(diào)用。
那么,為什么Environment每次調(diào)用要new呢?
好吧,當(dāng)你需要獲取數(shù)據(jù)庫Session的時候,是不是每次都要new呢。Environment提供的服務(wù)里包括了非線程安全的數(shù)據(jù)庫操作服務(wù)。
三、 jBPM4運行期環(huán)境的實現(xiàn)
1、JbpmConfiguration
JbpmConfiguration是jBPM4里最重要的類,它是整個應(yīng)用程序的入口。它實現(xiàn)了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。
對應(yīng)于兩個IOC容器(WireContext)的配置文件。
作為EnvironmentFactory,JbpmConfiguration持有成品process-engine-context對應(yīng)的IOC容器(全局的)實例,持有半成品transaction-context的WireDefinition。當(dāng)調(diào)用openEnvironment方法時,JbpmConfiguration會new Environment,然后將process-engine-context IOC填充入environment,同時初始化transaction-context IOC,并將其也填充入environment。這樣通過environment就可以獲得所有所需要的服務(wù),包括全局的和非線程安全的服務(wù)實例。也就是environment透過IOC容器提供了查找各種服務(wù)的能力。
2、與線程綁定的environment
environment初始化之后,避免參數(shù)傳遞得一塌糊涂的方式就是將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()任意調(diào)用了。
哪里有壓迫,哪里就有放抗。
在environment.close()方法里:
Environment.popEnvironment();
OK,結(jié)束。
http://m.tkk7.com/ronghao 榮浩原創(chuàng),轉(zhuǎn)載請注明出處:)
posted on 2009-06-17 18:15
ronghao 閱讀(2823)
評論(5) 編輯 收藏 所屬分類:
JbpmSide