posts - 193,  comments - 520,  trackbacks - 0
           
               摘要: 使用Selenium測試showModalDialog模態(tài)對話框一直是一件困難的事情,本文提出一種hack解決的方法。  閱讀全文
          posted @ 2009-07-27 21:17 ronghao 閱讀(3596) | 評論 (0)編輯 收藏
                 現(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ù),配置如下:
          <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" />


          細心的你會發(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 />

           
          相關(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>


          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>


          攔截器換用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


          posted @ 2009-06-22 16:38 ronghao 閱讀(7381) | 評論 (7)編輯 收藏
                  萬物生長靠太陽,兒童的生長離不開土壤、空氣和水,當然,也離不開綠壩娘的調(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();
            }


          兩個關(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呢?
          好吧,當你需要獲取數(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。當調(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>>();


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


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

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

          Environment.popEnvironment();


          OK,結(jié)束。


          posted @ 2009-06-17 18:15 ronghao 閱讀(2820) | 評論 (5)編輯 收藏
          一、目前的情況
          目前我們要進行持續(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ù)器進行手工測試的習慣。
          posted @ 2009-05-26 23:13 ronghao 閱讀(1531) | 評論 (0)編輯 收藏
                 和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);


          很明顯,提供兩種從容器里獲取組件的方法,一種是通過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>


          可以看到配置文件被分為了兩部分,分別是: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ù)。


          posted @ 2009-05-07 18:43 ronghao 閱讀(3701) | 評論 (2)編輯 收藏
          僅列出標題
          共39頁: First 上一頁 10 11 12 13 14 15 16 17 18 下一頁 Last 
          <2025年6月>
          25262728293031
          1234567
          891011121314
          15161718192021
          22232425262728
          293012345

          關(guān)注工作流和企業(yè)業(yè)務(wù)流程改進?,F(xiàn)就職于ThoughtWorks。新浪微博:http://weibo.com/ronghao100

          常用鏈接

          留言簿(38)

          隨筆分類

          隨筆檔案

          文章分類

          文章檔案

          常去的網(wǎng)站

          搜索

          •  

          最新評論

          閱讀排行榜

          評論排行榜

          主站蜘蛛池模板: 隆化县| 英吉沙县| 永寿县| 昆明市| 凤庆县| 太和县| 北辰区| 石渠县| 安国市| 牡丹江市| 新龙县| 迁安市| 龙山县| 岳阳县| 西林县| 廊坊市| 柏乡县| 太和县| 调兵山市| 平塘县| 孝昌县| 寻乌县| 东城区| 阿克| 岑巩县| 澄迈县| 铜鼓县| 禄劝| 莒南县| 宁蒗| 安溪县| 炉霍县| 九江县| 清水县| 巢湖市| 莲花县| 随州市| 刚察县| 五台县| 祁东县| 湛江市|