Spring教程.docx_第1頁(yè)
Spring教程.docx_第2頁(yè)
Spring教程.docx_第3頁(yè)
Spring教程.docx_第4頁(yè)
Spring教程.docx_第5頁(yè)
已閱讀5頁(yè),還剩17頁(yè)未讀, 繼續(xù)免費(fèi)閱讀

下載本文檔

版權(quán)說(shuō)明:本文檔由用戶提供并上傳,收益歸屬內(nèi)容提供方,若內(nèi)容存在侵權(quán),請(qǐng)進(jìn)行舉報(bào)或認(rèn)領(lǐng)

文檔簡(jiǎn)介

Spring教程Email:版權(quán)所有,如果轉(zhuǎn)載和篡改,請(qǐng)注明出處Spring教程作者:錢安川(Moxie)注:后面的內(nèi)容我將不再完善,但網(wǎng)上的朋友可以幫助完善,只需注明住處即可。Spring教程1Spring框架概述3Spring是什么?3Spring的歷史4Spring的使命(Mission Statement)4Spring受到的批判4Spring包含的模塊5總結(jié)6Spring的IoC容器6用戶注冊(cè)的例子7面向接口編程8(用戶持久化類)重構(gòu)第一步面向接口編程8重構(gòu)第二步工廠(Factory)模式9重構(gòu)第三步工廠(Factory)模式的改進(jìn)10重構(gòu)第四步IoC容器11控制反轉(zhuǎn)(IoC)/依賴注入(DI)11什么是控制反轉(zhuǎn)/依賴注入?11依賴注入的三種實(shí)現(xiàn)形式12BeanFactory14BeanFactory管理Bean(組件)的生命周期15Bean的定義16Bean的之前初始化19Bean的準(zhǔn)備就緒(Ready)狀態(tài)21Bean的銷毀21ApplicationContext21Spring的AOP框架21Spring的數(shù)據(jù)層訪問(wèn)22Spring的聲明式事務(wù)22Spring對(duì)其它企業(yè)應(yīng)用支持22名詞解釋容器:框架:容器框架組件:服務(wù):Spring框架概述 主要內(nèi)容:介紹Spring的歷史,Spring的概論和它的體系結(jié)構(gòu),重點(diǎn)闡述它在J2EE中扮演的角色。 目的:讓學(xué)員全面的了解Spring框架,知道Spring框架所提供的功能,并能將Spring框架和其它框架(WebWork/Struts、hibernate)區(qū)分開(kāi)來(lái)。Spring是什么?Spring是一個(gè)開(kāi)源框架,它由Rod Johnson創(chuàng)建。它是為了解決企業(yè)應(yīng)用開(kāi)發(fā)的復(fù)雜性而創(chuàng)建的。Spring使用基本的JavaBean來(lái)完成以前只可能由EJB完成的事情。然而,Spring的用途不僅限于服務(wù)器端的開(kāi)發(fā)。從簡(jiǎn)單性、可測(cè)試性和松耦合的角度而言,任何Java應(yīng)用都可以從Spring中受益。 目的:解決企業(yè)應(yīng)用開(kāi)發(fā)的復(fù)雜性 功能:使用基本的JavaBean代替EJB,并提供了更多的企業(yè)應(yīng)用功能 范圍:任何Java應(yīng)用簡(jiǎn)單來(lái)說(shuō),Spring是一個(gè)輕量級(jí)的控制反轉(zhuǎn)(IoC)和面向切面(AOP)的容器框架。 輕量從大小與開(kāi)銷兩方面而言Spring都是輕量的。完整的Spring框架可以在一個(gè)大小只有1MB多的JAR文件里發(fā)布。并且Spring所需的處理開(kāi)銷也是微不足道的。此外,Spring是非侵入式的:典型地,Spring應(yīng)用中的對(duì)象不依賴于Spring的特定類。 控制反轉(zhuǎn)Spring通過(guò)一種稱作控制反轉(zhuǎn)(IoC)的技術(shù)促進(jìn)了松耦合。當(dāng)應(yīng)用了IoC,一個(gè)對(duì)象依賴的其它對(duì)象會(huì)通過(guò)被動(dòng)的方式傳遞進(jìn)來(lái),而不是這個(gè)對(duì)象自己創(chuàng)建或者查找依賴對(duì)象。你可以認(rèn)為IoC與JNDI相反不是對(duì)象從容器中查找依賴,而是容器在對(duì)象初始化時(shí)不等對(duì)象請(qǐng)求就主動(dòng)將依賴傳遞給它。 面向切面Spring提供了面向切面編程的豐富支持,允許通過(guò)分離應(yīng)用的業(yè)務(wù)邏輯與系統(tǒng)級(jí)服務(wù)(例如審計(jì)(auditing)和事務(wù)()管理)進(jìn)行內(nèi)聚性的開(kāi)發(fā)。應(yīng)用對(duì)象只實(shí)現(xiàn)它們應(yīng)該做的完成業(yè)務(wù)邏輯僅此而已。它們并不負(fù)責(zé)(甚至是意識(shí))其它的系統(tǒng)級(jí)關(guān)注點(diǎn),例如日志或事務(wù)支持。 容器Spring包含并管理應(yīng)用對(duì)象的配置和生命周期,在這個(gè)意義上它是一種容器,你可以配置你的每個(gè)bean如何被創(chuàng)建基于一個(gè)可配置原型(prototype),你的bean可以創(chuàng)建一個(gè)單獨(dú)的實(shí)例或者每次需要時(shí)都生成一個(gè)新的實(shí)例以及它們是如何相互關(guān)聯(lián)的。然而,Spring不應(yīng)該被混同于傳統(tǒng)的重量級(jí)的EJB容器,它們經(jīng)常是龐大與笨重的,難以使用。 框架Spring可以將簡(jiǎn)單的組件配置、組合成為復(fù)雜的應(yīng)用。在Spring中,應(yīng)用對(duì)象被聲明式地組合,典型地是在一個(gè)XML文件里。Spring也提供了很多基礎(chǔ)功能(事務(wù)管理、持久化框架集成等等),將應(yīng)用邏輯的開(kāi)發(fā)留給了你。 所有Spring的這些特征使你能夠編寫更干凈、更可管理、并且更易于測(cè)試的代碼。它們也為Spring中的各種模塊提供了基礎(chǔ)支持。Spring的歷史Spring的基礎(chǔ)架構(gòu)起源于2000年早期,它是Rod Johnson在一些成功的商業(yè)項(xiàng)目中構(gòu)建的基礎(chǔ)設(shè)施。在2002后期,Rod Johnson發(fā)布了Expert One-on-One J2EE Design and Development一書,并隨書提供了一個(gè)初步的開(kāi)發(fā)框架實(shí)現(xiàn)interface21開(kāi)發(fā)包,interface21就是書中闡述的思想的具體實(shí)現(xiàn)。后來(lái),Rod Johnson 在interface21 開(kāi)發(fā)包的基礎(chǔ)之上,進(jìn)行了進(jìn)一步的改造和擴(kuò)充,使其發(fā)展為一個(gè)更加開(kāi)放、清晰、全面、高效的開(kāi)發(fā)框架Spring。2003年2月Spring框架正式成為一個(gè)開(kāi)源項(xiàng)目,并發(fā)布于SourceForge中。Spring的使命(Mission Statement) J2EE應(yīng)該更加容易使用。 面向?qū)ο蟮脑O(shè)計(jì)比任何實(shí)現(xiàn)技術(shù)(比如J2EE)都重要。 面向接口編程,而不是針對(duì)類編程。Spring將使用接口的復(fù)雜度降低到零。(面向接口編程有哪些復(fù)雜度?) 代碼應(yīng)該易于測(cè)試。Spring框架會(huì)幫助你,使代碼的測(cè)試更加簡(jiǎn)單。 JavaBean提供了應(yīng)用程序配置的最好方法。 在Java中,已檢查異常(Checked exception)被過(guò)度使用??蚣懿粦?yīng)該迫使你捕獲不能恢復(fù)的異常。Spring受到的批判 Spring不是一個(gè)“標(biāo)準(zhǔn)”。Spring不是J2EE規(guī)范的一部分,沒(méi)有通過(guò)JCP(Java Community Process)的審核認(rèn)可。批判來(lái)源于EJB的支持者,他們認(rèn)為EJB是一個(gè)標(biāo)準(zhǔn),是J2EE規(guī)范的一部分。當(dāng)然,標(biāo)準(zhǔn)最主要的目的是希望在應(yīng)用服務(wù)器之間是可移植的,可是EJB的移植卻并不輕松,不同應(yīng)用服務(wù)器的ejb部署描述文件總是有著差異。而且EJB開(kāi)發(fā)的類完全依賴于EJB容器。而Spring對(duì)其管理的Bean沒(méi)有任何形式的侵入,這樣的Bean是普通Java對(duì)象(POJO),那么它就遵循Java標(biāo)準(zhǔn),可以到處移植。 Spring是“超重量級(jí)”的。Spring涉及的內(nèi)容確實(shí)很多(例如:提供了對(duì)jdbc、ORM、遠(yuǎn)程訪問(wèn)等等的支持),但其本質(zhì)還是Java技術(shù)的龐大。Spring只是為了這些技術(shù)提供更好的使用方案而已。同時(shí),你可以只選取你需要使用的部分。Spring包含的模塊Spring框架由七個(gè)定義明確的模塊組成(圖1.1)。(Spring框架概覽圖)如果作為一個(gè)整體,這些模塊為你提供了開(kāi)發(fā)企業(yè)應(yīng)用所需的一切。但你不必將應(yīng)用完全基于Spring框架。你可以自由地挑選適合你的應(yīng)用的模塊而忽略其余的模塊。 就像你所看到的,所有的Spring模塊都是在核心容器之上構(gòu)建的。容器定義了Bean是如何創(chuàng)建、配置和管理的更多的Spring細(xì)節(jié)。當(dāng)你配置你的應(yīng)用時(shí),你會(huì)潛在地使用這些類。但是作為一名開(kāi)發(fā)者,你最可能對(duì)影響容器所提供的服務(wù)的其它模塊感興趣。這些模塊將會(huì)為你提供用于構(gòu)建應(yīng)用服務(wù)的框架,例如AOP和持久性。核心容器這是Spring框架最基礎(chǔ)的部分,它提供了依賴注入(Dependency Injection)特征來(lái)實(shí)現(xiàn)容器對(duì)Bean的管理。這里最基本的概念是BeanFactory,它是任何Spring應(yīng)用的核心。BeanFactory是工廠模式的一個(gè)實(shí)現(xiàn),它使用IoC將應(yīng)用配置和依賴說(shuō)明從實(shí)際的應(yīng)用代碼中分離出來(lái)。應(yīng)用上下文(Context)模塊核心模塊的BeanFactory使Spring成為一個(gè)容器,而上下文模塊使它成為一個(gè)框架。這個(gè)模塊擴(kuò)展了BeanFactory的概念,增加了對(duì)國(guó)際化(I18N)消息、事件傳播以及驗(yàn)證的支持。 另外,這個(gè)模塊提供了許多企業(yè)服務(wù),例如電子郵件、JNDI訪問(wèn)、EJB集成、遠(yuǎn)程以及時(shí)序調(diào)度(scheduling)服務(wù)。也包括了對(duì)模版框架例如Velocity和FreeMarker集成的支持。Spring的AOP模塊 Spring在它的AOP模塊中提供了對(duì)面向切面編程的豐富支持。這個(gè)模塊是在Spring應(yīng)用中實(shí)現(xiàn)切面編程的基礎(chǔ)。為了確保Spring與其它AOP框架的互用性, Spring的AOP支持基于AOP聯(lián)盟定義的API。AOP聯(lián)盟是一個(gè)開(kāi)源項(xiàng)目,它的目標(biāo)是通過(guò)定義一組共同的接口和組件來(lái)促進(jìn)AOP的使用以及不同的AOP實(shí)現(xiàn)之間的互用性。通過(guò)訪問(wèn)他們的站點(diǎn)http:/aopalliance. ,你可以找到關(guān)于AOP聯(lián)盟的更多內(nèi)容。 Spring的AOP模塊也將元數(shù)據(jù)編程引入了Spring。使用Spring的元數(shù)據(jù)支持,你可以為你的源代碼增加注釋,指示Spring在何處以及如何應(yīng)用切面函數(shù)。JDBC抽象和DAO模塊 使用JDBC經(jīng)常導(dǎo)致大量的重復(fù)代碼,取得連接、創(chuàng)建語(yǔ)句、處理結(jié)果集,然后關(guān)閉連接。Spring的JDBC和DAO模塊抽取了這些重復(fù)代碼,因此你可以保持你的數(shù)據(jù)庫(kù)訪問(wèn)代碼干凈簡(jiǎn)潔,并且可以防止因關(guān)閉數(shù)據(jù)庫(kù)資源失敗而引起的問(wèn)題。這個(gè)模塊還在幾種數(shù)據(jù)庫(kù)服務(wù)器給出的錯(cuò)誤消息之上建立了一個(gè)有意義的異常層。使你不用再試圖破譯神秘的私有的SQL錯(cuò)誤消息! 另外,這個(gè)模塊還使用了Spring的AOP模塊為Spring應(yīng)用中的對(duì)象提供了事務(wù)管理服務(wù)。對(duì)象/關(guān)系映射集成模塊對(duì)那些更喜歡使用對(duì)象/關(guān)系映射工具而不是直接使用JDBC的人,Spring提供了ORM模塊。Spring并不試圖實(shí)現(xiàn)它自己的ORM解決方案,而是為幾種流行的ORM框架提供了集成方案,包括Hibernate、JDO和iBATIS SQL映射。Spring的事務(wù)管理支持這些ORM框架中的每一個(gè)也包括JDBC。Spring的Web模塊Web上下文模塊建立于應(yīng)用上下文模塊之上,提供了一個(gè)適合于Web應(yīng)用的上下文。另外,這個(gè)模塊還提供了一些面向服務(wù)支持。例如:實(shí)現(xiàn)文件上傳的multipart請(qǐng)求,它也提供了Spring和其它Web框架的集成,比如Struts、WebWork。Spring的MVC框架 Spring為構(gòu)建Web應(yīng)用提供了一個(gè)功能全面的MVC框架。雖然Spring可以很容易地與其它MVC框架集成,例如Struts,但Spring的MVC框架使用IoC對(duì)控制邏輯和業(yè)務(wù)對(duì)象提供了完全的分離。它也允許你聲明性地將請(qǐng)求參數(shù)綁定到你的業(yè)務(wù)對(duì)象中,此外,Spring的MVC框架還可以利用Spring的任何其它服務(wù),例如國(guó)際化信息與驗(yàn)證??偨Y(jié)Spring帶來(lái)了復(fù)雜的J2EE開(kāi)發(fā)的春天。它的核心是輕量級(jí)的IoC容器,它的目標(biāo)是為J2EE應(yīng)用提供了全方位的整合框架,在Spring框架下實(shí)現(xiàn)多個(gè)子框架的組合,這些子框架之間可以彼此獨(dú)立,也可以使用其它的框架方案加以代替,Spring希望為企業(yè)應(yīng)用提供一站式(one-stop shop)的解決方案。Spring的IoC容器 主要內(nèi)容:從最基本的面向接口編程逐步引入IoC設(shè)計(jì)模式(以銀行卡:Card為例,接口單例工廠方法IoC);詳細(xì)介紹IoC的三種實(shí)現(xiàn),并對(duì)其優(yōu)、缺點(diǎn)進(jìn)行比較;之后開(kāi)始引入Spring的IoC容器,詳細(xì)介紹如何使用Spring的IoC容器組織業(yè)務(wù)組件。 目的:使學(xué)員真正理解IoC的概念、優(yōu)點(diǎn),并掌握Spring IoC容器的使用。用戶注冊(cè)的例子我們先看看更進(jìn)一步的需求:實(shí)現(xiàn)一個(gè)用戶注冊(cè)信息持久化的類。功能:1、 保存用戶注冊(cè)的信息;2、 根據(jù)用戶的名稱獲得該注冊(cè)用戶。雖然功能簡(jiǎn)單,但它對(duì)持久化方式的要求卻非常的靈活:1、 在內(nèi)存中持久化,供測(cè)試、演示使用。2、 如果用戶的數(shù)據(jù)很少,將用戶信息持據(jù)化到文本文件中。3、 如果用戶信息很多,并需要一些靈活的查詢,則需要使用JDBC技術(shù)將用將用戶信息持久化到數(shù)據(jù)庫(kù)中。4、 面對(duì)企業(yè)復(fù)雜關(guān)聯(lián)的數(shù)據(jù),甚至需要使用持久層框架來(lái)實(shí)現(xiàn)用戶信息的持久化,比如:iBATIS、Hibernate等。如何去設(shè)計(jì)、實(shí)現(xiàn)我們這個(gè)持久化類呢?我們遵循軟件開(kāi)發(fā)的原則“首先讓它跑起來(lái),再去優(yōu)化(重構(gòu))它”,我們首先實(shí)現(xiàn)最簡(jiǎn)單的在內(nèi)存中持久化用戶信息。既然我們要保存和取得用戶信息,首先應(yīng)該設(shè)計(jì)用戶類。代碼如下:User.javapublic class User private Long id; private String name; private String password; private String group; public User(String name,String password) = name; this.password = password;/相應(yīng)的get/set方法.持久化類有兩個(gè)方法,分別在內(nèi)存中保存和獲取User對(duì)象。代碼如下:MemoryUserPersist.javapublic class MemoryUserPersist private static Map users = new HashMap(); static User defaultAdmin = new User(Moxie,pass); users.put(defaultAdmin.getName(),defaultAdmin); public MemoryUserPersist () public void saveUser(User user) users.put(user.getName(),user); public User LoadUser(String userName) return (User)users.get(userName); 用戶持久化類完成之后,我們就可以在客戶端UserRegister中使用它了。例如:用戶注冊(cè)時(shí),UserRegister代碼片斷如下:MemoryUserPersist userPersist = new MemoryUserPersist ();userPersist.saveUser(user); 可是,現(xiàn)在如果要在文本文件中持久化User,又該如何實(shí)現(xiàn)呢?實(shí)現(xiàn)一個(gè)TextUserPersist類,這個(gè)并不困難。但客戶端代碼將面臨重大災(zāi)難:找到所有使用過(guò)MemoryUserPersist的客戶端類,將他們中的MemoryUserPersist逐個(gè)手工修改為 TextUserPersist,并且重新編譯,當(dāng)然以前的測(cè)試也必須全部從頭來(lái)過(guò)!人生的浩劫只是剛剛開(kāi)始,因?yàn)楦鶕?jù)前面的需求我們至少要分別實(shí)現(xiàn)四種持久化方式!這時(shí),你一定和我一樣在期待著救世主的早日降臨接口(Interface)。面向接口編程什么是接口? 接口定義了行為的協(xié)議,這些行為在繼承接口的類中實(shí)現(xiàn)。 接口定義了很多方法,但是沒(méi)有實(shí)現(xiàn)它們。類履行接口協(xié)議并實(shí)現(xiàn)所有定義在接口中的方法。 接口是一種只有聲明沒(méi)有實(shí)現(xiàn)的特殊類。接口的優(yōu)點(diǎn): Client不必知道其使用對(duì)象的具體所屬類。 一個(gè)對(duì)象可以很容易地被(實(shí)現(xiàn)了相同接口的)的另一個(gè)對(duì)象所替換。 對(duì)象間的連接不必硬綁定(hardwire)到一個(gè)具體類的對(duì)象上,因此增加了靈活性。 松散藕合(loosens coupling)。 增加了重用的可能性。接口的缺點(diǎn):設(shè)計(jì)的復(fù)雜性略有增加(用戶持久化類)重構(gòu)第一步面向接口編程1、 設(shè)計(jì)用戶持久化類的接口UserDao,代碼如下:public interface UserDao public void save(User user); public User load(String name);2、 具體的持久化來(lái)必須要繼承UserDao接口,并實(shí)現(xiàn)它的所有方法。我們還是首先實(shí)現(xiàn)內(nèi)存持久化的用戶類:public class MemoryUserDao implements UserDao private static Map users = new HashMap(); static User user = new User(Moxie,pass); users.put(user.getName(),user); public void save(User user) users.put(user.getId(),user); public User load(String name) return (User)users.get(name); MemoryUserDao的實(shí)現(xiàn)代碼和上面的MemoryUserPersist基本相同,唯一區(qū)別是MemoryUserDao類繼承了UserDao接口,它的save()和load()方法是實(shí)現(xiàn)接口的方法。這時(shí),客戶端UserRegister的代碼又該如何實(shí)現(xiàn)呢?UserDao userDao = new MemoryUserDao();userDao.save(user);(注:面向?qū)ο蟆岸鄳B(tài)”的闡述)如果我們?cè)偾袚Q到文本的持久化實(shí)現(xiàn)TextUserDao,客戶端代碼仍然需要手工修改。雖然我們已經(jīng)使用了面向?qū)ο蟮亩鄳B(tài)技術(shù),對(duì)象userDao方法的執(zhí)行都是針對(duì)接口的調(diào)用,但userDao對(duì)象的創(chuàng)建卻依賴于具體的實(shí)現(xiàn)類,比如上面MemoryUserDao。這樣我們并沒(méi)有完全實(shí)現(xiàn)前面所說(shuō)的“Client不必知道其使用對(duì)象的具體所屬類”。如何解決客戶端對(duì)象依賴具體實(shí)現(xiàn)類的問(wèn)題呢?下面該是我們的工廠(Factory)模式出場(chǎng)了!重構(gòu)第二步工廠(Factory)模式我們使用一個(gè)工廠類來(lái)實(shí)現(xiàn)userDao對(duì)象的創(chuàng)建,這樣客戶端只要知道這一個(gè)工廠類就可以了,不用依賴任何具體的UserDao實(shí)現(xiàn)。創(chuàng)建userDao對(duì)象的工廠類UserDaoFactory代碼如下:public class UserDaoFactory public static UserDao createUserDao() return new MemoryUserDao(); 客戶端UserRegister代碼片斷如下:UserDao userDao = UserDaoFactory. CreateUserDao();userDao.save(user);現(xiàn)在如果再要更換持久化方式,比如使用文本文件持久化用戶信息。就算有再多的客戶代碼調(diào)用了用戶持久化對(duì)象我們都不用擔(dān)心了。因?yàn)榭蛻舳撕陀脩舫志没瘜?duì)象的具體實(shí)現(xiàn)完全解耦。我們唯一要修改的只是一個(gè)UserDaoFactory類。重構(gòu)第三步工廠(Factory)模式的改進(jìn)到這里人生的浩劫已經(jīng)得到了拯救。但我們?nèi)圆粷M足,因?yàn)榧偃鐚?nèi)存持久化改為文本文件持久化仍然有著硬編碼的存在UserDaoFactory類的修改。代碼的修改就意味著重新編譯、打包、部署甚至引入新的Bug。所以,我們不滿足,因?yàn)樗€不夠完美!如何才是我們心目中的完美方案?至少要消除更換持久化方式時(shí)帶來(lái)的硬編碼。具體實(shí)現(xiàn)類的可配置不正是我們需要的嗎?我們?cè)谝粋€(gè)屬性文件中配置UserDao的實(shí)現(xiàn)類,例如:在屬性文件中可以這樣配置:userDao = com.test.MemoryUserDao。UserDao的工廠類將從這個(gè)屬性文件中取得UserDao實(shí)現(xiàn)類的全名,再通過(guò)Class.forName(className).newInstance()語(yǔ)句來(lái)自動(dòng)創(chuàng)建一個(gè)UserDao接口的具體實(shí)例。UserDaoFactory代碼如下:public class UserDaoFactory public static UserDao createUserDao() String className = ; / 從屬性文件中取得這個(gè)UserDao的實(shí)現(xiàn)類全名。 UserDao userDao = null; try userDao = (UserDao)Class.forName(className).newInstance(); catch (Exception e) e.printStackTrace(); return userDao; 通過(guò)對(duì)工廠模式的優(yōu)化,我們的方案已近乎完美。如果現(xiàn)在要更換持久化方式,不需要再做任何的手工編碼,只要修改配置文件中的userDao實(shí)現(xiàn)類名,將它設(shè)置為你需要更換的持久化類名即可。我們終于可以松下一口氣了?不,矛盾仍然存在。我們引入了接口,引入了工廠模式,讓我們的系統(tǒng)高度的靈活和可配置,同時(shí)也給開(kāi)發(fā)帶來(lái)了一些復(fù)雜度:1、本來(lái)只有一個(gè)實(shí)現(xiàn)類,后來(lái)卻要為這個(gè)實(shí)現(xiàn)類引入了一個(gè)接口。2、引入了一個(gè)接口,卻還需要額外開(kāi)發(fā)一個(gè)對(duì)應(yīng)的工廠類。3、工廠類過(guò)多時(shí),管理、維護(hù)非常困難。比如:當(dāng)UserDao的實(shí)現(xiàn)類是JdbcUserDao,它使用JDBC技術(shù)來(lái)實(shí)現(xiàn)用戶信息從持久化。也許要在取得JdbcUserDao實(shí)例時(shí)傳入數(shù)據(jù)庫(kù)Connection,這是仍少UserDaoFactory的硬編碼。當(dāng)然,面接口編程是實(shí)現(xiàn)軟件的可維護(hù)性和可重用行的重要原則已經(jīng)勿庸置疑。這樣,第一個(gè)復(fù)雜度問(wèn)題是無(wú)法避免的,再說(shuō)一個(gè)接口的開(kāi)發(fā)和維護(hù)的工作量是微不足道的。但后面兩個(gè)復(fù)雜度的問(wèn)題,我們是完全可以解決的:工廠模式的終極方案IoC模式。重構(gòu)第四步IoC容器使用IoC容器,用戶注冊(cè)類UserRegister不用主動(dòng)創(chuàng)建UserDao實(shí)現(xiàn)類的實(shí)例。由IoC容器主動(dòng)創(chuàng)建UserDao實(shí)現(xiàn)類的實(shí)例,并注入到用戶注冊(cè)類中。我們下面將使用Spring提供的IoC容器來(lái)管理我們的用戶注冊(cè)類。用戶注冊(cè)類UserRegister的部分代碼如下:public class UserRegister private UserDao userDao = null;/由容器注入的實(shí)例對(duì)象 public void setUserDao(UserDao userDao) this.userDao = userDao; / UserRegister的業(yè)務(wù)方法在其它的UserRegister方法中就可以直接使用userDao對(duì)象了,它的實(shí)例由Spring容器主動(dòng)為它創(chuàng)建。但是,如何組裝一個(gè)UserDao的實(shí)現(xiàn)類到UserRegister中呢?哦,Spring提供了配置文件來(lái)組裝我們的組件。Spring的配置文件applicationContext.xml代碼片斷如下:控制反轉(zhuǎn)(IoC)/依賴注入(DI)什么是控制反轉(zhuǎn)/依賴注入?控制反轉(zhuǎn)(IoC=Inversion of Control)IoC,用白話來(lái)講,就是由容器控制程序之間的(依賴)關(guān)系,而非傳統(tǒng)實(shí)現(xiàn)中,由程序代碼直接操控。這也就是所謂“控制反轉(zhuǎn)”的概念所在:(依賴)控制權(quán)由應(yīng)用代碼中轉(zhuǎn)到了外部容器,控制權(quán)的轉(zhuǎn)移,是所謂反轉(zhuǎn)。IoC也稱為好萊塢原則(Hollywood Principle):“Dont call us, well call you”。即,如果大腕明星想演節(jié)目,不用自己去找好萊塢公司,而是由好萊塢公司主動(dòng)去找他們(當(dāng)然,之前這些明星必須要在好萊塢登記過(guò))。正在業(yè)界為IoC爭(zhēng)吵不休時(shí),大師級(jí)人物Martin Fowler也站出來(lái)發(fā)話,以一篇經(jīng)典文章Inversion of Control Containers and the Dependency Injection pattern為IoC正名,至此,IoC又獲得了一個(gè)新的名字:“依賴注入 (Dependency Injection)”。相對(duì)IoC 而言,“依賴注入”的確更加準(zhǔn)確的描述了這種古老而又時(shí)興的設(shè)計(jì)理念。從名字上理解,所謂依賴注入,即組件之間的依賴關(guān)系由容器在運(yùn)行期決定,形象的來(lái)說(shuō),即由容器動(dòng)態(tài)的將某種依賴關(guān)系注入到組件之中。例如前面用戶注冊(cè)的例子。UserRegister依賴于UserDao的實(shí)現(xiàn)類,在最后的改進(jìn)中我們使用IoC容器在運(yùn)行期動(dòng)態(tài)的為UserRegister注入U(xiǎn)serDao的實(shí)現(xiàn)類。即UserRegister對(duì)UserDao的依賴關(guān)系由容器注入,UserRegister不用關(guān)心UserDao的任何具體實(shí)現(xiàn)類。如果要更改用戶的持久化方式,只要修改配置文件applicationContext.xm即可。依賴注入機(jī)制減輕了組件之間的依賴關(guān)系,同時(shí)也大大提高了組件的可移植性,這意味著,組件得到重用的機(jī)會(huì)將會(huì)更多。依賴注入的三種實(shí)現(xiàn)形式我們將組件的依賴關(guān)系由容器實(shí)現(xiàn),那么容器如何知道一個(gè)組件依賴哪些其它的組件呢?例如用戶注冊(cè)的例子:容器如何得知UserRegister依賴于UserDao呢。這樣,我們的組件必須提供一系列所謂的回調(diào)方法(這個(gè)方法并不是具體的Java類的方法),這些回調(diào)方法會(huì)告知容器它所依賴的組件。根據(jù)回調(diào)方法的不同,我們可以將IoC分為三種形式:Type1接口注入(Interface Injection)它是在一個(gè)接口中定義需要注入的信息,并通過(guò)接口完成注入。Apache Avalon是一個(gè)較為典型的Type1型IOC容器,WebWork框架的IoC容器也是Type1型。當(dāng)然,使用接口注入我們首先要定義一個(gè)接口,組件的注入將通過(guò)這個(gè)接口進(jìn)行。我們還是以用戶注冊(cè)為例,我們開(kāi)發(fā)一個(gè)InjectUserDao接口,它的用途是將一個(gè)UserDao實(shí)例注入到實(shí)現(xiàn)該接口的類中。InjectUserDao接口代碼如下:public interface InjectUserDao public void setUserDao(UserDao userDao);UserRegister需要容器為它注入一個(gè)UserDao的實(shí)例,則它必須實(shí)現(xiàn)InjectUserDao接口。UserRegister部分代碼如下:public class UserRegister implements InjectUserDao private UserDao userDao = null;/該對(duì)象實(shí)例由容器注入 public void setUserDao(UserDao userDao) this.userDao = userDao; / UserRegister的其它業(yè)務(wù)方法同時(shí),我們需要配置InjectUserDao接口和UserDao的實(shí)現(xiàn)類。如果使用WebWork框架則配置文件如下: request com.dev.spring.simple.MemoryUserDao com.dev.spring.simple.InjectUserDao這樣,當(dāng)IoC容器判斷出UserRegister組件實(shí)現(xiàn)了InjectUserDao接口時(shí),它就將MemoryUserDao實(shí)例注入到UserRegister組件中。Type2設(shè)值方法注入(Setter Injection)在各種類型的依賴注入模式中,設(shè)值注入模式在實(shí)際開(kāi)發(fā)中得到了最廣泛的應(yīng)用(其中很大一部分得力于Spring框架的影響)?;谠O(shè)置模式的依賴注入機(jī)制更加直觀、也更加自然。前面的用戶注冊(cè)示例,就是典型的設(shè)置注入,即通過(guò)類的setter方法完成依賴關(guān)系的設(shè)置。Type3構(gòu)造子注入(Constructor Injection)構(gòu)造子注入,即通過(guò)構(gòu)造函數(shù)完成依賴關(guān)系的設(shè)定。將用戶注冊(cè)示例該為構(gòu)造子注入,UserRegister代碼如下:public class UserRegister private UserDao userDao = null;/由容器通過(guò)構(gòu)造函數(shù)注入的實(shí)例對(duì)象 public UserRegister(UserDao userDao) this.userDao = userDao; /業(yè)務(wù)方法幾種依賴注入模式的對(duì)比總結(jié)接口注入模式因?yàn)闅v史較為悠久,在很多容器中都已經(jīng)得到應(yīng)用。但由于其在靈活性、易用性上不如其他兩種注入模式,因而在IOC的專題世界內(nèi)并不被看好。Type2和Type3型的依賴注入實(shí)現(xiàn)則是目前主流的IOC實(shí)現(xiàn)模式。這兩種實(shí)現(xiàn)方式各有特點(diǎn),也各具優(yōu)勢(shì)。Type2 設(shè)值注入的優(yōu)勢(shì)1 對(duì)于習(xí)慣了傳統(tǒng)JavaBean開(kāi)發(fā)的程序員而言,通過(guò)setter方法設(shè)定依賴關(guān)系顯得更加直觀,更加自然。2 如果依賴關(guān)系(或繼承關(guān)系)較為復(fù)雜,那么Type3模式的構(gòu)造函數(shù)也會(huì)相當(dāng)龐大(我們需要在構(gòu)造函數(shù)中設(shè)定所有依賴關(guān)系),此時(shí)Type2模式往往更為簡(jiǎn)潔。3 對(duì)于某些第三方類庫(kù)而言,可能要求我們的組件必須提供一個(gè)默認(rèn)的構(gòu)造函數(shù)(如Struts中的Action),此時(shí)Type3類型的依賴注入機(jī)制就體現(xiàn)出其局限性,難以完成我們期望的功能。Type3 構(gòu)造子注入的優(yōu)勢(shì):1 “在構(gòu)造期即創(chuàng)建一個(gè)完整、合法的對(duì)象”,對(duì)于這條Java設(shè)計(jì)原則,Type3無(wú)疑是最好的響應(yīng)者。2 避免了繁瑣的setter方法的編寫,所有依賴關(guān)系均在構(gòu)造函數(shù)中設(shè)定,依賴關(guān)系集中呈現(xiàn),更加易讀。3 由于沒(méi)有setter方法,依賴關(guān)系在構(gòu)造時(shí)由容器一次性設(shè)定,因此組件在被創(chuàng)建之后即處于相對(duì)“不變”的穩(wěn)定狀態(tài),無(wú)需擔(dān)心上層代碼在調(diào)用過(guò)程中執(zhí)行setter方法對(duì)組件依賴關(guān)系產(chǎn)生破壞,特別是對(duì)于Singleton模式的組件而言,這可能對(duì)整個(gè)系統(tǒng)產(chǎn)生重大的影響。4 同樣,由于關(guān)聯(lián)關(guān)系僅在構(gòu)造函數(shù)中表達(dá),只有組件創(chuàng)建者需要關(guān)心組件內(nèi)部的依賴關(guān)系。對(duì)調(diào)用者而言,組件中的依賴關(guān)系處于黑盒之中。對(duì)上層屏蔽不必要的信息,也為系統(tǒng)的層次清晰性提供了保證。5 通過(guò)構(gòu)造子注入,意味著我們可以在構(gòu)造函數(shù)中決定依賴關(guān)系的注入順序,對(duì)于一個(gè)大量依賴外部服務(wù)的組件而言,依賴關(guān)系的獲得順序可能非常重要,比如某個(gè)依賴關(guān)系注入的先決條件是組件的UserDao及相關(guān)資源已經(jīng)被設(shè)定??梢?jiàn),Type3和Type2模式各有千秋,而Spring、PicoContainer都對(duì)Type3和Type2類型的依賴注入機(jī)制提供了良好支持。這也就為我們提供了更多的選擇余地。理論上,以Type3類型為主,輔之以Type2類型機(jī)制作為補(bǔ)充,可以達(dá)到最好的依賴注入效果,不過(guò)對(duì)于基于Spring Framework開(kāi)發(fā)的應(yīng)用而言,Type2使用更加廣泛。BeanFactoryApplicationContextBeanFactory是Spring的“心臟”。它就是Spring IoC容器的真面目。Spring使用BeanFactory來(lái)實(shí)例化、配置和管理Bean。但是,在大多數(shù)情況我們并不直接使用BeanFactory,而是使用ApplicationContext。它也是BeanFactory的一個(gè)實(shí)現(xiàn),但是它添加了一系列“框架”的特征,比如:國(guó)際化支持、資源訪問(wèn)、事件傳播等。ApplicationContext我們將在后面章節(jié)中介紹。BeanFactoryBeanFactory其實(shí)是一個(gè)接口org.springframework.beans.factory.BeanFactory,它可以配置和管理幾乎所有的Java類。當(dāng)然,具體的工作是由實(shí)現(xiàn)BeanFactory接口的實(shí)現(xiàn)類完成。我們最常用的BeanFactory實(shí)現(xiàn)是org.springframework.beans.factory.xml.XmlBeanFactory。它從XML文件中讀取Bean的定義信息。當(dāng)BeanFactory被創(chuàng)建時(shí),Spring驗(yàn)證每個(gè)Bean的配置。當(dāng)然,要等Bean創(chuàng)建之后才能設(shè)置Bean的屬性。單例(Singleton)Bean在啟動(dòng)時(shí)就會(huì)被BeanFactory實(shí)例化,其它的Bean在請(qǐng)求時(shí)創(chuàng)建。根據(jù)BeanFactory的Java文檔(Javadocs)介紹,“Bean定義的持久化方式?jīng)]有任何的限制:LDAP、RDBMS、XML、屬性文件,等等”?,F(xiàn)在Spring已提供了XML文件和屬性文件的實(shí)現(xiàn)。無(wú)疑,XML文件是定義Bean的最佳方式。BeanFactory是初始化Bean和調(diào)用它們生命周期方法的“吃苦耐勞者”。注意,BeanFactory只能管理單例(Singleton)Bean的生命周期。它不能管理原型(prototype,非單例)Bean的生命周期。這是因?yàn)樵虰ean實(shí)例被創(chuàng)建之后便被傳給了客戶端,容器失去了對(duì)它們的引用。BeanFactory管理Bean(組件)的生命周期下圖描述了Bean的生命周期。它是由IoC容器控制。IoC容器定義Bean操作的規(guī)則,即Bean的定義(BeanDefinition)。Bean的定義包含了BeanFactory在創(chuàng)建Bean實(shí)例時(shí)需要的所有信息。BeanFactory首先通過(guò)構(gòu)造函數(shù)創(chuàng)建一個(gè)Bean實(shí)例,之后它會(huì)執(zhí)行Bean實(shí)例的一系列之前初始化動(dòng)作,初始化結(jié)束B(niǎo)ean將進(jìn)入準(zhǔn)備就緒(ready)狀態(tài),這時(shí)應(yīng)用程序就可以獲取這些Bean實(shí)例了。最后,當(dāng)你銷毀單例(Singleton)Bean時(shí),它會(huì)調(diào)用相應(yīng)的銷毀方法,結(jié)束B(niǎo)ean實(shí)例的生命周期。 (圖Bean的生命周期)Bean的定義前面的用戶注冊(cè)的例子中,我們已經(jīng)使用Spring定義了一個(gè)用戶持久化類:這是一個(gè)最簡(jiǎn)單的Bean定義。它類似于調(diào)用了語(yǔ)句:MemoryUserDao userDao = new MemoryUserDao()。id屬性必須是一個(gè)有效的XML ID,這意味著它在整個(gè)XML文檔中必須唯一。它是一個(gè)Bean的“終身代號(hào)(9527)”。同時(shí)你也可以用name屬性為Bean定義一個(gè)或多個(gè)別名(用逗號(hào)或空格分開(kāi)多個(gè)別名)。name屬性允許出現(xiàn)任意非法的XML字母。例如:。class屬性定義了這個(gè)Bean的全限定類名(包名類名)。Spring能管理幾乎所有的Java類。一般情況,這個(gè)Java類會(huì)有一個(gè)默認(rèn)的構(gòu)造函數(shù),用set方法設(shè)置依賴的屬性。Bean元素出了上面的兩個(gè)屬性之外,還有很多其它屬性。說(shuō)明如下:(14)(1)、id: Bean的唯一標(biāo)識(shí)名。它必須是合法的XML ID,在整個(gè)XML文檔中唯一。(2)、name: 用來(lái)為id創(chuàng)建一個(gè)或多個(gè)別名。它可以是任意的字母符合。多個(gè)別名之間用逗號(hào)或空格分開(kāi)。(3)、class: 用來(lái)定義類的全限定名(包名類名)。只有子類Bean不用定義該屬性。(4)、parent: 子類Bean定義它所引用它的父類Bean。這時(shí)前面的class屬性失效。子類Bean會(huì)繼承父類Bean的所有屬性,子類Bean也可以覆蓋父類Bean的屬性。注意:子類Bean和父類Bean是同一個(gè)Java類。(5)、abstract(默認(rèn)為”false”):用來(lái)定義Bean是否為抽象Bean。它表示這個(gè)Bean將不會(huì)被實(shí)例化,一般用于父類Bean,因?yàn)楦割怋ean主要是供子類Bean繼承使用。(6)、singleton(默認(rèn)為“true”):定義Bean是否是Singleton(單例)。如果設(shè)為“true”,則在BeanFactory作用范圍內(nèi),只維護(hù)此Bean的一個(gè)實(shí)例。如果設(shè)為“flase”,Bean將是Prototype(原型)狀態(tài),BeanFactory將為每次Bean請(qǐng)求創(chuàng)建一個(gè)新的Bean實(shí)例。(7)、lazy-init(默認(rèn)為“default”):用來(lái)定義這個(gè)Bean是否實(shí)現(xiàn)懶初始化。如果為“true”,它將在BeanFactory啟動(dòng)時(shí)初始化所有的Singleton Bean。反之,如果為“false”,它只在Bean請(qǐng)求時(shí)才開(kāi)始創(chuàng)建Singleton Bean。(8)、autowire(自動(dòng)裝配,默認(rèn)為“default”):它定義了Bean的自動(dòng)裝載方式。1、“no”:不使用自動(dòng)裝配功能。2、“byName”:通過(guò)Bean的屬性名實(shí)現(xiàn)自動(dòng)裝配。3、“byType”:通過(guò)Bean的類型實(shí)現(xiàn)自動(dòng)裝配。4、“constructor”:類似于byType,但它是用于構(gòu)造函數(shù)的參數(shù)的自動(dòng)組裝。5、“autodetect”:通過(guò)Bean類的反省機(jī)制(introspection)決定是使用“constructor”還是使用“byType”。(9)、dependency-check(依賴檢查,默認(rèn)為“default”):它用來(lái)確保Bean組件通過(guò)JavaBean描述的所以依賴關(guān)系都得到滿足。在與自動(dòng)裝配功能一起使用時(shí),它特別有用。1、 none:不進(jìn)行依賴檢查。2、 objects:只做對(duì)象間依賴的檢查。3、 simple:只做原始類型和String類型依賴的檢查4、 all:對(duì)所有類型的依賴進(jìn)行檢查。它包括了前面的objects和simple。(10)、depends-on(依賴對(duì)象):這個(gè)Bean在初始化時(shí)依賴的對(duì)象,這個(gè)對(duì)象會(huì)在這個(gè)Bean初始化之前創(chuàng)建。(11)、init-method:用來(lái)定義Bean的初始化方法,它會(huì)在Bean組裝之后調(diào)用。它必須是一個(gè)無(wú)參數(shù)的方法。(12)、destroy-method:用來(lái)定義Bean的銷毀方法,它在BeanFactory關(guān)閉時(shí)調(diào)用。同樣,它也必須是一個(gè)無(wú)參數(shù)的方法。它只能應(yīng)用于singleton Bean。(13)、factory-method:定義創(chuàng)建該Bean對(duì)象的工廠方法。它用于下面的“factory-bean”,表示這個(gè)Bean是通過(guò)工廠方法創(chuàng)建。此時(shí),“class”屬性失

溫馨提示

  • 1. 本站所有資源如無(wú)特殊說(shuō)明,都需要本地電腦安裝OFFICE2007和PDF閱讀器。圖紙軟件為CAD,CAXA,PROE,UG,SolidWorks等.壓縮文件請(qǐng)下載最新的WinRAR軟件解壓。
  • 2. 本站的文檔不包含任何第三方提供的附件圖紙等,如果需要附件,請(qǐng)聯(lián)系上傳者。文件的所有權(quán)益歸上傳用戶所有。
  • 3. 本站RAR壓縮包中若帶圖紙,網(wǎng)頁(yè)內(nèi)容里面會(huì)有圖紙預(yù)覽,若沒(méi)有圖紙預(yù)覽就沒(méi)有圖紙。
  • 4. 未經(jīng)權(quán)益所有人同意不得將文件中的內(nèi)容挪作商業(yè)或盈利用途。
  • 5. 人人文庫(kù)網(wǎng)僅提供信息存儲(chǔ)空間,僅對(duì)用戶上傳內(nèi)容的表現(xiàn)方式做保護(hù)處理,對(duì)用戶上傳分享的文檔內(nèi)容本身不做任何修改或編輯,并不能對(duì)任何下載內(nèi)容負(fù)責(zé)。
  • 6. 下載文件中如有侵權(quán)或不適當(dāng)內(nèi)容,請(qǐng)與我們聯(lián)系,我們立即糾正。
  • 7. 本站不保證下載資源的準(zhǔn)確性、安全性和完整性, 同時(shí)也不承擔(dān)用戶因使用這些下載資源對(duì)自己和他人造成任何形式的傷害或損失。

評(píng)論

0/150

提交評(píng)論