1 Spring框架
1.1 Spring框架
??? Spring框架是一個(gè)分層架構(gòu),由7個(gè)定義良好的模塊組成。Spring 模塊構(gòu)建在核心容器之上,核心容器定義了創(chuàng)建、配置和管理 bean 的方式,如圖1所示。

??? 組成Spring框架的每個(gè)模塊(或組件)都可以單獨(dú)存在,或者與其他一個(gè)或多個(gè)模塊聯(lián)合實(shí)現(xiàn)。每個(gè)模塊的功能如下:
????? ? 核心容器:核心容器提供Spring框架的基本功能。核心容器的主要組件是BeanFactory,它是工廠模式的實(shí)現(xiàn)。BeanFactory使用控制反轉(zhuǎn)(IOC)模式將應(yīng)用程序的配置和依賴性規(guī)范與實(shí)際的應(yīng)用程序代碼分開(kāi)。
????? ? Spring上下文: Spring上下文是一個(gè)配置文件,向 Spring 框架提供上下文信息。Spring 上下文包括企業(yè)服務(wù),例如 JNDI、EJB、電子郵件、國(guó)際化、校驗(yàn)和調(diào)度功能。
????? ? Spring AOP:通過(guò)配置管理特性,Spring AOP 模塊直接將面向方面的編程功能集成到了 Spring 框架中。所以,可以很容易地使 Spring 框架管理的任何對(duì)象支持 AOP。Spring AOP 模塊為基于 Spring 的應(yīng)用程序中的對(duì)象提供了事務(wù)管理服務(wù)。通過(guò)使用 Spring AOP,不用依賴 EJB 組件,就可以將聲明性事務(wù)管理集成到應(yīng)用程序中。
????? ? Spring DAO:JDBC DAO抽象層提供了有意義的異常層次結(jié)構(gòu),可用該結(jié)構(gòu)來(lái)管理異常處理和不同數(shù)據(jù)庫(kù)供應(yīng)商拋出的錯(cuò)誤消息。異常層次結(jié)構(gòu)簡(jiǎn)化了錯(cuò)誤處理,并且極大地降低了需要編寫的異常代碼數(shù)量(例如打開(kāi)和關(guān)閉連接)。Spring DAO的面向JDBC的異常遵從通用的DAO異常層次結(jié)構(gòu)。
????? ? Spring ORM: Spring框架插入了若干個(gè)ORM框架,從而提供了ORM的對(duì)象關(guān)系工具,其中包括 JDO、Hibernate 和 iBatis SQL Map。所有這些都遵從 Spring 的通用事務(wù)和 DAO 異常層次結(jié)構(gòu)。
????? ? Spring Web 模塊:Web 上下文模塊建立在應(yīng)用程序上下文模塊之上,為基于 Web 的應(yīng)用程序提供了上下文。所以,Spring 框架支持與 Jakarta Struts 的集成。Web 模塊還簡(jiǎn)化了處理多部分請(qǐng)求以及將請(qǐng)求參數(shù)綁定到域?qū)ο蟮墓ぷ鳌?/p>
????? ? Spring MVC 框架:MVC 框架是一個(gè)全功能的構(gòu)建 Web 應(yīng)用程序的 MVC 實(shí)現(xiàn)。通過(guò)策略接口,MVC 框架變成為高度可配置的,MVC 容納了大量視圖技術(shù),其中包括 JSP、Velocity、Tiles、iText 和 POI。
??? Spring框架的功能可以用在任何 J2EE 服務(wù)器中,大多數(shù)功能也適用于不受管理的環(huán)境。Spring 的核心要點(diǎn)是:支持不綁定到特定 J2EE 服務(wù)的可重用業(yè)務(wù)和數(shù)據(jù)訪問(wèn)對(duì)象。毫無(wú)疑問(wèn),這樣的對(duì)象可以在不同 J2EE 環(huán)境 (Web 或 EJB)、獨(dú)立應(yīng)用程序、測(cè)試環(huán)境之間重用。
1.2 IOC 和 AOP
??? 控制反轉(zhuǎn)模式(也稱作依賴性介入)的基本概念是:不創(chuàng)建對(duì)象,但是描述創(chuàng)建它們的方式。在代碼中不直接與對(duì)象和服務(wù)連接,但在配置文件中描述哪一個(gè)組件需要哪一項(xiàng)服務(wù)。容器(在 Spring 框架中是 IOC 容器)負(fù)責(zé)將這些聯(lián)系在一起。
??? 在典型的 IOC 場(chǎng)景中,容器創(chuàng)建了所有對(duì)象,并設(shè)置必要的屬性將它們連接在一起,決定什么時(shí)間調(diào)用方法。下表列出了 IOC 的一個(gè)實(shí)現(xiàn)模式。

Spring框架的 IOC 容器采用類型 2 和類型3實(shí)現(xiàn)。
1.2.1 面向切方的編程
??? 面向切面的編程,即AOP,是一種編程技術(shù),它允許程序員對(duì)橫切關(guān)注點(diǎn)或橫切典型的職責(zé)分界線的行為(例如日志和事務(wù)管理)進(jìn)行模塊化。AOP的核心構(gòu)造是切面,它將那些影響多個(gè)類的行為封裝到可重用的模塊中。
??? AOP和IOC是補(bǔ)充性的技術(shù),它們都運(yùn)用模塊化方式解決企業(yè)應(yīng)用程序開(kāi)發(fā)中的復(fù)雜問(wèn)題。在典型的面向?qū)ο箝_(kāi)發(fā)方式中,可能要將日志記錄語(yǔ)句放在所有方法和Java類中才能實(shí)現(xiàn)日志功能。在AOP方式中,可以反過(guò)來(lái)將日志服務(wù)模塊化,并以聲明的方式將它們應(yīng)用到需要日志的組件上。當(dāng)然,優(yōu)勢(shì)就是Java類不需要知道日志服務(wù)的存在,也不需要考慮相關(guān)的代碼。所以,用Spring AOP編寫的應(yīng)用程序代碼是松散耦合的。
??? AOP的功能完全集成到了Spring事務(wù)管理、日志和其他各種特性的上下文中。
1.3 IOC容器
??? Spring設(shè)計(jì)的核心是?org.springframework.beans?包,它的設(shè)計(jì)目標(biāo)是與 JavaBean 組件一起使用。這個(gè)包通常不是由用戶直接使用,而是由服務(wù)器將其用作其他多數(shù)功能的底層中介。下一個(gè)最高級(jí)抽象是??BeanFactory?接口,它是工廠設(shè)計(jì)模式的實(shí)現(xiàn),允許通過(guò)名稱創(chuàng)建和檢索對(duì)象。BeanFactory?也可以管理對(duì)象之間的關(guān)系。
??? BeanFactory?支持兩個(gè)對(duì)象模型。
·???????單例?模型提供了具有特定名稱的對(duì)象的共享實(shí)例,可以在查詢時(shí)對(duì)其進(jìn)行檢索。Singleton 是默認(rèn)的也是最常用的對(duì)象模型。對(duì)于無(wú)狀態(tài)服務(wù)對(duì)象很理想。
·???????原型?模型確保每次檢索都會(huì)創(chuàng)建單獨(dú)的對(duì)象。在每個(gè)用戶都需要自己的對(duì)象時(shí),原型模型最適合。
??? bean工廠的概念是Spring作為IOC容器的基礎(chǔ)。IOC將處理事情的責(zé)任從應(yīng)用程序代碼轉(zhuǎn)移到框架。正如我將在下一個(gè)示例中演示的那樣,Spring框架使用JavaBean屬性和配置數(shù)據(jù)來(lái)指出必須設(shè)置的依賴關(guān)系。
1.3.1 BeanFactory 接口
??? 因?yàn)?org.springframework.beans.factory.BeanFactory?是一個(gè)簡(jiǎn)單接口,所以可以針對(duì)各種底層存儲(chǔ)方法實(shí)現(xiàn)。最常用的?BeanFactory?定義是?XmlBeanFactory,它根據(jù) XML 文件中的定義裝入 bean,如清單1所示。
??? 清單1.XmlBeanFactory
????BeanFactory factory = new XMLBeanFactory(new FileInputSteam("mybean.xml"));
????在XML文件中定義的Bean是被懶加載的,這意味在需要bean之前,bean本身不會(huì)被初始化。要從BeanFactory檢索bean,只需調(diào)用getBean()方法,傳入將要檢索的 bean 的名稱即可,如清單2所示。
??? 清單2.getBean()
????MyBean mybean = (MyBean) factory.getBean("mybean");
??? 每個(gè) bean 的定義都可以是 POJO (用類名和 JavaBean 初始化屬性定義)或?FactoryBean。FactoryBean?接口為使用 Spring 框架構(gòu)建的應(yīng)用程序添加了一個(gè)間接的級(jí)別。
1.4 IOC示例
??? 理解控制反轉(zhuǎn)最簡(jiǎn)單的方式就是看它的實(shí)際應(yīng)用。在對(duì)由三部分組成的?Spring 系列?的第 1 部分進(jìn)行總結(jié)時(shí),我使用了一個(gè)示例,演示了如何通過(guò) Spring IOC容器注入應(yīng)用程序的依賴關(guān)系(而不是將它們構(gòu)建進(jìn)來(lái))。
??? 我用開(kāi)啟在線信用帳戶的用例作為起點(diǎn)。對(duì)于該實(shí)現(xiàn),開(kāi)啟信用帳戶要求用戶與以下服務(wù)進(jìn)行交互:
· ? ? ? 信用級(jí)別評(píng)定服務(wù),查詢用戶的信用歷史信息。
· ? ? ?遠(yuǎn)程信息鏈接服務(wù),插入客戶信息,將客戶信息與信用卡和銀行信息連接起來(lái),以進(jìn)行自動(dòng)借記(如果需要的話)。
· ? ? 電子郵件服務(wù),向用戶發(fā)送有關(guān)信用卡狀態(tài)的電子郵件。
1.5 ?三個(gè)接口
??? 對(duì)于這個(gè)示例,我假設(shè)服務(wù)已經(jīng)存在,理想的情況是用松散耦合的方式把它們集成在一起。以下清單顯示了三個(gè)服務(wù)的應(yīng)用程序接口。
??? 清單3. CreditRatingInterface
public interface CreditRatingInterface {
???public boolean getUserCreditHistoryInformation(ICustomer iCustomer);
}
??? 清單 3 所示的信用級(jí)別評(píng)定接口提供了信用歷史信息。它需要一個(gè)包含客戶信息的?Customer?對(duì)象。該接口的實(shí)現(xiàn)是由?CreditRating?類提供的。
??? 清單4.CreditLinkingInterface
public interface CreditLinkingInterface {
????????public ?String getUrl();
????????public ?void setUrl(String url);
????????public ?void linkCreditBankAccount() throws Exception ;
}
????信用鏈接接口將信用歷史信息與銀行信息(如果需要的話)連接在一起,并插入用戶的信用卡信息。信用鏈接接口是一個(gè)遠(yuǎn)程服務(wù),它的查詢是通過(guò)?getUrl()?方法進(jìn)行的。URL 由 Spring 框架的 bean 配置機(jī)制設(shè)置,我稍后會(huì)討論它。該接口的實(shí)現(xiàn)是由?CreditLinking?類提供的。
??? 清單5.EmailInterface
public ?interface EmailInterface {
??????public ?void sendEmail(ICustomer iCustomer);
??????public ?String getFromEmail();
??????public ?void setFromEmail(String fromEmail) ;
??????public String getPassword();
??????public ?void setPassword(String password) ;
??????public ?String getSmtpHost() ;
??????public void setSmtpHost(String smtpHost);
??????public ?String getUserId() ;
??????public ?void setUserId(String userId);
???}
? ??EmailInterface?負(fù)責(zé)向客戶發(fā)送關(guān)于客戶信用卡狀態(tài)的電子郵件。郵件配置參數(shù)(例如 SMPT 主機(jī)、用戶名、口令)由前面提到的 bean 配置機(jī)制設(shè)置。Email?類提供了該接口的實(shí)現(xiàn)。
1.6 ?Spring 使其保持松散
??? 這些接口就位之后,接下來(lái)要考慮的就是如何用松散耦合方式將它們集成在一起。在?清單 6?中可以看到信用卡帳戶用例的實(shí)現(xiàn)。
??? 注意,所有的 setter 方法都是由 Spring 的配置 bean 實(shí)現(xiàn)的。所有的依賴關(guān)系(也就是三個(gè)接口)都可以由 Spring 框架用這些 bean 注入。createCreditCardAccount()?方法會(huì)用服務(wù)去執(zhí)行其余實(shí)現(xiàn)。在?清單 7?中可以看到 Spring 的配置文件。我用箭頭突出了這些定義。?
1.7 ? 運(yùn)行應(yīng)用程序
??? 要運(yùn)行示例應(yīng)用程序,首先必須?下載 Spring 框架?及其所有依賴文件。接下來(lái),將框架釋放到(比如說(shuō))磁盤?c:\,這會(huì)創(chuàng)建?C:\spring-framework-1.2-rc2?(適用于當(dāng)前發(fā)行版本) 這樣的文件夾。在繼續(xù)后面的操作之前,還必須下載和釋放?Apache Ant。
? ??接下來(lái),將源代碼釋放到文件夾,例如?c:\?盤,然后創(chuàng)建?SpringProject。將 Spring 庫(kù)(即?C:\spring-framework-1.2-rc2\dist下的?spring.jar?和?C:\spring-framework-1.2-rc2\lib\jakarta-commons?下的??commons-logging.jar)復(fù)制到?SpringProject\lib?文件夾中。完成這些工作之后,就有了必需的構(gòu)建依賴關(guān)系集。
??? 打開(kāi)命令提示符,將當(dāng)前目錄切換到?SpringProject,在命令提示符中輸入以下命令:build。?
??? 這會(huì)構(gòu)建并運(yùn)行?CreateCreditAccountClient?類,類的運(yùn)行將創(chuàng)建?Customer?類對(duì)象并填充它,還會(huì)調(diào)用?CreateCreditCardAccount?類創(chuàng)建并鏈接信用卡帳戶。CreateCreditAccountClient?還會(huì)通過(guò)?ClassPathXmlApplicationContext?裝入 Spring 配置文件。裝入 bean 之后,就可以通過(guò)?getBean()?方法訪問(wèn)它們了,如清單 8 所示。
??? 清單 8. 裝入 Spring 配置文件
ClassPathXmlApplicationContext appContext = new ClassPathXmlApplicationContext(new String[] {
?????"springexample-creditaccount.xml"
?});
CreateCreditCardAccountInterface ?creditCardAccount = (CreateCreditCardAccountInterface)
????appContext.getBean("createCreditCard");
1.8 結(jié)束語(yǔ)
??? 在這篇由三部分組成的?Spring 系列?的第一篇文章中,我介紹了 Spring 框架的基礎(chǔ)。我從討論組成 Spring 分層架構(gòu)的 7 個(gè)模塊開(kāi)始,然后深入介紹了其中兩個(gè)模塊:Spring AOP 和 IOC 容器。
??? 由于學(xué)習(xí)的最佳方法是實(shí)踐,所以我用一個(gè)工作示例介紹了 IOC 模式(像 Spring 的 IOC 容器實(shí)現(xiàn)的那樣)如何用松散耦合的方式將分散的系統(tǒng)集成在一起。在這個(gè)示例中可以看到,將依賴關(guān)系或服務(wù)注入工作中的信用卡帳戶應(yīng)用程序,要比從頭開(kāi)始構(gòu)建它們?nèi)菀椎枚唷?/p>
??? 請(qǐng)繼續(xù)關(guān)注這一系列的下一篇文章,我將在這里學(xué)習(xí)的知識(shí)基礎(chǔ)上,介紹 Spring AOP模塊如何在企業(yè)應(yīng)用程序中提供持久支持,并讓您開(kāi)始了解 Spring MVC 模塊和相關(guān)插件。
2 Spring AOP與Hibernate
2.1 ?Spring AOP
??? 軟件系統(tǒng)通常由多個(gè)組件構(gòu)成,每個(gè)組件負(fù)責(zé)一個(gè)特定的功能領(lǐng)域。但是,這些組件也經(jīng)常承擔(dān)它們的核心功能之外的額外責(zé)任。系統(tǒng)服務(wù)(例如日志、事務(wù)管理和安全性)經(jīng)常發(fā)現(xiàn)自己跑到了別的組件的領(lǐng)域里,而這些組件的核心職責(zé)是其他事情。結(jié)果就是所謂的“代碼糾纏”,或者更簡(jiǎn)單點(diǎn)兒說(shuō)“一團(tuán)糟”。面向方面編程是一種試圖解決這個(gè)問(wèn)題的編程技術(shù),它把關(guān)注點(diǎn)的隔離提升為核心的編程概念。
??? 使用 AOP 時(shí),仍然是在一個(gè)地方定義系統(tǒng)的公共功能,但是可以聲明性地定義?如何?和?在哪里?應(yīng)用這個(gè)功能。如果對(duì)橫切關(guān)注點(diǎn)(例如日志和事務(wù)管理)進(jìn)行了模塊化,那么不用修改每個(gè)單獨(dú)的類,就可以向代碼中添加新特性。這類模塊化的關(guān)注點(diǎn)稱作?方面。
??? 以一個(gè)企業(yè)應(yīng)用程序?yàn)槔?。這類應(yīng)用程序通常要求類似于安全性和事務(wù)支持的服務(wù)。顯然,可以把這些服務(wù)的支持直接編寫到要求服務(wù)的每個(gè)類當(dāng)中,但是更希望能夠不必為大量事務(wù)性上下文編寫同樣的事務(wù)處理代碼。如果使用 Spring AOP進(jìn)行事務(wù)處理,那么可以聲明性地安排適當(dāng)?shù)姆椒ㄕ{(diào)用,而不必逐個(gè)安排。
??? Spring AOP提供了幾個(gè)方面,可以為 JavaBean 聲明事務(wù)。例如,TransactionProxyFactoryBean?是個(gè)方便的代理類,能夠攔截對(duì)現(xiàn)有類的方法調(diào)用,并把事務(wù)上下文應(yīng)用到事務(wù) bean。在下面的示例中會(huì)看到這個(gè)類的實(shí)際應(yīng)用。
2.2 ? Hibernate
??? Spring框架提供了對(duì) Hibernate、JDO 和 iBATIS SQL
????Maps 的集成支持。Spring 對(duì) Hibernate 的支持是第一級(jí)的,整合了許多 IOC 的方便特性,解決了許多典型的 Hibernate 集成問(wèn)題??蚣軐?duì) Hibernate 的支持符合 Spring 通用的事務(wù)和數(shù)據(jù)訪問(wèn)對(duì)象(DAO)異常層次結(jié)構(gòu)。
??? Spring為使用選擇的 OR 映射層來(lái)創(chuàng)建數(shù)據(jù)訪問(wèn)應(yīng)用程序提供了支持。因?yàn)樗袞|西都設(shè)計(jì)成一組可重用 JavaBean,所以不管選擇什么技術(shù),都能以庫(kù)的格式訪問(wèn)大多數(shù) Spring 的 OR 映射支持。?ApplicationContext?或?BeanFactory?內(nèi)部的 OR 映射的好處是簡(jiǎn)化了配置和部署。
??? Hibernate是 Java 平臺(tái)上一個(gè)功能全面的、開(kāi)源的 OR 映射框架。Hibernate 支持開(kāi)發(fā)符合常規(guī) Java 理念的持久性類 —— 包括關(guān)聯(lián)、繼承、多態(tài)、復(fù)合以及 Java 集合框架。Hibernate 查詢語(yǔ)言(HQL)被設(shè)計(jì)成 SQL 的一個(gè)微型面向?qū)ο髷U(kuò)展,它是對(duì)象和關(guān)系世界之間的橋梁。Hibernate 也支持用原始 SQL 或基于 Java 的標(biāo)準(zhǔn)和示例查詢表達(dá)查詢。Hibernate 使用 XML(*.hbm.xml)文件把 Java 類映射到表,把 JavaBean 屬性映射到數(shù)據(jù)庫(kù)表。
??? 通過(guò) JDBC 技術(shù),支持所有的 SQL 數(shù)據(jù)庫(kù)管理系統(tǒng)。Hibernate 與所有流行的 J2EE 應(yīng)用程序服務(wù)器和 Web 容器都很好地集成。
2.3 ? 實(shí)際示例
??? 一個(gè)銀行應(yīng)用程序示例可以讓您自己看到 Spring AOP和 Hibernate 一起工作有多么好。銀行帳戶用例允許用戶 (Customer)在一個(gè)事務(wù)中打開(kāi)一個(gè)或多個(gè)銀行帳戶。用戶可以申請(qǐng)多個(gè)銀行帳戶,可以選擇是支票帳戶類型或者是儲(chǔ)蓄帳戶類型。
??? 應(yīng)用程序數(shù)據(jù)庫(kù)(Cloudscape?)容納所有客戶和帳戶信息。在這個(gè)例子中,假設(shè)在?Customer?和?Account?類之間存在?1:N?的關(guān)聯(lián)。在實(shí)際生活場(chǎng)景中,關(guān)聯(lián)可能需要按?m:n?建模,才能支持聯(lián)合帳戶。
??? 由于用戶必須可以在一個(gè)事務(wù)中申請(qǐng)多個(gè)帳戶,所以首先要為數(shù)據(jù)庫(kù)交互實(shí)現(xiàn)一個(gè) DOA 模式。然后要設(shè)置 Spring AOP的?TransactionProxyFactoryBean,讓它攔截方法調(diào)用并聲明性地把事務(wù)上下文應(yīng)用到 DOA。
2.4 ? Hibernate實(shí)踐
??? 在Spring框架中,像JDBC?DataSource或Hibernate?SessionFactory這樣的資源,在應(yīng)用程序上下文中可以用bean實(shí)現(xiàn)。需要訪問(wèn)資源的應(yīng)用程序?qū)ο笾恍柰ㄟ^(guò)bean引用得到這類預(yù)先定義好的實(shí)例的引用即可(這方面的更多內(nèi)容在?下一節(jié)中)。在清單1中,可以看到示例銀行應(yīng)用程序的一段摘錄:XML 應(yīng)用程序上下文定義顯示了如何設(shè)置JDBC?DataSource,并在上面放一個(gè)Hibernate?SessionFactory。
??? 清單1.JDBC DataSource 和 HibernateSessionFactory 連接


??? 清單 1?顯示了如何為示例應(yīng)用程序數(shù)據(jù)庫(kù)(是 Cloudscape)配置數(shù)據(jù)源 bean(exampleDataSource)。exampleDatasource被連接到 Spring Hibernate 的?SessionFactory。請(qǐng)注意?*.hbm.xml?指定了示例應(yīng)用程序的OR映射文件。?
??? 數(shù)據(jù)源和會(huì)話工廠設(shè)置好之后,下一步就是在DAO中連接,在?CustomerDAOImpl?示例中,要使用?SessionFactory。接下來(lái),插入Spring的TransactionProxyFactoryBean,它會(huì)攔截對(duì)應(yīng)用程序的CustomerDAOImpl對(duì)象的方法調(diào)用,并聲明性地在它上面應(yīng)用事務(wù)。
??? 在?清單 2?的這個(gè)示例中,CustomerDAOImpl?類的addCustomer?方法是作為事務(wù)的一部分執(zhí)行的,有一個(gè)事務(wù)屬性?PROPAGATION_REQUIRED。這個(gè)屬性等價(jià)于 EJB 容器的?TX_REQUIRED。如果想讓這個(gè)方法一直在事務(wù)中運(yùn)行,可以使用?PROPAGATION_REQUIRED。如果事務(wù)已經(jīng)在運(yùn)行,那么 bean 方法會(huì)加入事務(wù),否則 Spring 的輕量級(jí)事務(wù)管理器會(huì)啟動(dòng)一個(gè)事務(wù)。如果想在調(diào)用組件服務(wù)時(shí)總是啟動(dòng)新事務(wù),可以使用?PROPAGATION_REQUIRES_NEW?屬性。
??? 應(yīng)用程序的連接完成之后,現(xiàn)在來(lái)進(jìn)一步查看源代碼。
2.5 ? 分析這個(gè)!
??? 如果以前沒(méi)這么做過(guò),那么請(qǐng)?下載這篇文章的源代碼。把源 zip 文件釋放到計(jì)算機(jī)中的任何位置上,例如?c:\。會(huì)創(chuàng)建一個(gè)叫作?SpringProjectPart2?的文件夾。src\spring?文件夾包含示例應(yīng)用程序的 Hibernate 映射文件和 Spring 配置文件。src\springexample\hibernate?文件包含應(yīng)用程序的源代碼。
??? 在這里會(huì)發(fā)現(xiàn)兩個(gè)類,即?Customer?和??Account,它們用 Hibernate 映射文件映射到兩個(gè)表。Customer?類代表客戶信息,Account?代表客戶的帳戶信息。正如前面提到的,我把這兩個(gè)類按照?1: N?關(guān)系進(jìn)行建模,即一個(gè)?Customer?可以擁有多個(gè)?Account。清單3顯示了?Customer?對(duì)象的 Hibernate 映射文件。
??? 清單 3. Customer 對(duì)象的 Hibernate 映射文件


??? set name="accounts"?和一對(duì)多類標(biāo)簽指定了?Customer?和?Account?之間的關(guān)系。我還在?Account.hbm.xml?文件中定義了?Account?對(duì)象的映射。
??? CustomerDAOImpl.java?代表應(yīng)用程序的 DAO,它在應(yīng)用程序數(shù)據(jù)庫(kù)中插入客戶和帳戶信息。CustomerDAOImpl?擴(kuò)展了 Spring 的?HibernateDaoSupport,它用 Spring
????HibernateTemplate 簡(jiǎn)化了會(huì)話管理。這樣,可以通過(guò)?getHibernateTemplate()?方法保存或檢索數(shù)據(jù)。下面顯示的?getCustomerAccountInfo()?對(duì)?Customer?進(jìn)行?查找,通過(guò)getHibernateTemplate().find方法用 HQL 得到客戶的帳戶信息,如清單 4 所示。
??? 清單 4. DAO 實(shí)現(xiàn)
public ?class CustomerDAOImpl extends HibernateDaoSupport implements CustomerDAO{
??????public void addCustomer(Customer customer) {
????????????getHibernateTemplate().save(customer);????
????????????//TODO Auto-generated method stub
??????}
??????public Customer getCustomerAccountInfo(Customer customer) {
????????Customer cust = null;
????????List list = getHibernateTemplate().find("from Customer customer " +
??????????"where customer.userId = ?" , customer.getUserId(),Hibernate.STRING);
????????if(list.size() > 0){
??????????cust = (Customer)? list.get(0);
????????}
????????return ?cust;
??}
??? 所有這些都應(yīng)當(dāng)很容易掌握?,F(xiàn)在來(lái)看代碼的實(shí)際應(yīng)用!
2.6 ?運(yùn)行應(yīng)用程序
??? 要運(yùn)行示例應(yīng)用程序,必須首先?下載 Spring 框架?和它的全部依賴文件。接下來(lái),釋放框架到某一位置(比如?c:\?),這會(huì)創(chuàng)建文件夾?C:\spring-framework-1.2-rc2(針對(duì)當(dāng)前發(fā)行版)。在繼續(xù)之前還必須下載和釋放?Apache Ant?和?Cloudscape。下載 Cloudscape之后,把它釋放到?c:\?,這會(huì)創(chuàng)建文件夾?C:\Cloudscape_10.0。
??? 接下來(lái),釋放源代碼到?c:\?,這會(huì)創(chuàng)建?SpringProject2?文件夾。接下來(lái)修改?build.xml?文件的入口,用實(shí)際安裝 Spring 的位置代替?C:\spring-framework-1.2-rc2,用實(shí)際安裝 Cloudscape的位置代替?C:\Program?Files\IBM\Cloudscape_10.0。
??? 打開(kāi)命令行提示符,進(jìn)入?SpringProject?目錄,在命令行提示符下輸入以下命令:build.?
????這會(huì)構(gòu)建并運(yùn)行?CreateBankCustomerClient?類,它會(huì)創(chuàng)建?Customer?類對(duì)象,用數(shù)據(jù)填充它,創(chuàng)建?Account?對(duì)象,填充它,并把它添加到?Customer?對(duì)象。
??? 然后?CreateBankCustomerClient?會(huì)調(diào)用?CustomerDAOImpl.addCustomer?類,添加客戶和帳戶信息。一旦插入完成,CreateBankCustomerClient?會(huì)調(diào)用CustomerDAOImpl.getCustomerAccountInfo?方法,根據(jù)?userid?得到客戶和帳戶信息。如果?CreateBankCustomerClient?執(zhí)行成功,會(huì)在控制臺(tái)上看到打印出?userid。也可以查詢 Cloudscape數(shù)據(jù)庫(kù)檢索客戶和帳戶信息。?
2.7 ?結(jié)束語(yǔ)
??? 在三部分的?Spring 系列?的第 2 部分中,我介紹了如何集成 Spring?Hibernate和Spring AOP。結(jié)果是一個(gè)強(qiáng)健的持久性框架,支持聲明性的實(shí)現(xiàn)事務(wù)。
??? 在這個(gè)系列的下一篇,也是最后一篇文章中,我將介紹 Spring 的 MVC 模塊,介紹如何用它來(lái)簡(jiǎn)化基于 Web 的應(yīng)用程序的創(chuàng)建。
3 Spring MVC框架
3.1 Spring MVC框架
??? Spring框架提供了構(gòu)建 Web 應(yīng)用程序的全功能 MVC 模塊。使用 Spring 可插入的 MVC 架構(gòu),可以選擇是使用內(nèi)置的 Spring Web 框架還是 Struts 這樣的 Web 框架。通過(guò)策略接口,Spring 框架是高度可配置的,而且包含多種視圖技術(shù),例如 JavaServer Pages(JSP)技術(shù)、Velocity、Tiles、iText 和 POI。Spring MVC 框架并不知道使用的視圖,所以不會(huì)強(qiáng)迫您只使用 JSP 技術(shù)。Spring MVC 分離了控制器、模型對(duì)象、分派器以及處理程序?qū)ο蟮慕巧?,這種分離讓它們更容易進(jìn)行定制。
?? ?Spring的Web MVC框架是圍繞DispatcherServlet設(shè)計(jì)的,它把請(qǐng)求分派給處理程序,同時(shí)帶有可配置的處理程序映射、視圖解析、本地語(yǔ)言、主題解析以及上載文件支持。默認(rèn)的處理程序是非常簡(jiǎn)單的 Controller 接口,只有一個(gè)方法 ModelAndView handleRequest(request,response)。Spring 提供了一個(gè)控制器層次結(jié)構(gòu),可以派生子類。如果應(yīng)用程序需要處理用戶輸入表單,那么可以繼承AbstractFormController。如果需要把多頁(yè)輸入處理到一個(gè)表單,那么可以繼承AbstractWizardFormController。
??? 示例應(yīng)用程序有助于直觀地學(xué)習(xí)這些特性。銀行應(yīng)用程序允許用戶檢索他們的帳戶信息。在構(gòu)建銀行應(yīng)用程序的過(guò)程中,可以學(xué)到如何配置 Spring MVC 框架和實(shí)現(xiàn)框架的視圖層,視圖層包括 JSTL 標(biāo)記(用于顯示輸出的數(shù)據(jù))和JavaServer Pages 技術(shù)。
3.2 配置Spring MVC
??? 要開(kāi)始構(gòu)建示例應(yīng)用程序,請(qǐng)配置 Spring MVC 的 DispatcherServlet。請(qǐng)?jiān)?web.xml 文件中注冊(cè)所有配置。清單1顯示了如何配置 sampleBankingServlet。
??? 清單1. 配置Spring MVC DispatcherServlet

??? DispatcherServlet從一個(gè)XML文件裝入Spring應(yīng)用程序上下文,XML文件的名稱是servlet 的名稱后面加上-servlet 。在這個(gè)示例中,DispatcherServlet 會(huì)從 sampleBankingServlet-servlet.xml 文件裝入應(yīng)用程序上下文。
3.3 配置應(yīng)用程序的URL
??? 下一步是配置想讓sampleBankingServlet處理的URL。同樣,還是要在web.xml中注冊(cè)所有這些信息。
??? 清單 2. 配置想要處理的URL

3.4 裝入配置文件
??? 下面,裝入配置文件。為了做到這點(diǎn),請(qǐng)為 Servlet 2.3 規(guī)范注冊(cè) ContextLoaderListener 或?yàn)?Servlet 2.2 及以下的容器注冊(cè) ContextLoaderServlet。為了保障后向兼容性,請(qǐng)用ContextLoaderServlet。在啟動(dòng) Web 應(yīng)用程序時(shí),ContextLoaderServlet 會(huì)裝入 Spring 配置文件。清單3注冊(cè)了 ContextLoaderServlet。
??? 清單 3. 注冊(cè) ContextLoaderServlet

??? contextConfigLocation參數(shù)定義了要裝入的 Spring 配置文件,如下面的 servlet 上下文所示。

??? sampleBanking-services.xml 文件代表示例銀行應(yīng)用程序服務(wù)的配置和 bean 配置。如果想裝入多個(gè)配置文件,可以在 標(biāo)記中用逗號(hào)作分隔符。
3.5 Spring MVC示例
??? 示例銀行應(yīng)用程序允許用戶根據(jù)惟一的 ID 和口令查看帳戶信息。雖然 Spring MVC 提供了其他選項(xiàng),但是我將采用 JSP 技術(shù)作為視圖頁(yè)面。這個(gè)簡(jiǎn)單的應(yīng)用程序包含一個(gè)視圖頁(yè)用于用戶輸入(ID 和口令),另一頁(yè)顯示用戶的帳戶信息。
??? 我從 LoginBankController 開(kāi)始,它擴(kuò)展了 Spring MVC 的 SimpleFormController。SimpleFormContoller 提供了顯示從 HTTP GET 請(qǐng)求接收到的表單的功能,以及處理從 HTTP POST 接收到的相同表單數(shù)據(jù)的功能。LoginBankController 用 AuthenticationService 和 AccountServices 服務(wù)進(jìn)行驗(yàn)證,并執(zhí)行帳戶活動(dòng)。“ 配置視圖屬性 ”一節(jié)中的 清單 5 描述了如何把 AuthenticationService 和 AccountServices 連接到 LoginBankController。 清單 4顯示了 LoginBankController 的代碼。
3.6 配置視圖屬性
??? 下面,我必須注冊(cè)在接收到 HTTP GET 請(qǐng)求時(shí)顯示的頁(yè)面。我在 Spring 配置中用 formView 屬性注冊(cè)這個(gè)頁(yè)面,如清單 5 所示。sucessView 屬性代表表單數(shù)據(jù)提交而且 doSubmitAction() 方法中的邏輯成功執(zhí)行之后顯示的頁(yè)面。formView 和 sucessView 屬性都代表被定義的視圖的邏輯名稱,邏輯名稱映射到實(shí)際的視圖頁(yè)面。
??? 清單 5. 注冊(cè) LoginBankController

??? commandClass和 commandName 標(biāo)記決定將在視圖頁(yè)面中活動(dòng)的 bean。例如,可以通過(guò) login.jsp 頁(yè)面訪問(wèn) loginCommand bean,這個(gè)頁(yè)面是應(yīng)用程序的登錄頁(yè)面。一旦用戶提交了登錄頁(yè)面,應(yīng)用程序就可以從 LoginBankController 的 onSubmit() 方法中的命令對(duì)象檢索出表單數(shù)據(jù)。
3.7 視圖解析器
??? Spring MVC的 視圖解析器 把每個(gè)邏輯名稱解析成實(shí)際的資源,即包含帳戶信息的 JSP 文件。我用的是 Spring 的 InternalResourceViewResolver,如 清單 6所示。
??? 因?yàn)槲以?JSP 頁(yè)面中使用了 JSTL 標(biāo)記,所以用戶的登錄名稱解析成資源 /jsp/login.jsp,而 viewClass 成為 JstlView。
3.8 驗(yàn)證和帳戶服務(wù)
??? 就像前面提到的,LoginBankController 內(nèi)部連接了 Spring 的 AccountServices 和 AuthenticationService。AuthenticationService 類處理銀行應(yīng)用程序的驗(yàn)證。AccountServices 類處理典型的銀行服務(wù),例如查找交易和電匯。清單 7 顯示了銀行應(yīng)用程序的驗(yàn)證和帳戶服務(wù)的配置。
??? 清單 7. 配置驗(yàn)證和帳戶服務(wù)

????以上服務(wù)在 sampleBanking-services.xml 中注冊(cè),然后裝入 web.xml 文件中,就像 前面討論的那樣??刂破骱头?wù)配置好后,這個(gè)簡(jiǎn)單的應(yīng)用程序就完成了?,F(xiàn)在我們來(lái)看看部署和測(cè)試它時(shí)會(huì)發(fā)生什么!
3.9 部署應(yīng)用程序
??? 我把示例應(yīng)用程序部署在 Tomcat servlet 容器中。Tomcat 是 Java Servlet 和 Java ServerPagest 技術(shù)的官方參考實(shí)現(xiàn)中使用的 servlet 容器。如果以前沒(méi)這么做過(guò),請(qǐng) 下載 jakarta-tomcat-5.0.28.exe并運(yùn)行它把 Tomcat 安裝到自己喜歡的任何位置,例如 c:\tomcat5.0。
??? 接下來(lái),下載示例代碼 并釋放到驅(qū)動(dòng)器(例如 c:\ )上。創(chuàng)建了 Spring 項(xiàng)目的文件夾之后,打開(kāi)它并把 spring-banking 子文件夾拷貝到 c:\tomvat5.0\webapps。spring-banking 文件夾是一個(gè) Web 檔案,里面包含 Spring MVC 示例應(yīng)用程序。lib 文件夾包含應(yīng)用程序需要的 Spring 框架、與Spring 相關(guān)的 MVC 庫(kù)以及 JSTL 標(biāo)記庫(kù)和 jar 文件。
????要啟動(dòng) Tomcat 服務(wù)器,請(qǐng)使用以下命令:
??? cd bin C:\Tomcat 5.0\bin>catalina.bat start
??? Tomcat應(yīng)當(dāng)啟動(dòng)并部署 Spring MVC 示例應(yīng)用程序。
3.10 ?測(cè)試應(yīng)用程序
??? 要測(cè)試應(yīng)用程序,請(qǐng)打開(kāi) Web 瀏覽器,指向http://localhost:tomcatport/springbanking并用 Tomcat 服務(wù)器實(shí)際運(yùn)行的端口替換 tomcatport。應(yīng)當(dāng)看到圖 1 所示的登錄屏幕。輸入用戶 ID “admin”和口令“password”,并按下登錄按鈕。其他用戶 ID 或口令會(huì)造成來(lái)自驗(yàn)證服務(wù)的錯(cuò)誤。
??? 圖 1. Spring MVC 示例登錄屏幕

登錄成功之后,會(huì)看到圖 2 所示的帳戶細(xì)節(jié)頁(yè)面。
圖 2. Spring MVC 示例帳戶細(xì)節(jié)頁(yè)面

3.11 ?結(jié)束語(yǔ)
??? 在三部分的 Spring 系列的第三篇文章中,我介紹了 Spring MVC 框架的特性。我演示了如何配置和開(kāi)發(fā) Spring MVC 應(yīng)用程序、如何配置 Spring MVC 控制器和向其中插入依賴項(xiàng)、如何用 JavaServer Pages 技術(shù)開(kāi)發(fā)應(yīng)用程序視圖,以及如何把自己的頁(yè)面與 Spring MVC 的視圖層集成。總結(jié)這篇文章時(shí),我演示了如何在 Tomcat servlet 容器中部署應(yīng)用程序以及如何在瀏覽器中測(cè)試它。
??? 請(qǐng)繼續(xù)關(guān)注 Spring 系列 的下一篇文章。在下一篇文章中,我將介紹如何把基于 JMS 的應(yīng)用程序與 Spring 框架集成。同時(shí),請(qǐng)參閱 參考資料 學(xué)習(xí)更多有關(guān) Spring 框架和 Spring MVC 的內(nèi)容。
4 ?參考鏈接
Spring框架簡(jiǎn)介
https://www.ibm.com/developerworks/cn/java/wa-spring1/
當(dāng)Hibernate遇上Spring
https://www.ibm.com/developerworks/cn/java/wa-spring2/index.html?ca=drs-