摘要: 使用Selenium測試showModalDialog模態(tài)對話框一直是一件困難的事情,本文提出一種hack解決的方法。 閱讀全文
現(xiàn)在流行抱大腿,不過對眼光的要求也高。要不就如高也,即使四眼,一樣無用。對Java企業(yè)開發(fā)而言,Spring的腿則是一定要抱的。而所謂抱Spring的腿,無外乎三點:
一是通過Spring暴露出服務(wù),將服務(wù)配置到Spring的IOC容器里;
二是在自己的運行環(huán)境里訪問到Spring的IOC容器,能夠輕松使用Spring容器里所配置的服務(wù);
三是對于具有事務(wù)管理特性的項目來說,將事務(wù)管理與Spring的事務(wù)管理進行合并。
下面分別討論:
一、 通過Spring暴露服務(wù)
還記得在jBPM4的運行期環(huán)境里提到的JbpmConfiguration嗎?它是整個jBPM4的入口,并且是整個應(yīng)用獨此一份的。通過它可以獲取processEngine,并藉此獲得工作流引擎所提供的各種服務(wù):
ProcessEngine processEngine = new Configuration()
.buildProcessEngine();
RepositoryService repositoryService = processEngine.getRepositoryService();
ExecutionService executionService = processEngine.getExecutionService();
TaskService taskService = processEngine.getTaskService();
HistoryService historyService = processEngine.getHistoryService();
ManagementService managementService = processEngine.getManagementService();
通過Spring暴露這些服務(wù),配置如下:
細心的你會發(fā)現(xiàn),配置時使用了JbpmConfiguration 的子類SpringConfiguration。SpringConfiguration相比JbpmConfiguration有哪些增強呢,下面再講??傊F(xiàn)在,就可以使用Spring來獲取或注入這些Jbpm4所提供的服務(wù)了。
二、在environment里加入SpringContext
jBPM4的environment(運行期環(huán)境)提供Engine IOC(process-engine-context)和Transaction IOC(transaction-context)。要想在運行期方便地訪問到Spring里所配置的服務(wù),最直接的方法就是在environment里加入Spring IOC(applicationContext)的引用。
SpringConfiguration即是對JbpmConfiguration增強了對Spring IOC的一個引用。

SpringConfiguration是如何做到的呢?簡單,實現(xiàn)Spring的ApplicationContextAware接口,自動持有applicationContext,然后openEnvironment時將其加入environment。
SpringContext是對applicationContext的簡單封裝。
那么什么從Engine IOC移民到Spring IOC了呢?是的,最重要的就是Hibernate Session Factory。
在jbpm.cfg.xml的process-engine-context里干掉:
相關(guān)配置挪動至Spring配置文件。
三、 事務(wù)
哪里有數(shù)據(jù)庫操作,哪里就有事務(wù)。對于嵌入式工作流而言,最重要的集成就是事務(wù)的集成。這里先分析jBPM4的事務(wù)實現(xiàn),然后再介紹集成入Spring的事務(wù)實現(xiàn)。
1、 Command模式
jBPM4的邏輯實現(xiàn)采用了Command模式。

采用Command模式后,jBPM4對CommandService構(gòu)造攔截器(Interceptor)鏈,配置在jbpm.cfg.xml的process-engine-context里:
2、 原有的事務(wù)實現(xiàn)
jBPM4原有的事務(wù)通過StandardTransactionInterceptor實現(xiàn),在CommandService執(zhí)行Command之前打開事務(wù)(實際委派Hibernate的事務(wù)管理),完成后提交/回滾。

jBPM4的事務(wù)是基于Command的。
3、 集成入Spring的事務(wù)實現(xiàn)
Spring的事務(wù)是基于服務(wù)調(diào)用的。

使jBPM4使用Spring提供的事務(wù):
攔截器換用SpringTransactionInterceptor,SpringTransactionInterceptor從environment 提供的Spring IOC獲取PlatformTransactionManager,使用事務(wù)模板回調(diào)Command,事務(wù)傳播模式強制加入當前事務(wù)。
同時,對hibernate session的配置(jbpm.cfg.xml的transaction-context)強制從當前線程中獲取:
并干掉原有的事務(wù)實現(xiàn):
參考文檔:
http://www.slideshare.net/guest8d4bce/spring-integration-with-jbpm4
萬物生長靠太陽,兒童的生長離不開土壤、空氣和水,當然,也離不開綠壩娘的調(diào)教。應(yīng)用程序也是如此,離不開數(shù)據(jù)庫連接、事務(wù)、日志、消息等,這些,共同構(gòu)成了應(yīng)用程序的運行期環(huán)境。
理想中的環(huán)境是什么樣子的哩。好吧,一句話,召之即來,揮之即去,當需要某個服務(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)一方式
好吧,我不會親自到廚房告訴廚師我想吃什么(因為我擔心這樣一來我會吃不下去),我也不會親自到收銀臺給錢。這些服務(wù)有一個統(tǒng)一的獲取方式:服務(wù)員。我想吃什么和結(jié)賬,告訴服務(wù)員即可。關(guān)鍵是這一方式要統(tǒng)一,要足夠簡單。Spring最懶,把服務(wù)給你全部注入了,當然你也可以握住BeanFactory的纖纖細手,一個一個的get。
3、 提供特定于我線程不安全的服務(wù)
我點了一盤魚香肉絲,隔壁也點了一盤魚香肉絲,結(jié)果服務(wù)員讓我們吃同一盤魚香肉絲。我立刻跳起來:靠,你們的服務(wù)不是線程安全的嗎?!Hibernate的Session正是屬于這么一種情況,需要環(huán)境進行隔離,我的唯一職責就是吃飯!我的領(lǐng)域邏輯是如何優(yōu)美的進餐!為此還要不斷重構(gòu)我吃飯的姿勢哩。
好不容易吃完飯,付完款,正準備離場。服務(wù)員風度翩翩地走到我的身旁,我以為還有打折券供應(yīng),結(jié)果是:服務(wù)員小姐輕啟朱唇:先生,麻煩您把吃剩的盤子清洗完畢。
崩潰!
像數(shù)據(jù)庫連接的打開,關(guān)閉、事務(wù)的打開、提交等都屬于運行期環(huán)境應(yīng)該做的事情。
4、 其他的七七八八
雜事不少,例如統(tǒng)一的事件機制、權(quán)限攔截等等。
二、 jBPM4的運行期環(huán)境
好吧,先來看看如何建立jBPM4的運行期環(huán)境:
兩個關(guān)鍵的類:EnvironmentFactory和Environment。
EnvironmentFactory是全局的,在整個應(yīng)用程序中保持一個實例即可。
Environment則是每次方法調(diào)用則要new一個。
看看Environment的主要方法:
是的,environment為我們的代碼提供所需要的服務(wù)類實例。
那么,如何獲得environment?
繼續(xù)看:
static,我喜歡也。方便、快捷,不管是在地上、車上還是房頂上,隨處都可調(diào)用。
那么,為什么Environment每次調(diào)用要new呢?
好吧,當你需要獲取數(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總的配置文件,還是大概掃一下這個配置文件:
配置文件被分為了兩部分,分別是:process-engine-context和transaction-context。
對應(yīng)于兩個IOC容器(WireContext)的配置文件。
作為EnvironmentFactory,JbpmConfiguration持有成品process-engine-context對應(yīng)的IOC容器(全局的)實例,持有半成品transaction-context的WireDefinition。當調(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與線程綁定??碋nvironment的代碼:
是的,在openEnvironment時,有這么一行代碼:
這樣environment就與線程綁定了,可以通過Environment.getCurrent()任意調(diào)用了。
哪里有壓迫,哪里就有放抗。
在environment.close()方法里:
OK,結(jié)束。
一、目前的情況
目前我們要進行持續(xù)集成的對象是一個有著100人左右的開發(fā)團隊,他們開發(fā)著一套很龐大的系統(tǒng)。整個開發(fā)團隊劃分為多個開發(fā)小組進行協(xié)同開發(fā),每個開發(fā)小組負責2-3個模塊的開發(fā),實際這里的模塊已經(jīng)相當于一個中小型系統(tǒng)。各模塊所有的類都通過eclipse整體編譯在一起,直接放置在WEB-INF/classes下。本地是無法啟動整個系統(tǒng)的,需要耗費大量的資源。
二、碰到的問題
在了解具體情況之前,我們最初的想法是為整個產(chǎn)品做一個持續(xù)集成,但是很快就發(fā)現(xiàn)這一想法存在很多的問題:
1、整個產(chǎn)品每次構(gòu)建的時間會很長,這個時間包括代碼的編譯、啟動Weblogic,完成自動化測試,同時對服務(wù)器的硬件要求非常高
2、因為構(gòu)建時間長,所以如果本地構(gòu)建通過后再提交會嚴重影響開發(fā)效率,況且本地的硬件條件很可能啟動不了
3、如果本地不構(gòu)建提交,則由于開發(fā)人數(shù)眾多,構(gòu)建會非常不穩(wěn)定,會經(jīng)常處于失敗狀態(tài)。而構(gòu)建失敗會導(dǎo)致后續(xù)提交的阻塞。
4、作為一個100人的開發(fā)團隊,代碼提交會引發(fā)頻繁的服務(wù)器構(gòu)建,服務(wù)器無法負擔。
同時作為客戶,他們有這樣一種想法:敏捷開發(fā)是好的,但是不適合于大的項目和大的團隊。
最重要的問題集中在兩個方面:
1、啟動整個產(chǎn)品過于重量級(不包括自動化測試的情況下已經(jīng)如此)
2、如何不影響開發(fā)人員的頻繁提交
三、我們的想法
我們現(xiàn)在的想法是做多階段的持續(xù)集成(multi-stage CI)
可以參考這里http://www.ddj.com/development-tools/212201506
具體而言:
1、各個開發(fā)小組內(nèi)做小組內(nèi)的持續(xù)集成
2、開發(fā)小組間集成做整個產(chǎn)品的持續(xù)集成

大概:
1、每個開發(fā)小組一個分支,整個產(chǎn)品一條主線
2、在小組分支上搭建持續(xù)集成環(huán)境,小組內(nèi)的開發(fā)向該分支上提交,各個小組可以并發(fā)開發(fā),互不影響
3、小組完成一個完整的功能后,從主線更新合并代碼,本地構(gòu)建通過,提交,觸發(fā)整個產(chǎn)品的持續(xù)集成
為使小組內(nèi)持續(xù)集成構(gòu)建加快,小組內(nèi)盡量劃分清楚對其他模塊的依賴,不必要的模塊(這里的模塊包括基礎(chǔ)模塊,例如工作流模塊)不必加載。
同時推薦輕量級的web服務(wù)器例如Tomcat來完成小組內(nèi)的測試環(huán)境。需要啟動weblogic的情況或功能依賴過多的情況下,建議在產(chǎn)品持續(xù)集成時進行測試。
同時保留原有的啟動單獨測試服務(wù)器進行手工測試的習慣。
和Jbpm3一樣,Jbpm4實現(xiàn)了自己的IOC容器。以現(xiàn)在的眼光看來,應(yīng)用程序里一個IOC容器幾乎是居家必備的,否則,又要平白多出一坨一坨的工廠類和單態(tài)類來。
一、 Jbpm4 IOC容器介紹
IOC容器的目的是管理組件和實現(xiàn)組件之間的解耦。和Spring里的BeanFactory對應(yīng),Jbpm4里的接口是Context,具體實現(xiàn)則是WireContext。Context實際在Jbpm4里有更多的含義,它與Environment一起,共同構(gòu)成了代碼運行的運行期環(huán)境。在這個環(huán)境里可以獲取系統(tǒng)的組件,更為重要的是提供了數(shù)據(jù)庫連接(session)和事務(wù)(這個稍后會講)。
先來看看Context接口的核心方法:
很明顯,提供兩種從容器里獲取組件的方法,一種是通過name,一種是通過type。
對于IOC容器來說,一般情況下都會提供一種加載的方式,比如從xml文件進行加載、從資源文件進行加載。Jbpm4透過WireParser具備從xml加載的能力。
此外,WireContext通過一個Map緩存初始化后的組件。
二、 Jbpm4 IOC容器實現(xiàn)
容器的實現(xiàn)有五個關(guān)鍵類和接口,分別是:WireParser、Binding、Descriptor、WireDefinition和WireContext。

WireParser讀取xml文件,同時WireParser會加載一系列的Binding(默認從jbpm.wire.bindins.xml文件讀取加載)。
Binding負責根據(jù)xml里元素的tag將xml元素轉(zhuǎn)換為對應(yīng)的Descriptor。
Descriptor負責初始化對象。它們被添加到WireDefinition。
WireDefinition被WireParser返回給WireContext。WireContext創(chuàng)建對象時會訪問WireDefinition里的Descriptor,同時將初始化對象的任務(wù)委托給Descriptor自身。
需要注意的是:Jbpm4在初始化對象時有著四種策略,分別是:延遲創(chuàng)建和初始化、延遲創(chuàng)建和立刻初始化、立刻創(chuàng)建和延遲初始化、立刻創(chuàng)建和立刻初始化。
立刻創(chuàng)建:在WireContext創(chuàng)建完畢后對象就已經(jīng)創(chuàng)建。
延遲創(chuàng)建:調(diào)用WireContext的get方法獲取該對象時才創(chuàng)建該對象。
初始化:一般完成對象屬性的注入等操作。
三、 Jbpm4 IOC容器在Jbpm4里的應(yīng)用
IOC容器在Jbpm4里最重要的作用就是加載Jbpm的總的配置文件(默認是jbpm.cfg.xml),這也是整個Jbpm應(yīng)用的起點。大概掃一下這個配置文件:
可以看到配置文件被分為了兩部分,分別是:process-engine-context和transaction-context。在實際應(yīng)用中,它們分別對應(yīng)著兩個不同的WireContext:ProcessEngineContext和TransactionConext。ProcessEngineContext覆蓋了jbpm4里最重要的服務(wù)類,這些類是全局唯一的,當然,ProcessEngineContext也是獨此一份。本是同根生,命運各不同。TransactionConext則是在每次openEnvironment時重新創(chuàng)建,因為其包含了數(shù)據(jù)庫連接和事務(wù)。
貫穿于整個Jbpm4中,這兩個Context被壓到Environment里(Environment和線程綁定),在任何需要的地方都能提供一條龍的服務(wù)。于是,在很多領(lǐng)域類里,利用這些服務(wù)實現(xiàn)充血模型就是很順理成章的一件事了。
總結(jié): ProcessEngineContext給引擎領(lǐng)域模型提供全局的組件查找;TransactionConext提供數(shù)據(jù)庫相關(guān)服務(wù)。
一是通過Spring暴露出服務(wù),將服務(wù)配置到Spring的IOC容器里;
二是在自己的運行環(huán)境里訪問到Spring的IOC容器,能夠輕松使用Spring容器里所配置的服務(wù);
三是對于具有事務(wù)管理特性的項目來說,將事務(wù)管理與Spring的事務(wù)管理進行合并。
下面分別討論:
一、 通過Spring暴露服務(wù)
還記得在jBPM4的運行期環(huán)境里提到的JbpmConfiguration嗎?它是整個jBPM4的入口,并且是整個應(yīng)用獨此一份的。通過它可以獲取processEngine,并藉此獲得工作流引擎所提供的各種服務(wù):
ProcessEngine processEngine = new Configuration()
.buildProcessEngine();
RepositoryService repositoryService = processEngine.getRepositoryService();
ExecutionService executionService = processEngine.getExecutionService();
TaskService taskService = processEngine.getTaskService();
HistoryService historyService = processEngine.getHistoryService();
ManagementService managementService = processEngine.getManagementService();
通過Spring暴露這些服務(wù),配置如下:
<bean id="jbpmConfiguration" class="org.jbpm.pvm.internal.cfg.SpringConfiguration">
<constructor-arg value="be/inze/spring/demo/jbpm.cfg.xml" />
</bean>
<bean id="processEngine" factory-bean="jbpmConfiguration" factory-method="buildProcessEngine" />
<bean id="repositoryService" factory-bean="processEngine" factory-method="getRepositoryService" />
<bean id="executionService" factory-bean="processEngine" factory-method="getExecutionService" />
<constructor-arg value="be/inze/spring/demo/jbpm.cfg.xml" />
</bean>
<bean id="processEngine" factory-bean="jbpmConfiguration" factory-method="buildProcessEngine" />
<bean id="repositoryService" factory-bean="processEngine" factory-method="getRepositoryService" />
<bean id="executionService" factory-bean="processEngine" factory-method="getExecutionService" />
細心的你會發(fā)現(xiàn),配置時使用了JbpmConfiguration 的子類SpringConfiguration。SpringConfiguration相比JbpmConfiguration有哪些增強呢,下面再講??傊F(xiàn)在,就可以使用Spring來獲取或注入這些Jbpm4所提供的服務(wù)了。
二、在environment里加入SpringContext
jBPM4的environment(運行期環(huán)境)提供Engine IOC(process-engine-context)和Transaction IOC(transaction-context)。要想在運行期方便地訪問到Spring里所配置的服務(wù),最直接的方法就是在environment里加入Spring IOC(applicationContext)的引用。
SpringConfiguration即是對JbpmConfiguration增強了對Spring IOC的一個引用。

SpringConfiguration是如何做到的呢?簡單,實現(xiàn)Spring的ApplicationContextAware接口,自動持有applicationContext,然后openEnvironment時將其加入environment。
environment.setContext(new SpringContext(applicationContext));
SpringContext是對applicationContext的簡單封裝。
那么什么從Engine IOC移民到Spring IOC了呢?是的,最重要的就是Hibernate Session Factory。
在jbpm.cfg.xml的process-engine-context里干掉:
<hibernate-configuration>
<cfg resource="jbpm.hibernate.cfg.xml" />
</hibernate-configuration>
<hibernate-session-factory />
<cfg resource="jbpm.hibernate.cfg.xml" />
</hibernate-configuration>
<hibernate-session-factory />
相關(guān)配置挪動至Spring配置文件。
三、 事務(wù)
哪里有數(shù)據(jù)庫操作,哪里就有事務(wù)。對于嵌入式工作流而言,最重要的集成就是事務(wù)的集成。這里先分析jBPM4的事務(wù)實現(xiàn),然后再介紹集成入Spring的事務(wù)實現(xiàn)。
1、 Command模式
jBPM4的邏輯實現(xiàn)采用了Command模式。

采用Command模式后,jBPM4對CommandService構(gòu)造攔截器(Interceptor)鏈,配置在jbpm.cfg.xml的process-engine-context里:
<command-service>
<retry-interceptor />
<environment-interceptor />
<standard-transaction-interceptor />
</command-service>
<retry-interceptor />
<environment-interceptor />
<standard-transaction-interceptor />
</command-service>
2、 原有的事務(wù)實現(xiàn)
jBPM4原有的事務(wù)通過StandardTransactionInterceptor實現(xiàn),在CommandService執(zhí)行Command之前打開事務(wù)(實際委派Hibernate的事務(wù)管理),完成后提交/回滾。

jBPM4的事務(wù)是基于Command的。
3、 集成入Spring的事務(wù)實現(xiàn)
Spring的事務(wù)是基于服務(wù)調(diào)用的。

使jBPM4使用Spring提供的事務(wù):
<command-service>
<retry-interceptor />
<environment-interceptor />
<spring-transaction-interceptor current="true" />
</command-service>
<retry-interceptor />
<environment-interceptor />
<spring-transaction-interceptor current="true" />
</command-service>
攔截器換用SpringTransactionInterceptor,SpringTransactionInterceptor從environment 提供的Spring IOC獲取PlatformTransactionManager,使用事務(wù)模板回調(diào)Command,事務(wù)傳播模式強制加入當前事務(wù)。
同時,對hibernate session的配置(jbpm.cfg.xml的transaction-context)強制從當前線程中獲取:
<hibernate-session current="true"/>
并干掉原有的事務(wù)實現(xiàn):
<transaction />
參考文檔:
http://www.slideshare.net/guest8d4bce/spring-integration-with-jbpm4
萬物生長靠太陽,兒童的生長離不開土壤、空氣和水,當然,也離不開綠壩娘的調(diào)教。應(yīng)用程序也是如此,離不開數(shù)據(jù)庫連接、事務(wù)、日志、消息等,這些,共同構(gòu)成了應(yīng)用程序的運行期環(huán)境。
理想中的環(huán)境是什么樣子的哩。好吧,一句話,召之即來,揮之即去,當需要某個服務(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)一方式
好吧,我不會親自到廚房告訴廚師我想吃什么(因為我擔心這樣一來我會吃不下去),我也不會親自到收銀臺給錢。這些服務(wù)有一個統(tǒng)一的獲取方式:服務(wù)員。我想吃什么和結(jié)賬,告訴服務(wù)員即可。關(guān)鍵是這一方式要統(tǒng)一,要足夠簡單。Spring最懶,把服務(wù)給你全部注入了,當然你也可以握住BeanFactory的纖纖細手,一個一個的get。
3、 提供特定于我線程不安全的服務(wù)
我點了一盤魚香肉絲,隔壁也點了一盤魚香肉絲,結(jié)果服務(wù)員讓我們吃同一盤魚香肉絲。我立刻跳起來:靠,你們的服務(wù)不是線程安全的嗎?!Hibernate的Session正是屬于這么一種情況,需要環(huán)境進行隔離,我的唯一職責就是吃飯!我的領(lǐng)域邏輯是如何優(yōu)美的進餐!為此還要不斷重構(gòu)我吃飯的姿勢哩。
好不容易吃完飯,付完款,正準備離場。服務(wù)員風度翩翩地走到我的身旁,我以為還有打折券供應(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();
}

Environment environment = environmentFactory.openEnvironment();
try {


} 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);
public abstract <T> T get(Class<T> type);
是的,environment為我們的代碼提供所需要的服務(wù)類實例。
那么,如何獲得environment?
繼續(xù)看:
public static Environment getCurrent();
static,我喜歡也。方便、快捷,不管是在地上、車上還是房頂上,隨處都可調(diào)用。
那么,為什么Environment每次調(diào)用要new呢?
好吧,當你需要獲取數(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>
<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。當調(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與線程綁定??碋nvironment的代碼:
static ThreadLocal<Environment> currentEnvironment = new ThreadLocal<Environment>();
static ThreadLocal<Stack<Environment>> currentEnvironmentStack = new ThreadLocal<Stack<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é)束。
一、目前的情況
目前我們要進行持續(xù)集成的對象是一個有著100人左右的開發(fā)團隊,他們開發(fā)著一套很龐大的系統(tǒng)。整個開發(fā)團隊劃分為多個開發(fā)小組進行協(xié)同開發(fā),每個開發(fā)小組負責2-3個模塊的開發(fā),實際這里的模塊已經(jīng)相當于一個中小型系統(tǒng)。各模塊所有的類都通過eclipse整體編譯在一起,直接放置在WEB-INF/classes下。本地是無法啟動整個系統(tǒng)的,需要耗費大量的資源。
二、碰到的問題
在了解具體情況之前,我們最初的想法是為整個產(chǎn)品做一個持續(xù)集成,但是很快就發(fā)現(xiàn)這一想法存在很多的問題:
1、整個產(chǎn)品每次構(gòu)建的時間會很長,這個時間包括代碼的編譯、啟動Weblogic,完成自動化測試,同時對服務(wù)器的硬件要求非常高
2、因為構(gòu)建時間長,所以如果本地構(gòu)建通過后再提交會嚴重影響開發(fā)效率,況且本地的硬件條件很可能啟動不了
3、如果本地不構(gòu)建提交,則由于開發(fā)人數(shù)眾多,構(gòu)建會非常不穩(wěn)定,會經(jīng)常處于失敗狀態(tài)。而構(gòu)建失敗會導(dǎo)致后續(xù)提交的阻塞。
4、作為一個100人的開發(fā)團隊,代碼提交會引發(fā)頻繁的服務(wù)器構(gòu)建,服務(wù)器無法負擔。
同時作為客戶,他們有這樣一種想法:敏捷開發(fā)是好的,但是不適合于大的項目和大的團隊。
最重要的問題集中在兩個方面:
1、啟動整個產(chǎn)品過于重量級(不包括自動化測試的情況下已經(jīng)如此)
2、如何不影響開發(fā)人員的頻繁提交
三、我們的想法
我們現(xiàn)在的想法是做多階段的持續(xù)集成(multi-stage CI)
可以參考這里http://www.ddj.com/development-tools/212201506
具體而言:
1、各個開發(fā)小組內(nèi)做小組內(nèi)的持續(xù)集成
2、開發(fā)小組間集成做整個產(chǎn)品的持續(xù)集成

大概:
1、每個開發(fā)小組一個分支,整個產(chǎn)品一條主線
2、在小組分支上搭建持續(xù)集成環(huán)境,小組內(nèi)的開發(fā)向該分支上提交,各個小組可以并發(fā)開發(fā),互不影響
3、小組完成一個完整的功能后,從主線更新合并代碼,本地構(gòu)建通過,提交,觸發(fā)整個產(chǎn)品的持續(xù)集成
為使小組內(nèi)持續(xù)集成構(gòu)建加快,小組內(nèi)盡量劃分清楚對其他模塊的依賴,不必要的模塊(這里的模塊包括基礎(chǔ)模塊,例如工作流模塊)不必加載。
同時推薦輕量級的web服務(wù)器例如Tomcat來完成小組內(nèi)的測試環(huán)境。需要啟動weblogic的情況或功能依賴過多的情況下,建議在產(chǎn)品持續(xù)集成時進行測試。
同時保留原有的啟動單獨測試服務(wù)器進行手工測試的習慣。
和Jbpm3一樣,Jbpm4實現(xiàn)了自己的IOC容器。以現(xiàn)在的眼光看來,應(yīng)用程序里一個IOC容器幾乎是居家必備的,否則,又要平白多出一坨一坨的工廠類和單態(tài)類來。
一、 Jbpm4 IOC容器介紹
IOC容器的目的是管理組件和實現(xiàn)組件之間的解耦。和Spring里的BeanFactory對應(yīng),Jbpm4里的接口是Context,具體實現(xiàn)則是WireContext。Context實際在Jbpm4里有更多的含義,它與Environment一起,共同構(gòu)成了代碼運行的運行期環(huán)境。在這個環(huán)境里可以獲取系統(tǒng)的組件,更為重要的是提供了數(shù)據(jù)庫連接(session)和事務(wù)(這個稍后會講)。
先來看看Context接口的核心方法:
Object get(String key);
<T> T get(Class<T> type);
<T> T get(Class<T> type);
很明顯,提供兩種從容器里獲取組件的方法,一種是通過name,一種是通過type。
對于IOC容器來說,一般情況下都會提供一種加載的方式,比如從xml文件進行加載、從資源文件進行加載。Jbpm4透過WireParser具備從xml加載的能力。
此外,WireContext通過一個Map緩存初始化后的組件。
二、 Jbpm4 IOC容器實現(xiàn)
容器的實現(xiàn)有五個關(guān)鍵類和接口,分別是:WireParser、Binding、Descriptor、WireDefinition和WireContext。

WireParser讀取xml文件,同時WireParser會加載一系列的Binding(默認從jbpm.wire.bindins.xml文件讀取加載)。
Binding負責根據(jù)xml里元素的tag將xml元素轉(zhuǎn)換為對應(yīng)的Descriptor。
Descriptor負責初始化對象。它們被添加到WireDefinition。
WireDefinition被WireParser返回給WireContext。WireContext創(chuàng)建對象時會訪問WireDefinition里的Descriptor,同時將初始化對象的任務(wù)委托給Descriptor自身。
需要注意的是:Jbpm4在初始化對象時有著四種策略,分別是:延遲創(chuàng)建和初始化、延遲創(chuàng)建和立刻初始化、立刻創(chuàng)建和延遲初始化、立刻創(chuàng)建和立刻初始化。
立刻創(chuàng)建:在WireContext創(chuàng)建完畢后對象就已經(jīng)創(chuàng)建。
延遲創(chuàng)建:調(diào)用WireContext的get方法獲取該對象時才創(chuàng)建該對象。
初始化:一般完成對象屬性的注入等操作。
三、 Jbpm4 IOC容器在Jbpm4里的應(yīng)用
IOC容器在Jbpm4里最重要的作用就是加載Jbpm的總的配置文件(默認是jbpm.cfg.xml),這也是整個Jbpm應(yīng)用的起點。大概掃一下這個配置文件:
<?xml version="1.0" encoding="UTF-8"?>
<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>
<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)用中,它們分別對應(yīng)著兩個不同的WireContext:ProcessEngineContext和TransactionConext。ProcessEngineContext覆蓋了jbpm4里最重要的服務(wù)類,這些類是全局唯一的,當然,ProcessEngineContext也是獨此一份。本是同根生,命運各不同。TransactionConext則是在每次openEnvironment時重新創(chuàng)建,因為其包含了數(shù)據(jù)庫連接和事務(wù)。
貫穿于整個Jbpm4中,這兩個Context被壓到Environment里(Environment和線程綁定),在任何需要的地方都能提供一條龍的服務(wù)。于是,在很多領(lǐng)域類里,利用這些服務(wù)實現(xiàn)充血模型就是很順理成章的一件事了。
總結(jié): ProcessEngineContext給引擎領(lǐng)域模型提供全局的組件查找;TransactionConext提供數(shù)據(jù)庫相關(guān)服務(wù)。
| |||||||||
日 | 一 | 二 | 三 | 四 | 五 | 六 | |||
---|---|---|---|---|---|---|---|---|---|
25 | 26 | 27 | 28 | 29 | 30 | 31 | |||
1 | 2 | 3 | 4 | 5 | 6 | 7 | |||
8 | 9 | 10 | 11 | 12 | 13 | 14 | |||
15 | 16 | 17 | 18 | 19 | 20 | 21 | |||
22 | 23 | 24 | 25 | 26 | 27 | 28 | |||
29 | 30 | 1 | 2 | 3 | 4 | 5 |
關(guān)注工作流和企業(yè)業(yè)務(wù)流程改進?,F(xiàn)就職于ThoughtWorks。新浪微博:http://weibo.com/ronghao100
常用鏈接
留言簿(38)
隨筆分類
- ajax相關(guān)(9)
- cms(7)
- Head First Process-深入淺出流程(15)
- j2se基礎(chǔ)(6)
- JbpmSide(6)
- OOA/OOD(4)
- SOA、BPM(26)
- 工作日志(24)
- 工作流jbpm3(10)
- 張小慶,在路上(42)
- 心情小站(24)
- 權(quán)限相關(guān)(12)
- 表現(xiàn)層相關(guān)(4)
- 轉(zhuǎn)載(4)
隨筆檔案
- 2013年8月 (1)
- 2012年12月 (1)
- 2012年1月 (3)
- 2011年12月 (2)
- 2011年11月 (2)
- 2011年10月 (3)
- 2011年9月 (3)
- 2011年8月 (7)
- 2011年7月 (4)
- 2011年6月 (3)
- 2011年5月 (5)
- 2011年4月 (6)
- 2011年3月 (4)
- 2011年2月 (2)
- 2010年9月 (1)
- 2010年6月 (1)
- 2010年5月 (1)
- 2010年3月 (4)
- 2010年1月 (2)
- 2009年11月 (5)
- 2009年10月 (4)
- 2009年9月 (1)
- 2009年7月 (1)
- 2009年6月 (2)
- 2009年5月 (2)
- 2009年4月 (1)
- 2009年3月 (4)
- 2009年2月 (2)
- 2008年12月 (1)
- 2008年11月 (1)
- 2008年10月 (1)
- 2008年9月 (2)
- 2008年8月 (2)
- 2008年7月 (2)
- 2008年6月 (3)
- 2008年5月 (4)
- 2008年4月 (1)
- 2008年3月 (2)
- 2008年2月 (2)
- 2008年1月 (4)
- 2007年11月 (3)
- 2007年10月 (3)
- 2007年9月 (2)
- 2007年8月 (4)
- 2007年7月 (1)
- 2007年6月 (12)
- 2007年5月 (2)
- 2007年4月 (1)
- 2007年3月 (8)
- 2007年2月 (6)
- 2007年1月 (4)
- 2006年12月 (4)
- 2006年11月 (3)
- 2006年10月 (1)
- 2006年8月 (2)
- 2006年7月 (3)
- 2006年6月 (3)
- 2006年4月 (1)
- 2006年3月 (2)
- 2006年2月 (2)
- 2006年1月 (4)
- 2005年12月 (7)
- 2005年11月 (12)
文章分類
文章檔案
常去的網(wǎng)站
搜索
最新評論

- 1.?re: 使用Handler來增強Web服務(wù)的功能
- asdfasfd
- --ads
- 2.?re: 使用solr搭建你的全文檢索
-
@木哥哥
你的分詞器用的是什么啊?mmseg貌似可以的 - --陳冠馳
- 3.?re: 使用solr搭建你的全文檢索
-
@marten這是你的solr的schame.xml配置文件有問題。好好檢查下你的配置文件里面的字段什么的配置對著沒
- --陳冠馳
- 4.?re: 討論一下你覺得一個工作流產(chǎn)品好的標準
- 評論內(nèi)容較長,點擊標題查看
- --深圳非凡信息技術(shù)有限公司
- 5.?re: DisplayTag應(yīng)用
- name="test"從哪里來的,千篇一律的到處使用test卻沒有test的定義,sb
- --qige