java黃土地

          太空里的一滴水珠

            BlogJava :: 首頁 :: 新隨筆 :: 聯(lián)系 :: 聚合  :: 管理 ::
           

          1

          Spring IoC容器的實例化非常簡單,如下面的例子:

          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"});
          // of course, an ApplicationContext is just a BeanFactory
          BeanFactory factory = (BeanFactory) context;

          2

          2.1. 用構(gòu)造器來實例化

          當采用構(gòu)造器來創(chuàng)建bean實例時,Springclass并沒有特殊的要求,我們通常使用的class都適用。也就是說,被創(chuàng)建的類并不需要實現(xiàn)任何特定的接口,或以特定的方式編碼,只要指定beanclass屬性即可。不過根據(jù)所采用的IoC類型,class可能需要一個默認的空構(gòu)造器。

          <bean id="exampleBean" class="examples.ExampleBean"/>

          <bean name="anotherExample" class="examples.ExampleBeanTwo"/>

          2.2. 使用 靜態(tài)工廠方法實例化

          當采用靜態(tài)工廠方法創(chuàng)建bean時,除了需要指定class屬性外,還需要通過factory-method屬性來指定創(chuàng)建bean實例的工廠方法。Spring將調(diào)用此方法(其可選參數(shù)接下來介紹)返回實例對象,就此而言,跟通過普通構(gòu)造器創(chuàng)建類實例沒什么兩樣。

          下面的bean定義展示了如何通過工廠方法來創(chuàng)建bean實例。注意,此定義并未指定返回對象的類型,僅指定該類包含的工廠方法。在此例中, createInstance()必須是一個static方法。

          <bean id="exampleBean"
                class="examples.ExampleBean2"
                factory-method="createInstance"/>
          2.3. 使用實例工廠方法實例化

          使用靜態(tài)工廠方法實例化類似,用來進行實例化的實例工廠方法位于另外一個已有的bean中,容器將調(diào)用該bean的工廠方法來創(chuàng)建一個新的bean實例

          為使用此機制,class屬性必須為空,而factory-bean屬性必須指定為當前(或其祖先)容器中包含工廠方法的bean的名稱,而該工廠bean的工廠方法本身必須通過factory-method屬性來設(shè)定(參看以下的例子)

          <!-- the factory bean, which contains a method called createInstance() -->
          <bean id="myFactoryBean" class="...">
           ...
          </bean>
           <!-- the bean to be created via the factory bean -->
          <bean id="exampleBean"
                factory-bean="myFactoryBean"
                factory-method="createInstance"/>

          3.3.1注入依賴

          依賴注入DI)背后的基本原理是對象之間的依賴關(guān)系(即一起工作的其它對象)只會通過以下幾種方式來實現(xiàn):構(gòu)造器的參數(shù)、工廠方法的參數(shù),或給由構(gòu)造函數(shù)或者工廠方法創(chuàng)建的對象設(shè)置屬性。

          DI主要有兩種注入方式,即Setter注入 構(gòu)造器注入3.3.1.1. Setter注入

          通過調(diào)用無參構(gòu)造器或無參static工廠方法實例化bean之后,調(diào)用該beansetter方法,即可實現(xiàn)基于setterDI

          public class SimpleMovieLister {
                // the SimpleMovieLister has a dependency on the MovieFinder
              private MovieFinder movieFinder;
                // a setter method so that the Spring container can 'inject' a MovieFinder
              public void setMoveFinder(MovieFinder movieFinder) {
                  this.movieFinder = movieFinder;
              }
              
              // business logic that actually 'uses' the injected MovieFinder is omitted...

          }

          3.3.1.2. 構(gòu)造器注入

          基于構(gòu)造器DI通過調(diào)用帶參數(shù)的構(gòu)造器來實現(xiàn),每個參數(shù)代表著一個協(xié)作者。此外,還可通過給靜態(tài)工廠方法傳參數(shù)來構(gòu)造bean

          public class SimpleMovieLister {

                // the SimpleMovieLister has a dependency on the MovieFinder

              private MovieFinder movieFinder;

                // a constructor so that the Spring container can 'inject' a MovieFinder

              public SimpleMovieLister(MovieFinder movieFinder) {

                  this.movieFinder = movieFinder;

              }

             

              // business logic that actually 'uses' the injected MovieFinder is omitted...

          }最后,我們還要提到的一點就是,當協(xié)作bean被注入到依賴bean時,協(xié)作bean必須在依賴bean之前完全配置好。例如bean Abean B存在依賴關(guān)系,那么Spring IoC容器在調(diào)用bean Asetter方法之前,bean B必須被完全配置,這里所謂完全配置的意思就是bean將被實例化(如果不是采用提前實例化的singleton模式),相關(guān)的依賴也將被設(shè)置好,而且所有相關(guān)的lifecycle方法(如IntializingBeaninit方法以及callback方法)也將被調(diào)用。

          3.3.2構(gòu)造器參數(shù)的解析

          構(gòu)造器參數(shù)將根據(jù)類型來進行匹配。如果bean定義中的構(gòu)造器參數(shù)類型明確,那么bean定義中的參數(shù)順序就是對應(yīng)構(gòu)造器參數(shù)的順序。考慮以下的類...

          package x.y;
           public class Foo {
                public Foo(Bar bar, Baz baz) {
                  // ...
              }
          }

          這里的參數(shù)類型非常明確(當然前提是假定類BarBaz在繼承層次上并無任何關(guān)系)。因此下面的配置將會很好地工作,且無須顯式地指定構(gòu)造器參數(shù)索引及其類型。

          <beans>
              <bean name="foo" class="x.y.Foo">
                  <constructor-arg>
                      <bean class="x.y.Bar"/>
                  </constructor-arg>
                  <constructor-arg>
                      <bean class="x.y.Baz"/>
                  </constructor-arg>
              </bean>
          </beans>

          當引用的bean類型已知,則匹配沒有問題(如上述的例子)。但是當使用象<value>true<value>這樣的簡單類型時,Spring將無法決定該值的類型,因而僅僅根據(jù)類型是無法進行匹配的。考慮以下將在下面兩節(jié)使用的類:

          package examples;
           public class ExampleBean {
                // No. of years to the calculate the Ultimate Answer
              private int years;
              
              // The Answer to Life, the Universe, and Everything
              private String ultimateAnswer;
                public ExampleBean(int years, String ultimateAnswer) {
                  this.years = years;
                  this.ultimateAnswer = ultimateAnswer;
              }

          }

          3.3.2.1. 構(gòu)造器參數(shù)類型匹配

          針對上面的這種情況,我們可以在構(gòu)造器參數(shù)定義中使用type屬性來顯式的指定參數(shù)所對應(yīng)的簡單類型。例如:

          <bean id="exampleBean" class="examples.ExampleBean">
           <constructor-arg type="int" value="7500000"/>
           <constructor-arg type="java.lang.String" value="42"/>
          </bean>

          3.3.2.2. 構(gòu)造器參數(shù)的索引

          通過使用index屬性可以顯式的指定構(gòu)造器參數(shù)出現(xiàn)順序。例如:

          <bean id="exampleBean" class="examples.ExampleBean">
           <constructor-arg index="0" value="7500000"/>
           <constructor-arg index="1" value="42"/>
          </bean>

          使用index屬性除了可以解決多個簡單類型構(gòu)造參數(shù)造成的模棱兩可的問題之外,還可以用來解決兩個構(gòu)造參數(shù)類型相同造成的麻煩。注意:index屬性值從0開始

          提示

          指定構(gòu)造器參數(shù)索引是使用構(gòu)造器IoC首選的方式。

          3.3.3.1.1. idref元素

          idref元素用來將容器內(nèi)其它beanid傳給<constructor-arg/> <property/>元素,同時提供錯誤驗證功能。

          <bean id="theTargetBean" class="..."/>
           <bean id="theClientBean" class="...">
              <property name="targetName">
                  <idref bean="theTargetBean" />
              </property>
          </bean>

          上述bean定義片段完全地等同于(在運行時)以下的片段:

          <bean id="theTargetBean" class="..."/>
           <bean id="client" class="...">
              <property name="targetName">
                  <value>theTargetBean</value>
              </property>
          </bean>

          第一種形式比第二種更可取的主要原因是,使用idref標記允許容器在部署時 驗證所被引用的bean是否存在。而第二種方式中,傳給client beantargetName屬性值并沒有被驗證。任何的輸入錯誤僅在client bean實際實例化時才會被發(fā)現(xiàn)(可能伴隨著致命的錯誤)。如果client bean prototype類型的bean,則此輸入錯誤(及由此導致的異常)可能在容器部署很久以后才會被發(fā)現(xiàn)。

          此外,如果被引用的bean在同一XML文件內(nèi),且bean名字就是bean id,那么可以使用local屬性,此屬性允許XML解析器在解析XML文件時來對引用的bean進行驗證。

          <property name="targetName">
             <!-- a bean with an id of 'theTargetBean' must exist, else an XML exception will be thrown -->
             <idref local="theTargetBean"/>
          </property>

          3.3.3.2. 引用其它的bean(協(xié)作者)

          <constructor-arg/><property/>元素內(nèi)部還可以使用ref元素。該元素用來將bean中指定屬性的值設(shè)置為對容器中的另外一個bean的引用。如前所述,該引用bean將被作為依賴注入,而且在注入之前會被初始化(如果是singleton bean則已被容器初始化)。

          第一種形式也是最常見的形式是通過使用<ref/>標記指定bean屬性的目標bean,通過該標簽可以引用同一容器或父容器內(nèi)的任何bean(無論是否在同一XML文件中)。

          <ref bean="someBean"/>

          第二種形式是使用reflocal屬性指定目標bean,它可以利用XML解析器來驗證所引用的bean是否存在同一文件中。local屬性值必須是目標beanid屬性值。如果在同一配置文件中沒有找到引用的beanXML解析器將拋出一個例外。如果目標bean是在同一文件內(nèi),使用local方式就是最好的選擇(為了盡早地發(fā)現(xiàn)錯誤)。

          <ref local="someBean"/>

          第三種方式是通過使用refparent屬性來引用當前容器的父容器中的beanparent屬性值既可以是目標beanid值,也可以是name屬性值。而且目標bean必須在當前容器的父容器中。使用parent屬性的主要用途是為了用某個與父容器中的bean同名的代理來包裝父容器中的一個bean

          <bean id="accountService" class="com.foo.SimpleAccountService">
              <!-- insert dependencies as required as here -->
          </bean>
          <!-- in the child (descendant) context -->
          <bean id="accountService" <-- notice that the name of this bean is the same as the name of the 'parent' bean
                class="org.springframework.aop.framework.ProxyFactoryBean">
                <property name="target">
                    <ref parent="accountService"/> <-- notice how we refer to the parent bean
                </property>
              <!-- insert other configuration and dependencies as required as here -->
          </bean>

          ('parent'屬性的使用并不常見。)

          3.3.3.5. Nulls

          <null/>用于處理null值。Spring會把屬性的空參數(shù)當作空字符串處理。以下的xml片斷將email屬性設(shè)為空字符串

          <bean class="ExampleBean">
           <property name="email"><value></value></property>
          </bean>

          這等同于Java代碼: exampleBean.setEmail("")。而null值則可以使用<null>元素可用來表示。例如:

          <bean class="ExampleBean">
           <property name="email"><null/></property>
          </bean>

          上述的配置等同于Java代碼:exampleBean.setEmail(null)

          3.3.4使用depends-on

          多數(shù)情況下,一個bean對另一個bean的依賴最簡單的做法就是將一個bean設(shè)置為另外一個bean的屬性。在xml配置文件中最常見的就是使用<ref/>元素。有時候它還有另外一種變體,如果一個bean能感知IoC容器,只要給出它所依賴的id,那么就可以通過編程的方式從容器中取得它所依賴的對象。無論采用哪一種方法,被依賴bean將在依賴bean之前被適當?shù)某跏蓟?/p>

          在少數(shù)情況下,有時候bean之間的依賴關(guān)系并不是那么的直接(例如,當類中的靜態(tài)塊的初始化被時,如數(shù)據(jù)庫驅(qū)動的注冊)。depends-on屬性可以用于當前bean初始化之前顯式地強制一個或多個bean被初始化。下面的例子中使用了depends-on屬性來指定一個bean的依賴。

          <bean id="beanOne" class="ExampleBean" depends-on="manager"/>
           
          <bean id="manager" class="ManagerBean" />

          若需要表達對多個bean的依賴,可以在'depends-on'中將指定的多個bean名字用分隔符進行分隔,分隔符可以是逗號、空格及分號等。下面的例子中使用了'depends-on'來表達對多個bean的依賴。

          <bean id="beanOne" class="ExampleBean" depends-on="manager,accountDao">
           <property name="manager" ref="manager" />
          </bean>
           <bean id="manager" class="ManagerBean" />
          <bean id="accountDao" class="x.y.jdbc.JdbcAccountDao" />

           

          3.3.5延遲初始化bean

          ApplicationContext實現(xiàn)的默認行為就是在啟動時將所有singleton bean提前進行實例化。提前實例化意味著作為初始化過程的一部分,ApplicationContext實例會創(chuàng)建并配置所有的singleton bean。通常情況下這是件好事,因為這樣在配置中的任何錯誤就會即刻被發(fā)現(xiàn)(否則的話可能要花幾個小時甚至幾天)。

          有時候這種默認處理可能并不是你想要的。如果你不想讓一個singleton beanApplicationContext實現(xiàn)在初始化時被提前實例化,那么可以將bean設(shè)置為延遲實例化。一個延遲初始化bean將告訴IoC 容器是在啟動時還是在第一次被用到時實例化。

          XML配置文件中,延遲初始化將通過<bean/>元素中的lazy-init屬性來進行控制。例如:

          <bean id="lazy" class="com.foo.ExpensiveToCreateBean" lazy-init="true">
              <!-- various properties here... -->
          </bean>
           <bean name="not.lazy" class="com.foo.AnotherBean">
              <!-- various properties here... -->
          </bean>

          ApplicationContext實現(xiàn)加載上述配置時,設(shè)置為lazybean不會ApplicationContext啟動時提前被實例化,而not.lazy卻會被提前實例化。

          3.3.6自動裝配(autowire)協(xié)作者

          模式

          說明

          no

          不使用自動裝配。必須通過ref元素指定依賴,這是默認設(shè)置。由于顯式指定協(xié)作者可以使配置更靈活、更清晰,因此對于較大的部署配置,推薦采用該設(shè)置。而且在某種程度上,它也是系統(tǒng)架構(gòu)的一種文檔形式。

          byName

          根據(jù)屬性名自動裝配。此選項將檢查容器并根據(jù)名字查找與屬性完全一致的bean,并將其與屬性自動裝配。例如,在bean定義中將autowire設(shè)置為by name,而該bean包含master屬性(同時提供setMaster(..)方法),Spring就會查找名為masterbean定義,并用它來裝配給master屬性。

          byType

          如果容器中存在一個與指定屬性類型相同的bean,那么將與該屬性自動裝配。如果存在多個該類型的bean,那么將會拋出異常,并指出不能使用byType方式進行自動裝配。若沒有找到相匹配的bean,則什么事都不發(fā)生,屬性也不會被設(shè)置。如果你不希望這樣,那么可以通過設(shè)置dependency-check="objects"Spring拋出異常。

          constructor

          byType的方式類似,不同之處在于它應(yīng)用于構(gòu)造器參數(shù)。如果在容器中沒有找到與構(gòu)造器參數(shù)類型一致的bean,那么將會拋出異常。

          autodetect

          通過bean類的自省機制(introspection)來決定是使用constructor還是byType方式進行自動裝配。如果發(fā)現(xiàn)默認的構(gòu)造器,那么將使用byType方式。

          3.3.7依賴檢查

          當需要確保bean的所有屬性值(或者屬性類型)被正確設(shè)置的時候,那么這個功能會非常有用。當然,在很多情況下,bean類的某些屬性會具有默認值,或者有些屬性并不會在所有場景下使用,因此這項功能會存在一定的局限性。就像自動裝配一樣,依賴檢查也可以針對每一個bean進行設(shè)置。依賴檢查默認為not

          模式

          說明

          none

          沒有依賴檢查,如果bean的屬性沒有值的話可以不用設(shè)置。

          simple

          對于原始類型及集合(除協(xié)作者外的一切東西)執(zhí)行依賴檢查

          object

          僅對協(xié)作者執(zhí)行依賴檢查

          all

          對協(xié)作者,原始類型及集合執(zhí)行依賴檢查

          3.3.8方法注入

          在大部分情況下,容器中的bean都是singleton類型的。如果一個singleton bean要引用另外一個singleton bean,或者一個非singleton bean要引用另外一個非singleton bean時,通常情況下將一個bean定義為另一個beanproperty值就可以了。不過對于具有不同生命周期的bean來說這樣做就會有問題了,比如在調(diào)用一個singleton類型bean A的某個方法時,需要引用另一個非singletonprototype)類型的bean B,對于bean A來說,容器只會創(chuàng)建一次,這樣就沒法在需要的時候每次讓容器為bean A提供一個新的的bean B實例。

          3.3.8.1. Lookup方法注入

          這究竟是不是方法注入……

          Lookup方法注入利用了容器的覆蓋受容器管理的bean方法的能力,從而返回指定名字的bean實例。在上述場景中,Lookup方法注入適用于原型bean(盡管它也適用于singleton bean,但在那種情況下直接注入一個實例就夠了)Lookup方法注入的內(nèi)部機制是Spring利用了CGLIB庫在運行時生成二進制代碼功能,通過動態(tài)創(chuàng)建Lookup方法bean的子類而達到復寫Lookup方法的目的。

          package fiona.apple;

           
          // no more Spring imports! 
           
          public class CommandManager {
           
             public Object process(Object command) {
                // grab a new instance of the appropriate Command interface
                Command command = createCommand();
                // set the state on the (hopefully brand new) Command instance
                command.setState(commandState);
                return command.execute();
             }
           
              // mmm, but where is the implementation of this method?
             protected abstract CommandHelper createHelper();
           
          }

          在包含被注入方法的客戶類中(此處是CommandManager),此方法的定義必須按以下形式進行:

          <public|protected> [abstract] <return-type> theMethodName(no-arguments);

          如果方法是抽象的,動態(tài)生成的子類會實現(xiàn)該方法。否則,動態(tài)生成的子類會覆蓋類里的具體方法。讓我們來看個例子:

          <!-- a stateful bean deployed as a prototype (non-singleton) -->
          <bean id="command" class="fiona.apple.AsyncCommand" scope="prototype">
           <!-- inject dependencies here as required -->
          </bean>
           
          <!-- commandProcessor uses statefulCommandHelper -->
          <bean id="commandManager" class="fiona.apple.CommandManager">
           <lookup-method name="createCommand" bean="command"/>
          </bean>

          在上面的例子中,標識為commandManagerbean在需要一個新的command bean實例時,會調(diào)用createCommand方法。重要的一點是,必須將command部署為原型。當然也可以指定為singleton,如果是這樣的話,那么每次將返回相同的command bean實例!

          Lookup方法注入既可以結(jié)合構(gòu)造器注入,也可以與setter注入相結(jié)合。

          請注意,為了讓這個動態(tài)子類得以正常工作,需要把CGLIBjar文件放在classpath里。 另外,Spring容器要子類化的類不能是final的,要覆蓋的方法也不能是final的。同樣的,要測試一個包含抽象方法的類也稍微有些不同,你需要自己編寫它的子類提供該抽象方法的樁實現(xiàn)。 最后,作為方法注入目標的bean不能是序列化的(serialized)

           

          posted on 2007-04-06 12:15 海邊的腳印 閱讀(222) 評論(0)  編輯  收藏

          只有注冊用戶登錄后才能發(fā)表評論。


          網(wǎng)站導航:
           
          主站蜘蛛池模板: 大宁县| 贵南县| 丰城市| 府谷县| 当雄县| 大新县| 紫云| 南靖县| 册亨县| 青海省| 五家渠市| 长葛市| 罗江县| 德格县| 毕节市| 南投县| 板桥市| 庄浪县| 华亭县| 临汾市| 卓尼县| 万源市| 汝州市| 克什克腾旗| 根河市| 台中市| 长宁县| 靖宇县| 黄大仙区| 清涧县| 海门市| 宾川县| 荣成市| 新竹县| 井冈山市| 泸州市| 布尔津县| 土默特左旗| 昌宁县| 南部县| 巍山|