隨筆-28  評(píng)論-15  文章-81  trackbacks-0

          在本章中作者講解了SpringIoC概念,詳細(xì)介紹了如何配置我們自己的應(yīng)用系統(tǒng),如何編寫松耦合的組件。如何在XML中配置Bena

          這里提個(gè)建議,現(xiàn)在的Spring已經(jīng)升級(jí)到2.0版本了,而本書(《Spring in Action》)出版時(shí)還是Spring1.X2.0有了較大的變化建議新學(xué)Spring的人下載2.0版本的來(lái)學(xué)習(xí),現(xiàn)在最新的版本已經(jīng)是Rc3了。同時(shí)2.0版本的中文參考已經(jīng)在Spring中文論壇有人組織翻譯了。而且現(xiàn)在已經(jīng)有預(yù)覽版了,大家可以先參考一下。(Spring中文預(yù)覽版:http://www.jactiongroup.net/reference2/html/同時(shí)向無(wú)償翻譯Spring文檔的這些高手們致敬。

           

          一、容納你的Bean

          容器是Spring的核心。Spring使用IoC管理所有組成應(yīng)用系統(tǒng)的組件。Spring有兩種不同的容器:

          l         Bena工廠(BeanFactory):由org.springframework.beans.factory.BeanFactory接口定義。是最簡(jiǎn)單的容器,提供了基礎(chǔ)的依賴注入支持。

          l         應(yīng)用上下文(ApplicationContext):由org.springframework.context.ApplicationContext接口定義。建立在Bean工廠之上提供了系統(tǒng)架構(gòu)服務(wù)。

          1BeanFactory介紹

                 見(jiàn)名知意,BeanFactory采用了工廠模式(抽象工廠模式http://blog.csdn.net/qutr/archive/2006/01/22/586034.aspx工廠方法模式http://blog.csdn.net/qutr/archive/2006/07/21/954070.aspx)。這個(gè)類專門負(fù)責(zé)創(chuàng)建類(對(duì)象)。有些書上說(shuō)SpringBeanFactory像一個(gè)超負(fù)荷運(yùn)轉(zhuǎn)的機(jī)器,因?yàn)槌撕?jiǎn)單的創(chuàng)建對(duì)象以外,BeanFactory可以在實(shí)例化這些對(duì)象的時(shí)候,創(chuàng)建協(xié)作對(duì)象間的關(guān)聯(lián)關(guān)系。這樣就把配置的負(fù)擔(dān)從Bean自身以及Bean的調(diào)用者中脫離出來(lái)。更詳細(xì)的可以查看BeanFactory的源代碼。

          Spring中有幾種BeanFactory的實(shí)現(xiàn)。其中最長(zhǎng)用的是org.springframework.beans.factory.xml.XmlBeanFactory,它根據(jù)XML文件中的定義裝載Bean。在XmlBeanFactory類中提供了兩個(gè)構(gòu)造函數(shù),通常我們用的是XmlBeanFactory(Resource resource) throws BeansException這個(gè)。他一般這樣定義:BeanFactory factory = new XmlBeanFactory(new FileSystemResource(“beans.xml”));其中傳遞的參數(shù)引用為:import org.springframework.core.io.FileSystemResource;書中這里是不太正確的,因?yàn)樵?/span>Spring2.0里已經(jīng)不提供傳遞java.io.InputStream對(duì)象的構(gòu)造函數(shù)了。翻譯者非常的不負(fù)責(zé)任,應(yīng)該在這里給出說(shuō)明。

          BeanFactory得到一個(gè)Bean只需調(diào)用getBean(“beanName”)方法,把你需要的Bean的名字當(dāng)作參數(shù)傳遞進(jìn)去就可以了。像這樣:MyBean myBean = (MyBean)factory.getBean(“myBean”);當(dāng)getBean()方法被調(diào)用的時(shí)候,工廠就會(huì)開(kāi)始實(shí)例化Bean 并且使用依賴注入開(kāi)始設(shè)置Bean的屬性。

          事實(shí)上BeanFactory接口提供有6種方法供客戶代碼調(diào)用:

          1boolean containsBean(String): 如果BeanFactory包含符合給定名稱的Bean定義或Bean實(shí)例,則返回true

          2Object getBean(String): 返回以給定名字注冊(cè)的Bean實(shí)例。就是上面提到的最簡(jiǎn)單的一種。

          3Object getBean(String, Class): 返回以給定名稱注冊(cè)的Bean,返回的Bean將被扔給(cast)給定的類。如果Bean不能被Cast,相應(yīng)的異常(BeanNotOfRequiredTypeException)將被拋出。

          4Class getType(String name): 返回給定名稱的BeanClass。如果沒(méi)有相應(yīng)于給定名稱的Bean,則拋出NoSuchBeanDefinitionException異常。

          5boolean isSingleton(String): 決定在給定名稱時(shí),Bean定義或Bean實(shí)例注冊(cè)是否為單件模式,如果相應(yīng)于給定名稱的Bean不能被找到,則拋出NoSuchBeanDefinitionException異常。

          6String[] getAliases(String): 如果在Bean的定義中有定義,則返回給定Bean名稱的別名。

          2.使用應(yīng)用上下文(ApplicationContext

          使用ApplicationContext可以獲得Sroing框架的強(qiáng)大功能。表面上ApplicationContextBeanFactory差不多,但是ApplicationContext提供了更多的功能:

          l         ApplicationContext提供了文本信息解析工具,包括對(duì)國(guó)際化的支持。

          l         ApplicationContext提供了載入文件資源的通用方法,如載入圖片。

          l         ApplicationContext可以向注冊(cè)為監(jiān)聽(tīng)器的Bean發(fā)送事件。

          l         ApplicationContextSpring2.0里可能還加了其他功能。

          有三種ApplicationContext的實(shí)現(xiàn)經(jīng)常被用到:

          l         ClassPathXmlApplicationContext—從類路徑中的XML文件載入上下文定義信息,把上下文定義文件當(dāng)成類路徑資源。(可以在整個(gè)類路徑中尋找XML文件)

          l         FileSystemXmlApplicationContext—從文件系統(tǒng)中的XML文件載入上下文定義信息。(只能在指定的路徑中尋找XML文件)

          l         XmlWebApplicationContext—Web系統(tǒng)中的XMLwenjian 載入上下文定義信息。

          其中FileSystemXmlApplicationContextClassPathXmlApplicationContext(他們都包含在org.springframework.context.support包下)的使用形式分別如下:

          ApplicationContext context = new FileSystemXmlApplicationContext(“c:/foo.xml”);

          ApplicationContext context2 = new ClassPathXmlApplicationContext(“foo.xml”)

          應(yīng)用上下文會(huì)在上下文啟動(dòng)后預(yù)載入所有的單實(shí)例Bean。確保當(dāng)你需要的時(shí)候他們已經(jīng)準(zhǔn)備好了你的應(yīng)用不需要等待他們被創(chuàng)建。

          總之實(shí)例化一個(gè)Bean大概有三種方法:

          第一種:

          Resource resource = new FileSystemResource("beans.xml");

          BeanFactory factory = new XmlBeanFactory(resource);

          第二種:

          ClassPathResource resource = new ClassPathResource("beans.xml");

          BeanFactory factory = new XmlBeanFactory(resource);

          第三種:

          ApplicationContext context = new ClassPathXmlApplicationContext(new String[] {"applicationContext.xml", "applicationContext-part2.xml"});

          BeanFactory factory = (BeanFactory) context;

          ApplicathionContext的超類是BeanFactory,所以理所當(dāng)然的這里的context可以是BeanFactory

          3Bean的生命周期

          在書中作者用圖文并茂的方式解說(shuō)了BeanBeanFactoryApplicationContext中的生命周期,從創(chuàng)建到銷毀的全過(guò)程。他們二者之間略有不同,書上講的比較詳細(xì),這里就不羅列了。

           

          二、基本裝配

          Spring容器內(nèi)拼湊Bean叫做裝配。裝配Bean的時(shí)候,你是在告訴容器需要哪些Bean以及容器如何使用依賴注入將他們配合在一起。

          1.使用XML裝配

          Bean裝配在Spring中最常用的是XML文件。在前面提到過(guò)的XmlBeanFactoryClassPathXmlApplicationContextFileSystemXmlApplicationContextXmlWebApplicationContext都支持用XML裝配Bean

          Spring規(guī)定了自己的XML文件格式,根元素為<Beans><Beans>有多個(gè)<Bean>子元素。每個(gè)<Bean>定義了一個(gè)Bean如何被裝載到Spring容器中。看下面的名為test.xmlXML文件:

          <?xml version="1.0" encoding="UTF-8"?>

          <!DOCTYPE beans PUBLIC "-//SPRING//DTD BEAN//EN" "http://www.springframework.org/dtd/spring-beans.dtd">

          <beans>

              <bean id = "foo"

                    class = "springinaction.foo">

              </bean>

              <bean id = "bar"

                   class = "springinaction.bar">

              </bean>

          </beans>

          Spring中,對(duì)一個(gè)Bean的最基本的配置包括BeanID和他的類全稱。在test.xml文件中其中<Beans>為根元素,bean id=”foo”標(biāo)明一個(gè)Bean他的Idfoo,此處的foo是由程序員自己命名的,但是在一個(gè)大的系統(tǒng)中有好多個(gè)Bean這里要求XML中的Id要唯一,在程序代碼中如果想取得foo這個(gè)Bean就要用getBean(“foo”)了。class=”springinaction.foo”Bean的全稱類名。

          2.添加一個(gè)Bean

          Spring中的Bean在缺省情況下是單實(shí)例模式(也叫單態(tài)模式,http://blog.csdn.net/qutr/archive/2006/02/28/611868.aspx)。如果想每次從容器中得到得到一個(gè)Bean的不同實(shí)例,需要將Bean定義為原型模式(http://blog.csdn.net/qutr/archive/2006/07/24/968297.aspx)。我們可以用Beansingleton屬性來(lái)設(shè)置,缺省情況為true

          <bean id = "foo"

                    class = "springinaction.foo"

                    singleton="false">

              Bean的定義中用init-method來(lái)初始化某些參數(shù),用destroy-method來(lái)銷毀對(duì)象。

          <bean id = "foo"

                    class = "springinaction.foo"

                    singleton="false"

                    init-method="init"

                    destroy-method="destory">

              Spring也提供了兩個(gè)接口來(lái)實(shí)現(xiàn)相同的功能:InitializingBeanDisposableBean

          3.通過(guò)Set方法注入依賴。

          寫過(guò)JavaBean的人可能都熟悉getset方法。Spring就是用Set注入來(lái)配置Bean的。<bean>的子元素<property>指明了使用它們的set方法來(lái)注入。你可以注入任何類型。

          每個(gè)Bean(通常就是你定義的一個(gè)class)通常都會(huì)有一些簡(jiǎn)單的類型成員,如intString等等。通過(guò)使用<property>的子元素<value>可以設(shè)置基本類型的屬性(值)。

          <bean id = "bar" class = "springinaction.bar">

                  <property name="barName">

                      <value>coffeeBar</value>

                  </property>

          </bean>

          如上所示,在我們的springinaction.bar類中定義了一個(gè)名為barNameString類型的成員,用<value>coffeeBar</value>中的coffeeBar來(lái)給他設(shè)置值。如:setName(barName);如果定義了一個(gè)int類型的成員我們可以在<value></value>中寫入一個(gè)數(shù)字。

          利用property豐富的屬性我們可以為一個(gè)Bean引用其它Bean,通過(guò)<ref>實(shí)現(xiàn);可以嵌入一個(gè)內(nèi)部Bean,通常很少使用。可以裝配各種集合,如java.util.List, java.util.Set, java.util.Map等等。可以設(shè)置propertiesnull值。

          下面給出一個(gè)例子,這個(gè)例子同樣來(lái)自官方文檔。

          <bean id="moreComplexObject" class="example.ComplexObject">

           <!-- java.util.Properties -->

           <property name="adminEmails">

              <props>

                  <prop key="administrator">administrator@somecompany.org</prop>

                  <prop key="support">support@somecompany.org</prop>

                  <prop key="development">development@somecompany.org</prop>

              </props>

           </property>

           <!-- java.util.List -->

           <property name="someList">

              <list>

                  <value>a list element followed by a reference</value>

                  <ref bean="myDataSource" />

              </list>

           </property>

           <!-- java.util.Map -->

           <property name="someMap">

              <map>

                  <entry>

                      <key>

                          <value>yup an entry</value>

                      </key>

                      <value>just some string</value>

                  </entry>

                  <entry>

                      <key>

                          <value>yup a ref</value>

                      </key>

                     <ref bean="myDataSource" />

                  </entry>

              </map>

           </property>

           <!-- java.util.Set -->

           <property name="someSet">

              <set>

                  <value>just some string</value>

                  <ref bean="myDataSource" />

              </set>

           </property>

          </bean>

          一目了然,非常清楚就不多解釋了。關(guān)于集合Spring2.0又添加了新的內(nèi)容,如:你如果使用的是JDK1.5那么還可以使用Java的泛型來(lái)清晰的解析各種容器所包含的類型,請(qǐng)參看:http://static.springframework.org/spring/docs/2.0.x/reference/beans.html#beans-collection-elements

          4.通過(guò)構(gòu)造函數(shù)注入依賴

          Set注入是Srping所推薦的,但是Set注入的缺點(diǎn)是,他無(wú)法清晰的表示出哪些屬性是必須的,哪些是可選的。而使用構(gòu)造函數(shù)注入的優(yōu)勢(shì)是通過(guò)構(gòu)造函數(shù)來(lái)強(qiáng)制以來(lái)關(guān)系,有了構(gòu)造函數(shù)的約束不可能實(shí)現(xiàn)一個(gè)不完全或無(wú)法使用的Bean

          <bean id="coo" class="springinaction.coo">

                  <constructor-arg>

                      <value>cool</value>

                  </constructor-arg>

              </bean>

          上面的例子通過(guò)構(gòu)造函數(shù)傳值來(lái)實(shí)例化一個(gè)coo對(duì)象。如coo co = new coo(“cool”);

          如果有多個(gè)構(gòu)造函數(shù),那么可以設(shè)置<constructor-arg>的type或index來(lái)傳入?yún)?shù)了如果類型都一樣那么只能用index了,index的值是從0開(kāi)始的。

          Spring為我們提供了Set注入和構(gòu)造函數(shù)注入,在兩者的使用方式上個(gè)人有個(gè)人的理由和不同見(jiàn)解,在本書中作者給我們的建議大概是:看情況,那個(gè)合適用哪個(gè)(廢話J)。但是,Spring的開(kāi)發(fā)團(tuán)隊(duì)通常提倡人們使用setter注入。其實(shí)Spring一共給我提供了三種注入方式:接口注入和上面的兩種注入。他們都有各自的優(yōu)點(diǎn),詳細(xì)的說(shuō)明見(jiàn)《Spring開(kāi)發(fā)指南》。

          下面再給出兩個(gè)例子來(lái)說(shuō)明一下Setter注入和constructor注入:

          <bean id="exampleBean"

                  class="examples.ExampleBean">

             

               <!-- 用嵌套的 <ref/> 元素進(jìn)行setter注入 -->

              <property name="beanOne">

                  <ref bean="anotherExampleBean"/>

              </property>

             

              <!-- 用嵌套的 'ref' 屬性進(jìn)行setter注入 (注意:如果你看得是翻譯的2.0的預(yù)覽版這里是錯(cuò)誤的,請(qǐng)和官方的英文版對(duì)照看)-->

              <property name="beanTwo" ref = "yetAnotherBean"/><!我這里是正確的,2.0的中文預(yù)覽版這里寫錯(cuò)了-->

             

               <property name="integerProperty" value="1"/>

              </bean>

           

              <bean id="anotherExampleBean" class="examples.AnotherBean"/>

              <bean id="yetAnotherBean" class="examples.YetAnotherBean"/>

          Spring提供了快捷的ref屬性,來(lái)代替ref元素,但是使用ref屬性你要小!

          下面是一個(gè)類

          publicclass ExampleBean

          {

           

              private AnotherBean beanOne;

              private YetAnotherBean beanTwo;

              privateinti;

           

              publicvoid setBeanOne(AnotherBean beanOne) {

                  this.beanOne = beanOne;

              }

           

              publicvoid setBeanTwo(YetAnotherBean beanTwo) {

                  this.beanTwo = beanTwo;

              }

           

              publicvoid setIntegerProperty(int i) {

                  this.i = i;

              }   

          }

          上面是一個(gè)Bean(其實(shí)就是一個(gè)普通的不能在普通的Java類)和它相對(duì)應(yīng)的XML的配置文件,是一個(gè)典型的setter注入。例子清晰易懂就不多說(shuō)了。

          <bean id="exampleBean"

                  class="examples.ExampleBean">

             

              <!-- 用嵌套的 <ref/> 元素進(jìn)行構(gòu)造函數(shù)注入 -->

              <constructor-arg>

                  <ref bean="anotherExampleBean"/>

              </constructor-arg>

             

              <!-- 用嵌套的 'ref' 屬性進(jìn)行構(gòu)造函數(shù)注入 -->

              <constructor-arg ref="yetAnotherBean"/>

               

              <constructor-arg type="int" value="1"/>

              </bean>

             

              <bean id="anotherExampleBean" class="examples.AnotherBean"/>

              <bean id="yetAnotherBean" class="examples.YetAnotherBean"/>

          下面是一個(gè)類

          publicclass ExampleBean

          {

              private AnotherBean beanOne;

              private YetAnotherBean beanTwo;

              privateinti;

             

              public ExampleBean(AnotherBean anotherBean, YetAnotherBean yetAnotherBean, int i)

              {

                  this.beanOne = anotherBean;

                  this.beanTwo = yetAnotherBean;

                  this.i = i;

              }

          }

          上面是一個(gè)Bean和它相對(duì)應(yīng)的XML的配置文件,是一個(gè)典型的constructor注入。例子也比較清晰易懂這里也就不多說(shuō)了。

           

          三、自動(dòng)裝配

          在前面講到的都是手動(dòng)顯示裝配Bean的方法,Spring還提供了自動(dòng)裝配Bean的方法。只要設(shè)置<Bean>autowire屬性。有四種自動(dòng)裝配類型:

          l         byName:在容器中尋找和需要自動(dòng)裝配的屬性名相同的Bean(或ID)。如果沒(méi)有找到這個(gè)屬性就沒(méi)有裝配上。

          l         byType:在容器中尋找一個(gè)與自動(dòng)裝配的屬性類型相同的Bean。如果沒(méi)有找到這個(gè)屬性就沒(méi)有裝配上。如果找到超過(guò)一個(gè)則拋出org.springframework.beans.factory.UnsatisfiedDependencyException異常。

          l         constructor:在容器中查找與需要自動(dòng)裝配的Bean的構(gòu)造函數(shù)參數(shù)一致的一個(gè)或多個(gè)Bean。如果存在不確定Bean或構(gòu)造函數(shù)容器會(huì)拋出org.springframework.beans.factory.UnsatisfiedDependencyException異常。

          l         autodetect:首先嘗試使用constuctor來(lái)自動(dòng)裝配,然后使用byType方式。不確定性的處理與constructor方式和byType方式一樣,都拋出org.springframework.beans.factory.UnsatisfiedDependencyException異常。

          如下實(shí)例:

          在前面的顯示裝配:

          <bean id="courseService"

                  class="springinaction.chapter02.CourseServiceImpl">

                  <property name="courseDao">

                      <ref bean="courseDao"/>

                  </property>

                  <property name="studentService">

                      <ref bean="studentService"/>

                  </property>

              </bean>

          下面是自動(dòng)裝配:

          <bean id="courseService"

                  class="springinaction.chapter02.CourseServiceImpl"

                  autowire="byName"/>

          Spring對(duì)Bean自動(dòng)裝配的過(guò)程中很容易出現(xiàn)不確定性,這些不確定性會(huì)導(dǎo)致程序無(wú)法運(yùn)行。那么在我們的實(shí)際應(yīng)用中要避免出現(xiàn)裝配的不確定性。避免裝配的不確定性的最好的方法就是使用顯示裝配和自動(dòng)裝配的混合方法。對(duì)有二義性的Bena使用顯示裝配,對(duì)沒(méi)有二義性的Bean使用自動(dòng)裝配。

           

          在通常情況下我們會(huì)分門別類的吧Bena設(shè)置在多個(gè)XML文件中。另外一種方法是使用一個(gè)或多個(gè)的<import/>(就像我們寫Java程序要引入必要的包下的類一樣)元素來(lái)從另外一個(gè)或多個(gè)文件加載Bean定義。需要注意的是:任何<import/>元素必須放在配置文件中的<bean/>元素之前以完成Bean定義的導(dǎo)入。如下示例:

          <beans>

          <import resource="services.xml"/>

          <import resource="resources/messageSource.xml"/>

          <import resource="/resources/themeSource.xml"/>

          <bean id="bean1" class="..."/>

          <bean id="bean2" class="..."/>

          <beans/>

          上例中,三行import引入了必要的XML文件。兩行bean定義了Bean依照XMLSchemaDTD,被導(dǎo)入文件必須是完全有效的XMLBean定義文件,且包含上層的<beans/>元素。

           

          四、使用Spring的特殊Bean和應(yīng)用舉例

                 在書中談到的Spring的特殊Bean的使用方法,我個(gè)人覺(jué)得這時(shí)SpringIoC的高級(jí)用法或者是邊角用法,由于我也是新手初學(xué)這里就不多啰嗦了,等以后在實(shí)踐中有了體會(huì)在補(bǔ)上,關(guān)于這方面的內(nèi)容在Spring2.0的官方文檔上都有提到,這份文檔非常的詳細(xì),我個(gè)人覺(jué)得只要把這份文檔好好看了其他的書甚至可以放在一邊了,當(dāng)然Rod寫的書還是要好好看的。

                 關(guān)于應(yīng)用舉例,本書中在這章舉的例子不是很全面,剛開(kāi)了個(gè)頭后面感覺(jué)就不說(shuō)了。我本來(lái)想將我最近正做的一個(gè)實(shí)際應(yīng)用中的例子放到這里,但是我的這個(gè)程序好像有點(diǎn)為了SpringSpring所以讓我改了又改,至今也沒(méi)有出來(lái)所以也就不再這里顯示了。等以后專門寫一篇文章來(lái)討論一下。

           

          五、小結(jié)

                 Spring框架的核心是Spring容器。BeanFactory是最簡(jiǎn)單的容器,他提供了最基本的依賴注入和Bean裝配服務(wù)。但是,畢竟Spring是一個(gè)輕量級(jí)框架,要想得到更多的高級(jí)框架服務(wù)時(shí)我們需要使用ApplicationContext容器,所以為了讓你的應(yīng)用程序看起來(lái)更高級(jí)更上檔次盡量多的使用ApplicationContext,這也是本書作者所提倡的。

          其實(shí)關(guān)于SpringIoC的核心和大部分內(nèi)容在上面的文字中已經(jīng)提到了,說(shuō)來(lái)說(shuō)去表面上就那些東西了。而IoCDI)的真正思想是要靠大量的實(shí)踐去體會(huì)和領(lǐng)悟的。

          上面是我對(duì)書中知識(shí)點(diǎn)的羅列和自己的一點(diǎn)理解(約占1%100J)請(qǐng)大家指教!

          posted on 2007-10-23 21:43 譚明 閱讀(866) 評(píng)論(0)  編輯  收藏 所屬分類: Spring
          主站蜘蛛池模板: 莱西市| 鹿泉市| 柳江县| 江陵县| 利辛县| 泗洪县| 微博| 息烽县| 婺源县| 伊金霍洛旗| 台江县| 太和县| 炉霍县| 台南县| 呼伦贝尔市| 红桥区| 肇源县| 全南县| 阳春市| 扶绥县| 柳州市| 蒲城县| 临洮县| 营山县| 巨野县| 碌曲县| 贵南县| 高密市| 南丰县| 香港| 白朗县| 中牟县| 台中市| 长宁县| 山阴县| 得荣县| 东乡| 余江县| 晋州市| 瓮安县| 吉安市|