陳景霞,李 萌
CHEN Jing-xia,LI Meng
(陜西科技大學 電氣與信息工程學院,西安 710021)
隨著互聯網技術的發展和普及,越來越多的復雜動態空間非線性分析系統的軟件工具開始使用基于Web的網絡平臺實現用戶界面、科學分析、信息處理、分發數據結果、行業專家跨地域信息交換和共享等功能。其中,對非線性分析模擬系統軟件基于web平臺的實時訪問正成為網絡應用系統中很重要的一部分。飛速發展的網絡硬件和軟件技術為web應用開發提供了更多的選擇方案。因而,合理的選擇和開發web平臺對于非線性分析系統及其應用顯得越來越重要。Web開發現階段涌現出了許多優秀的開源框架,將web開發提升到一個更高的水平[1]。但是在某些情況下,開源框架并不能直接為常見的問題提供解決辦法,開發者往往需要在開源框架基礎上構建自己的開發框架。在分析現有幾種開源框架特性和用法的基礎上,本文研究一種新型的基于J2EE的開源框架組合,并定義了加強幾種開源框架協同工作的技術體系和方法,有效的提高了web系統定制開發與集成的效率。
開發web應用項目時,通常有一些共同的設計問題需要考慮,如表現層、業務層、數據訪問層的設計以及系統測試等等,甚至圍繞個別獨特功能性需求也會使用一些共同的設計模式,這就不可避免的會出現開發框架與設計模式的重用[2]。本文描述一種定制的J2EE框架(Customized J2EE Web-based Framework,簡稱CJW架構),它能夠識別一般web應用開發的共同設計要素,提供從用戶表現層到數據層一整套web應用開發模式、工具和實踐方法。該框架基于Struts、Spring、Hibernate和JUnit等開源框架和工具進行構建和開發,可以進行靈活定制以滿足各種Web項目的開發需求。
Web應用程序的設計需要考慮諸如表現層、業務邏輯、數據存取和安全性等多個層面的因素,將不同的設計任務分解到不同的層次能夠有效降低系統代碼的耦合度,提高系統的可維護性,也便于采用好的設計模式,為特定設計層選擇專用的開發工具和技術。同時,將一個項目進行層次劃分會導致各層之間存在相互依賴。例如,一個簡單的包含數據輸入和查詢功能的用例,只有將表現層的用戶界面、查詢邏輯代碼和數據庫存取代碼結合起來才能實現所需要的功能,因此,需要定義一種好的策略來管理各層之間的依賴關系。
本文開發的CJW架構使用Spring框架將設計模式、可復用的代碼和配置文件結合起來[3],通過控制反轉(IOC)技術實現系統各層的松耦合,通過IOC容器管理各個對象之間的依賴關系,能夠有效避免硬性編碼造成的耦合過于緊密的狀況;使用依賴注入(Dependency Injection,DI)技術實現邏輯相關代碼的松耦合,依賴注入是由框架或容器將被調用類注入給調用對象,以此來消除對象和被調用類之間的依賴關系,具體實現形式包括構造函數注入,設值方法注入和接口注入[4]。同時,Spring框架提供的面向切面編程(AOP)方法,通過方法攔截可以輕松的實現諸如事務管理、日志管理、性能監控、安全檢測等關注點編程。方法攔截是Spring AOP的一個重要概念,通過JDK動態代理機制實現,使開發人員能夠更加專注于業務邏輯的實現[5]。
CJW架構包括兩個部分:代碼和配置信息。代碼在特別的應用層中負責解決某個特定的問題,如與數據庫的連接和交互、屏幕端的數據顯示等。而配置文件則負責將應用的各個層連接起來。將配置信息從代碼中分離出來不僅可以單獨對配置信息進行管理,也可以靈活地將不同的配置信息應用于相同的底層代碼。例如,一個數據庫訪問對象(DAO)能夠使用JDBC接口通過某個數據源連接數據庫,但它并不清楚這個數據源的連接信息究竟是從JNDI上下文中獲取的,還是通過數據庫驅動管理器獲取的,該數據源可以連接遠程數據庫,也可以連接本地數據庫。無論這個數據源如何定義,DAO都能以相同的方式調用它。同樣,一個服務對象(Service)可以用相同的模式調用一個DAO而不必知道該DAO是使用Hibernate或是Web服務實現,還是直接通過JDBC實現的。
CJW架構通過一組XML文件描述、管理整個應用的上下文配置信息,這些配置文件的邏輯集合就構成了整個應用的配置集合。在基于J2EE的企業級應用開發過程中,系統框架對數據源和JNDI等外部資源的使用通常在標準配置中定義,但可能會遇到如下問題:1)數據庫的數據還沒有被完全加載時,開發人員想要測試其中某種類型數據的顯示結果,導致這部分測試工作無法進行。2)某些Service服務類或DAO還沒有完成開發,那么與此相關的代碼集成和測試就會阻礙整個開發的進程。
針對上述問題,本文提出的CJW架構采用一種專門面向開發的配置集合代替傳統的配置方法,使開發人員不必擔心那些與緊迫開發需求無關的外部系統是否可用。CJW架構定義了兩個配置集合:默認配置和模塊配置,基于這兩種配置和特定的項目需求,開發者也可以增加額外的配置文件來定制自己的應用架構。默認配置使用JNDI定義的數據源與開發數據庫建立連接,并且調用已經完全開發好的Service和DAO對象。而靈活的開發環境則是由模塊配置集合搭建的,這些配置集合具備以下功能:1)可以連接本地數據庫,或是通過DriverManagerDataSource驅動程序管理器連接開發數據庫;2)使用Spring框架的DataSourceTransactionManager進行本地事務管理;3)調用完全開發好的應用Service和DAO對象;4)使整個基于Spring框架的應用上下文能夠在應用服務器外部進行完整的運行和測試。
CJW架構的配置集合包括service和Web兩部分:Service部分定義各種服務接口和實現(即services)、數據庫訪問對象接口和實現(即DAOs)以及服務和整合層用到的各種資源;Web部分主要為表現層定義各種顯示組件。這兩部分對于一個完整的配置集合缺一不可。CJW架構的配置集合由Spring框架的beanRefContext.xml和applicationContextMapping.properties等配置文件化合而成。其中,beanRefContext.xml文件定義了所有配置集合的services,它通常位于項目的src/config目錄下,不同配置集合共享的應用上下文文件也位于這個目錄下。此外,每一個模塊配置集合都有自己的子目錄,其下包含自己的相關文件。在XML文件中使用 配置好上述CJW架構之后,接下來的編碼與整體構造工作包括:開發相應的用戶端界面;設計相應的Action類、ActionForm類和validation.xml輸入校驗組件;設計服務層service接口和實現類;設計數據訪問層DAO接口和實現類;管理各個類之間的依賴關系。在開發一個實際用例時,弄清楚上述這些類的詳細需求和彼此之間的依賴關系非常重要。 測試應該是整個開發過程中不可或缺的一部分。對于本文提出的CJW框架而言,單元測試是指基于JUnit框架[6]實現的對服務層或整合層中每個類所進行的測試,其目的是確保類中封裝的方法結合其它組件運行時能實現預期的功能。表現層的Action類通常不需要進行單元測試。與單元測試不同,集成測試需要代碼之間的相互依賴,其目的是確保不同開發者開發的類聯合運行時能實現預期的功能。而功能測試的重點則要針對每種可能出現的情況設計測試數據,并用這些數據測試應用的功能性,包括使用不同的數據對服務層的類進行功能測試,或者用真實的依賴關系對用戶界面層進行功能測試。 為了進行不同類型的測試,首先要確保開發的應用程序是可測試的,一個可測試的應用需要具備以下基本特征:1)系統開發要便于進行單元測試和集成測試,應該在沒有必須數據源或創建隊列的情況下就能進行單元測試,測試時應該能夠模擬代碼之間的依賴性。2)為了進行功能測試,應用設計要便于模擬各種可能的測試情況。3)便于在應用的整個生命周期反復的運行所有測試。4)測試代碼和應用代碼劃分清楚,互不干擾。將表現層、服務層和數據訪問層的設計相分離的良好系統架構,對于設計一個可測試的應用非常重要。本文開發的CJW架構將更有利于設計出可測試的應用系統:首先提供了測試模板類有助于創建單元測試;整個應用的配置更加靈活便于適應各種測試需要;能夠像任何JUnit測試那樣進行單元測試,簡單方便。CJW架構中還專門開發了默認的Ant編譯腳本,在生成EAR文件時可以被調用對系統進行單元測試,也可以單獨運行完成單元測試。 本文開發的CJW架構使用Struts框架和JavaScript技術實現系統的表現層邏輯,處理應用程序與客戶端的交互問題,并且為項目的擴展提供附加的技術支持。應用Struts框架進行開發時,首先要在web.xml文件中建立Action Servlet,然后在struts-config.xml文件中設置action mappings、formbeans以及頁面重定向;最后在validation.xml文件中設置數據校驗規則,對用戶輸入數據的合法性進行檢查。為了使開發者不必頻繁的編輯struts-config.xml或者validation.xml,CJW架構對上述方法進行了改進,使開發者在Action類和ActionForm類中應用XDoclet注釋進行配置說明,注釋信息在運行Ant腳本時能自動轉換成strutsconfig.xml和validation.xml配置文件。 CJW架構設計了一個默認的Action模板類,使表現層的設計達到以下目標:1)每個JSP頁面都對應一個唯一的Action處理類,一個Action類負責對一個單一的web頁面進行處理。2)在Action類和ActionForm類中使用XDoclet注釋對類之間的依賴關系及合法性校驗規則進行說明。3)盡量避免或減少使用session會話對象,否則會降低系統的可伸縮性。然后,遵循以下步驟開發一個web頁面:1)創建一個新的JSP頁面,其中包含一個名為“actionType”的默認隱藏域,用來表示用戶希望對該頁面進行的處理類型。2)通過繼承Action模板類創建一個新的Action類,必須說明該Action類與ActionForm中“actionType”隱藏域所表示處理方法的對應關系,然后在Spring配置文件中聲明訪問這個Action類的條件。3)創建一個新的ActionForm類并使用XDoclet注釋說明表單數據的有效性校驗規則。一旦JSP、Action以及ActionForm創建完成,必須運行Ant腳本重新生成struts-config.xml配置文件。 基于CJW架構開發的應用程序支持直接使用JDBC和Hibernate框架與關系數據庫建立持久連接和數據通信,在必要的Spring上下文文件中進行配置即可。直接使用JDBC訪問數據庫的DAO類必須繼承Spring框架的JdbcDaoSupport.java類;使用Hibernate框架訪問數據庫的DAO類必須繼承Spring框架的HibernateDaoSupport.java類。 CJW架構使用Spring框架來維護代碼之間的依賴性。例如,Action類和ActionForm之間的依賴性在struts-config.xml文件中配置,而Service類和DAO類之間的依賴性在Spring應用上下文文件applicationContext.xml中配置。在同一個開發小組中這些配置文件被所有開發者共享,這可能導致配置文件的版本沖突。CJW架構提供了一種新型有效的方法,即XDoclet注釋來說明類之間的依賴性,這種注釋的方法不僅簡化了系統的配置,而且能有效避免配置文件的版本沖突。 本文開發的CJW架構提出使用簡單的JavaBeans(即POJOs)實現業務邏輯,而業務邏輯必須以接口的形式進行聲明,所有的Service實現類必須實現一個或多個業務接口,并且建議當服務層出現業務邏輯錯誤時能拋出定制的異常。CJW架構采用基于Spring框架的面向方面編程(AOP)的方式實現事務管理。同時,CJW架構很好地將面向服務用戶的部署接口與面向業務邏輯的服務接口相分離。部署接口是一種可以用Web服務定義語言(WSDL)描述的外部接口,這類接口的實現類通常必須將請求委托給實現服務接口的類。服務接口則是表示業務邏輯的Java接口,這樣能確保所有的業務邏輯在業務層的一個固定類中進行定義和維護。部署接口中通常會包含服務接口中的若干方法。 Apache Axis 1.2.4框架是目前流行的標準Web服務架構。開發Web服務有兩種不同的方法[7]:契約在前和契約在后,這兩者之間的區別在于WSDL是在編碼之前創建的,還是從寫好的代碼中產生的。如果服務的消費者和提供者都是使用各自不同技術(如.NET或Java)去實現Web服務的供應商,那就適合采用契約在前的方法開發Web 服務[10]。 CJW架構在業務邏輯中間層采用相關技術實現與數據庫、Web服務等外部資源的整合,其整合的目標在于:1)將基于JDBC或Hibernate的數據庫訪問操作封裝在數據訪問對象(DAO)中;2)盡可能簡化對Web服務的調用;3)所有外部數據向應用域對象的轉換操作應該限制在這一層進行;4)這一層中的單元測試類要設計簡單且易于執行。 CJW架構支持使用Spring框架的JdbcTemplate和HibernateTemplate模板類訪問關系數據庫。當直接使用JDBC訪問關系數據庫時,應用中的DAO對象可以繼承Spring框架的JdbcDaoSupport類,該類管理著訪問數據庫要用到的各種資源(例如預處理語句對象PreparedStatement等)。CJW架構可以通過應用配置文件將數據源插入到DAO類中。當使用Hibernate時,同樣可以通過應用配置文件將Hibernate的SessionFactory注入到DAO類中。 本文開發的CJW框架結構也明確定義了應用開發小組的人員角色及各自的作用:1)前端開發者主要負責設計開發JSP頁面、Action/ActionForm類以及對外的Web服務接口;2)中間服務層的開發者則負責開發各種應用服務,并將這些服務相關的應用模塊進行集成;3)底層開發者主要負責開發各種DAO類以及密集型Web服務。各個角色之間的相互配合對整個應用開發的成敗將起決定性的作用。 開發中經常會遇到的一個基本問題是當代碼相關的組件不可用時如何對代碼進行開發和集成。針對這個問題,CJW架構提供了一種以聲明方式注入“模擬對象”的結構,這些“模擬對象”隨著開發周期的推進將被實際的對象所取代。同時,編寫、運行JUnit測試也使得測試工作成為開發過程不可缺少的一部分,CJW架構重點測試應用的服務以及服務之間的依賴關系。應用程序以EAR企業歸檔文件的形式進行部署,EAR文件可以通過手工運行Ant腳本生成,也可以通過調度程序周期性的執行Ant腳本生成。建議在生成EAR文件之前完成所有的JUnit測試。 本文提出了一個基于J2EE的web信息系統開發架構CJW,重點論述了開發J2EE項目應該考慮的系統架構、相關技術和開發步驟。該架構取自于真實的項目經驗,目的是幫助開發者們以此為參考,更快、更好的構建J2EE系統并設計出滿足自己需求的定制框架。不過,這只是冰山一角,只此一篇論文并不能描述清楚J2EE的技術細節以及J2EE在科學和企業應用中的潛在影響,尤其是在基于Web的非線性分析模擬軟件方面,作者將進一步研究該CJW架構在此方面的應用和優化。 [1] 李成嚴,馮慧靈. 基于開源技術的Web應用架構研究[J].計算機技術與發展,2009,19(8): 27-30. [2] 曾亮,齊歡,王小平等.基于J2EE核心模式的組合Web框架研究[J]. 華中科技大學學報(自然科學版),2007,35(6):43-46. [3] 袁華強,王亞強,朱君. 利用J2EE輕量級框架構建Web應用研究[J]. 計算機工程與設計,2007,28(1): 22-25. [4] The Spring Framework official website: http://www.springframework.org/. [5] Martin Fowler discusses details of the dependency injection pattern and how spring injects dependen cies: http://www.martinfowler.com/. [6] JUnit framework: http://www.junit.org/. [7] A.S. Boranbayev,Optimal methods for java web services,News of the National Academy of Science of the Republic of Kazakhstan 5 (2007) 38-43.1.2 類與依賴關系的設計
1.3 測試技術
1.4 Web表現層的設計
1.5 數據庫存取
1.6 通過注釋進行配置
2 CJW架構的服務體系
3 中間層的整合
4 開發生命周期
5 結論