運用J2EE創(chuàng)建靈活易擴展的企業(yè)應用程序探討
alix_an@sohu.com
內(nèi)容摘要
        在J2EE技術(shù)飛速發(fā)展的今天,各種技術(shù)框架和設計模式層出不窮,每種技術(shù)都有各自的優(yōu)勢與劣勢。目前,沒有一種技術(shù)處于絕對的霸主地位,如何使我們的應用程序不過多地依賴某種實現(xiàn)技術(shù),具有強的可擴展性,同時,能更好地集成各種技術(shù)框架,使他們發(fā)揮最大的優(yōu)勢,是我們創(chuàng)建企業(yè)應用時,應該考慮的問題。本文主要介紹了筆者基于SOA(Service Oriented Architecture)思想而設計的MiniSOA構(gòu)架的設計原理,核心組件與使用示例,它能很好地幫您集成各種技術(shù),使您輕松地選擇自己的表現(xiàn)層、業(yè)務層和數(shù)據(jù)持久層,“無痛”切換各個層面的技術(shù)實現(xiàn),降低各個層面的耦合性,同時滿足多小組的團隊開發(fā),提高開發(fā)效率,最大限度地發(fā)揮開發(fā)人員的技術(shù)優(yōu)勢。
引言
        隨著J2EE的飛速發(fā)展,已經(jīng)有越來越多的企業(yè)應用程序以J2EE技術(shù)為其構(gòu)建的基石,J2EE本身并不是產(chǎn)品,它只是制定了一套創(chuàng)建企業(yè)應用程序的規(guī)范,不同廠商根據(jù)J2EE規(guī)范,創(chuàng)建了符合J2EE規(guī)范的產(chǎn)品,這給予了我們更多的選擇創(chuàng)建企業(yè)應用的平臺。
        一個典型的J2EE的應用,至少應該包括以下三部分:表現(xiàn)層,業(yè)務邏輯層和數(shù)據(jù)持久層,為了更加容易地創(chuàng)建企業(yè)應用程序,許許多多的Framework涌現(xiàn)出來,表現(xiàn)層我們可以選擇Struts, JSF, Tapestry, WebWork, Velocity等, 數(shù)據(jù)持久層我們可以選擇原始的JDBC, ORMapping tools(Hibernate,toplink等),SQLMapper tools(Ibatis),JDO, EJB(Entity Bean)等,業(yè)務邏輯層我們可以用普通的java Beans,也可以用EJB(session Bean)。每種技術(shù)都有它的優(yōu)點與缺點,各自有各自的適用范疇,例如EJB可以很好地進行分布式處理和Object Cache等,但EJB的運行需要EJB容器,開發(fā)調(diào)試起來很不方便,特別在需求不確定性很大、模型不穩(wěn)定的情況下,實在是一種重量級別的開發(fā);而JAVA BEAN則是一種很輕量級的方式,開發(fā)調(diào)試容易,但又很難實現(xiàn)分布式處理。在各種技術(shù)紛爭的今天,暫時還沒有一種技術(shù)處于絕對的霸主地位,在這種條件下,我們不能把“賭注“押在任何一種技術(shù)上,如何使我們的應用程序有很高的靈活性和易擴展性是我們要仔細研究的課題。
        在實際的項目中,關于應用程序開發(fā)時所用技術(shù)的問題,大致存在兩種情況,一種是構(gòu)架師或技術(shù)經(jīng)理沒有嚴格限定用什么技術(shù)來實現(xiàn)具體的業(yè)務邏輯或者只有簡單的開發(fā)規(guī)范,程序員在開發(fā)時,只是依據(jù)自己的技術(shù)背景,選擇自己熟悉的實現(xiàn)方式,這種情況一般屬于橫向開發(fā),在小的項目中,每個人只做自己負責的一個模塊,從表現(xiàn)層,業(yè)務邏輯層,一直到數(shù)據(jù)層,都由同一個人來負責,這種方式給了技術(shù)人員更多的自我發(fā)揮能力的空間,但不便于后期維護,特別是人員流動頻繁的情況下,問題更是嚴重。第二種情況是構(gòu)架師或技術(shù)經(jīng)理在項目初期從開發(fā)成本,項目需求等等各個方面做出評估,經(jīng)過幾番取舍,確定項目各個層面使用什么樣的技術(shù)實現(xiàn)方式,按不同層面進行分工,不同的工作人員負責不同層面的技術(shù)實現(xiàn),這種方式比第一種方式要好得多,適合校大項目的開發(fā),但也存在很多問題。在目前各種實現(xiàn)技術(shù)紛爭的情況下,沒有一種技術(shù)是萬能的,在做取舍時,難免和某一技術(shù)或?qū)崿F(xiàn)方式依賴性過強,同時限定了技術(shù)人員個人技術(shù)特長的很好發(fā)揮,當由于某些原因要更改實現(xiàn)方式時,經(jīng)常是牽一發(fā)而動全身,造成資源的極大浪費和開發(fā)成本的提高。
        所以,在構(gòu)建企業(yè)應用時,應該有個好的技術(shù)框架,這個框架應該考慮到各種主流的實現(xiàn)技術(shù),我們既可以根據(jù)實際情況進行取舍,同時在從一種實現(xiàn)方式變更為另一種實現(xiàn)方式時,又可以進行平滑過度,讓多種技術(shù)實現(xiàn)并存,發(fā)揮技術(shù)人員的最大優(yōu)勢,降低項目成本,提高開發(fā)效率。
基于SOA的構(gòu)架
圖一

        SOA(Service Oriented Architecture),對這一術(shù)語我們并不陌生,因為Web service是基于SOA的一種技術(shù),服務的提供者將提供的服務注冊到UDDI,其使用者從UDDI上獲得服務的描述(WSDL),然后根據(jù)服務接口使用服務。Web Service用xml進行消息的傳遞,通過SOAP綁定在現(xiàn)有的輕量級協(xié)議,如HTTP之上,可以透過防火墻,不依賴服務端和客戶端具體地實現(xiàn)技術(shù),進行分布式遠程調(diào)用,它是現(xiàn)有的應用向Internet的延伸。Web service在EAI,B2B,應用到應用的集成等方面體現(xiàn)了巨大的優(yōu)勢,有很多文獻介紹Web service,由于這不是本文重點,在此不再贅述。
        SOA的優(yōu)勢在于降低了服務的提供者與使用者之間的耦合性,服務的提供者將自己提供的服務注冊在中介那里,服務使用者先通過中介查找自己所需服務,使用者獲得的是服務接口,但并不知道服務的具體實現(xiàn),它根據(jù)調(diào)用接口調(diào)用服務,這樣即使服務的實現(xiàn)方式發(fā)生了變化,只要供使用者調(diào)用接口沒有改變,服務使用者就不會受到任何影響,這種思想正是我們應該學習和借鑒的地方。那么既然Web service是基于SOA的,我們的企業(yè)應用是不是就可以完全構(gòu)架在Web service上呢?我們并不建議這么做,Web service對于企業(yè)內(nèi)部的應用并不太適合,在一個應用內(nèi)部使用Web service,系統(tǒng)大量的資源花費在進行XML消息的解析和進行遠程調(diào)用上,造成系統(tǒng)運轉(zhuǎn)緩慢。當然,從某種意義上講,EJB也是SOA的一種實現(xiàn),服務的提供者把服務注冊在JNDI上,使用者通過JNDI找到自己想要的服務,通過遠程接口使用服務,但EJB的運行需要EJB 容器,開發(fā)調(diào)試起來不方便,特別對于需求經(jīng)常變化的系統(tǒng),進行EJB調(diào)試的時間會更久。我們所需要的是一個輕量級的構(gòu)架,能兼顧各種主流的技術(shù),但又不依賴具體的某個實現(xiàn)方式,當實現(xiàn)方式從一種技術(shù)變更為另一種技術(shù)時,對于服務的使用者來說幾乎沒有影響,從而實現(xiàn)客戶端和服務器端的松耦合,這樣,我們的表現(xiàn)層,業(yè)務邏輯層和數(shù)據(jù)持久層都可以依據(jù)實際需求情況與偏好隨意選擇各種實現(xiàn)方式。        
MiniSOA構(gòu)架介紹
MiniSOA設計思想
MiniSOA是以SOA思想為指導的一個極其輕量級的構(gòu)架,其主旨是降低服務使用者和提供者之間的耦合度,使現(xiàn)在流行的多種技術(shù)能夠很好的并存,并充分發(fā)揮各自的優(yōu)勢,技術(shù)人員能夠發(fā)揮自己的特長,用自己熟悉的技術(shù)來實現(xiàn)業(yè)務邏輯,同時應用程序某些層面能夠方便的在不同的實現(xiàn)技術(shù)之間進行切換,而不會對其他層面造成影響。MiniSOA沒有創(chuàng)建一個新的編程模式,沒有Web service,EJB那么工業(yè)化的龐大,它只是通過XML配置把應用組件裝配在一起,通過必要的緩存,提高組件的運行效率,自動管理組件運行時的事務、環(huán)境參數(shù)等信息,使其能更有效的運行,同時,提供多小組的團隊開發(fā)的支持,并方便進行單元測試,使開發(fā)人員集中精力開發(fā)業(yè)務邏輯,提高勞動生產(chǎn)率。
圖二
 點擊查看大圖
MiniSOA概述
為了降低表現(xiàn)層,業(yè)務層和數(shù)據(jù)持久層等各個層面之間的耦合性,各個層面使用其他層面提供的服務時,不是直接去使用服務對象,而是通過服務中介,查找定位服務接口,通過接口來訪問服務,服務提供者可以通過各種方式來實現(xiàn)服務接口,然后把提供的服務注冊到服務中介,服務中介是服務使用者和服務提供者之間進行通訊的橋梁,可以在服務中介上做一些其他方面的控制,如事務,安全等。
表現(xiàn)層作為業(yè)務層的使用者,在使用業(yè)務層提供的服務時,通過Business Service Manager這個中介來查找和使用服務接口;業(yè)務層是表現(xiàn)層的服務提供者,它把通過各種方式實現(xiàn)的服務對象注冊到Business Service Manager,供表現(xiàn)層對象使用,同時業(yè)務層也是數(shù)據(jù)持久層服務的使用者,它通過Data access Object Manager這個中介來使用數(shù)據(jù)持久層提供的服務;同樣數(shù)據(jù)持久層把對數(shù)據(jù)庫,文件等資源的存取進行封裝,把以各種方式提供的服務對象以接口的形式注冊到Data Access Object Manager,供業(yè)務層對象使用。
圖三
 點擊查看大圖
MiniSOA包括業(yè)務層和數(shù)據(jù)持久層兩部分組件,業(yè)務層的核心組件是ServiceManager, 它是表現(xiàn)層和業(yè)務層進行交互的橋梁;數(shù)據(jù)持久層的核心組件是DaoManager,它是業(yè)務層和數(shù)據(jù)持久層進行交互的橋梁。根據(jù)數(shù)據(jù)模型和業(yè)務需求,定義提供的服務接口后,開發(fā)人員用自己熟悉的技術(shù)開發(fā)接口的實現(xiàn)組件,經(jīng)過單元測試后,把服務接口、實現(xiàn)組件和相應的事務,環(huán)境參數(shù)等信息配置到dao-conf.xml,service-conf.xml文件,服務使用者就可以通過ServiceManager,DaoManager來查找所需的服務接口,調(diào)用服務方法。
MiniSOA 業(yè)務層核心組件簡介:
l        ServiceFacotry:作為表現(xiàn)層調(diào)用業(yè)務層的Facade,它讀取service-factory-conf.xml配置文件,創(chuàng)建用于各個模塊的ServiceManager,便于多個開發(fā)小組的分工合作。
l        Service-factory-conf.xml 實例:
<servie-factory>
        <factory>
                <service-id>module1</service-id>
                <service-file>module1-service-conf.xml</service-file>
        </factory>
        <factory>
                <service-id>module2</service-id>
                <service-file>module2-service-conf.xml</service-file>
        </factory>
</servie-factory>
通過service-factory-conf.xml配置文件,每個模塊可以使用和本模塊相關的service配置,適合多個開發(fā)小組共同開發(fā),有效避免了資源沖突。
l        ServiceManager, ServiceManagerBuilder:ServiceManagerBuilder用于讀取serivice-conf.xml配置信息,創(chuàng)建每個service對象使用的環(huán)境對象ServiceContext,返回用于服務使用者查找具體服務的ServiceManager接口。
l        Service-conf.xml實例:
<service-config>
         <settings
                cglib-enabled="true"
                dao-config="dao-hibernate-conf.xml"        
        />        
        <service singleton="true" runas="java-bean">
                <interface>demo.Order</interface>
                <java-bean>
                       <implementation>demo.OrderImpl</implementation>
                </java-bean>
                   <environment>
                       <name>smtphost</name>
                  <value>mail.mycom.com</value>
       </environment>
       <environment>
                       <name>mailfrom</name>
                       <value>from@mycom.com</value>
       </environment>        
       <transaction>
                       <method>sendMail</method>
                  <trans-automanagement>false</trans-automanagement>
         </transaction>
         <transaction>
                         <method>*</method>
                   <trans-automanagement>true</trans-automanagement>
         </transaction>
        </service>
        <service singleton = "false" >
                ...
        </service>
</service-config>
供使用者使用的每個service分別配置在<service>標簽中,cglib-enable屬性用于配置本模塊的services是否要用cglib來增強PRoxy功能,dao-config屬性指定service使用的dao配置信息,runas屬性設置service的實現(xiàn)方式:(java-bean,remote-ejb,local-ejb),singleton屬性用于配置service是否是單一實例的,如果singleton為true,則此service在第一次創(chuàng)建和使用后,被ServiceManager緩存起來,其他Client再請求此service時,則使用被緩存的對象,而不會再被創(chuàng)建,singleton為true的service是無狀態(tài)的,不能保持每個Client的狀態(tài)信息,相反,singleton為false的service是有狀態(tài)的,每個Client都使用自己的service對象,它們之間互不影響。
l        ServiceContext:是ServiceManager和service實現(xiàn)組件之間傳遞信息的橋梁,ServiceContext里保存了每個Service的環(huán)境變量的配置,每個方法的事務配置等信息。
l         ServiceProxy:是ServiceManager創(chuàng)建service對象的代理對象,用于增強對service的控制。
關于數(shù)據(jù)持久層的各個組件的功能和業(yè)務層的各個組件功能類似,在此不再贅述。
使用MiniSOA進行應用程序開發(fā)示例
下面我們模擬銀行轉(zhuǎn)帳業(yè)務,來示例如何使用MiniSOA開發(fā)應用程序。
1.        定義用戶接口組件Bank:
public interface Bank {  
        void transfer(String srcAccountNo,String destAccountNo, float amount );
}
2.        實現(xiàn)用戶接口組件(用Java Bean + DAO)
public class BankImpl extends BaseService implements Bank { //BaseService是MiniSOA提供的服務接口實現(xiàn)組件的父類
        public void transfer(String srcAccountNo,String destAccountNo, float amount ) {
                try{
                        //通過ServiceContext得到DaoManager
                           DaoManager daoManager = 
                             serviceContext.getServiceManager().getDaoManager();
                        //通過DaoManager得到數(shù)據(jù)訪問層接口AccountDao
                           AccountDao accountDao =
                           (AccountDao) daoManager.getDao(AccountDao.class);
                        //通過AccountDao接口得到每個賬號對應的Account信息
                           Account srcAccount = accountDao.findAccountByPK(srcAccountNo);
                        Account destAccount = accountDao.findAccountByPK(destAccountNo);
                        //對Account進行加、減帳戶金額的操作
                           srcAccount.setAmount( srcAccount.getAccount() ? amount);
                        destAccount.setAmount( destAccount.getAccount() + amount);
                        //將更新的帳戶信息寫回到數(shù)據(jù)庫
                           accountDao.updateAccount(srcAccount);
                        accountDao.updateAccount(destAccount);
                }catch(Exception e) { … …}
}
}
注意對銀行轉(zhuǎn)帳業(yè)務邏輯的實現(xiàn),必須在同一個事務中進行,否則,將導致數(shù)據(jù)的不一致,而上面對Bank的transfer方法并沒有進行手工的Transaction的管理,下面在Service的配置中,可以讓MiniSOA自動管理Transaction。
3.        配置service-factory-conf.xml,和本模塊的service-config.xml文件,由MiniSOA自動管理Transaction
service-factory-conf.xml示例:
<servie-factory>
                <factory>
                        <service-id> bankModule </service-id>
                        <service-file> bankModule-service-conf.xml</service-file>
                </factory>
                …
        </service-factory>
bankModule-service-conf.xml示例:
<service-config>
        <settings
                cglib-enabled="true"
                dao-config="dao-hibernate-conf.xml"        
        />        
        <service singleton="true" runas=”java-bean”>
                <interface>demo.Bank</interface>
                <java-bean>
                        <implementation>demo.BankImpl</implementation>
                </java-bean>
<transaction>
               <method>transfer</method>
                  <trans-automanagement>true</trans-automanagement>
       </transaction>
        </service>
        </service-config>
4.        寫Client程序,調(diào)用Bank service
//先得到srcAccountNo, destAccountNo,amount
……
        //得到ServiceFactory
        ServiceFactory  serviceFactory = ServiceFactory.getInstance();
        //通過ServiceFactory得到本模塊的ServiceManager
        ServiceManager sm = serviceFactory.getServiceManager(“bankModule”);
        //通過ServiceManager得到服務的操作接口Bank
        Bank bank = (Bank)sm.getService(Bank.class);
        //使用服務
        if ( bank != null ) {
            bank.transfer(srcAccountNo, destAccountNo, amount);
        }
……
對于表現(xiàn)層,只要我們的Bank這個Interface不發(fā)生變化,我們可以選擇任何框架技術(shù),無論是基于MVC的Struts,JSF,還是Java application, Java Applet對業(yè)務層都沒有任何影響。
總結(jié)
        以上初步介紹了我的MiniSOA構(gòu)架的設計思想、核心組件以及使用MiniSOA開發(fā)的簡單示例,使用MiniSOA我們可以很簡單地創(chuàng)建靈活,具有易擴展性且不依賴于具體實現(xiàn)技術(shù)的應用程序,能夠很好地集成各種流行的技術(shù),在充分發(fā)揮各種技術(shù)優(yōu)勢的同時,最大限度地釋放出開發(fā)人員的技術(shù)優(yōu)勢,同時有利于小組間的分工與合作,提高軟件開發(fā)效率。
對MiniSOA有興趣的讀者可以向筆者索要免費的MiniSOA運行庫、示例和技術(shù)支持,希望與您共同探討可重用的軟件構(gòu)架技術(shù), alix_an@sohu.com( 也可以暫時在http://210.52.149.164:10000/alix/ 這里下載進入討論組討論。
                     (出處:http://m.survivalescaperooms.com)