# 【第二章】 IoC 之 2.3 IoC的配置使用——跟我學Spring3
### 2.3.1? XML配置的結構
一般配置文件結構如下:
1. <beans>??
2. <import?resource=”resource1.xml”/>??
3. <bean?id=”bean1”class=””></bean>??
4. <bean?id=”bean2”class=””></bean>??
5. <bean?name=”bean2”class=””></bean>??
6. <alias?alias="bean3"?name="bean2"/>??
7. <import?resource=”resource2.xml”/>??
8. </beans>??
1、<bean>標簽主要用來進行Bean定義;
2、alias用于定義Bean別名的;
3、import用于導入其他配置文件的Bean定義,這是為了加載多個配置文件,當然也可以把這些配置文件構造為一個數組(new String[] {“config1.xml”, config2.xml})傳給ApplicationContext實現進行加載多個配置文件,那一個更適合由用戶決定;這兩種方式都是通過調用Bean Definition Reader 讀取Bean定義,內部實現沒有任何區別。<import>標簽可以放在<beans>下的任何位置,沒有順序關系。
### 2.3.2? Bean的配置
Spring IoC容器目的就是管理Bean,這些Bean將根據配置文件中的Bean定義進行創建,而Bean定義在容器內部由BeanDefinition對象表示,該定義主要包含以下信息:
●全限定類名(FQN):用于定義Bean的實現類;
●Bean行為定義:這些定義了Bean在容器中的行為;包括作用域(單例、原型創建)、是否惰性初始化及生命周期等;
●Bean創建方式定義:說明是通過構造器還是工廠方法創建Bean;
●Bean之間關系定義:即對其他bean的引用,也就是依賴關系定義,這些引用bean也可以稱之為同事bean 或依賴bean,也就是依賴注入。
Bean定義只有“全限定類名”在當使用構造器或靜態工廠方法進行實例化bean時是必須的,其他都是可選的定義。難道Spring只能通過配置方式來創建Bean嗎?回答當然不是,某些SingletonBeanRegistry接口實現類實現也允許將那些非BeanFactory創建的、已有的用戶對象注冊到容器中,這些對象必須是共享的,比如使用DefaultListableBeanFactory 的registerSingleton() 方法。不過建議采用元數據定義。
### 2.3.3?? ?Bean的命名
每個Bean可以有一個或多個id(或稱之為標識符或名字),在這里我們把**第一個id稱為“標識符”,其余id叫做“別名”**;這些id在IoC容器中必須唯一。如何為Bean指定id呢,有以下幾種方式;
一、? 不指定id,只配置必須的全限定類名,由IoC容器為其生成一個標識,客戶端必須通過接口“T getBean(Class<T> requiredType)”獲取Bean;
1. <bean?class=”?cn.javass.spring.chapter2.helloworld.HelloImpl”/>??????????????(1)??
測試代碼片段如下:
1. @Test??
2. public?void?test1()?{??
3. BeanFactory?beanFactory?=??
4. new?ClassPathXmlApplicationContext("chapter2/namingbean1.xml");??
5. //根據類型獲取bean??
6. HelloApi?helloApi?=?beanFactory.getBean(HelloApi.class);??
7. helloApi.sayHello();??
8. }??
二、指定id,必須在Ioc容器中唯一;
1. <bean?id=”?bean”?class=”?cn.javass.spring.chapter2.helloworld.HelloImpl”/>????(2)??
測試代碼片段如下:
1. @Test??
2. public?void?test2()?{??
3. BeanFactory?beanFactory?=??
4. new?ClassPathXmlApplicationContext("chapter2/namingbean2.xml");??
5. //根據id獲取bean??
6. HelloApi?bean?=?beanFactory.getBean("bean",?HelloApi.class);??
7. bean.sayHello();??
8. }??
三、指定name,這樣name就是“標識符”,必須在Ioc容器中唯一;
1. <bean?name=”?bean”?class=”?cn.javass.spring.chapter2.helloworld.HelloImpl”/>?(3)??
測試代碼片段如下:
1. @Test??
2. public?void?test3()?{??
3. BeanFactory?beanFactory?=??
4. new?ClassPathXmlApplicationContext("chapter2/namingbean3.xml");??
5. //根據name獲取bean??
6. HelloApi?bean?=?beanFactory.getBean("bean",?HelloApi.class);??
7. bean.sayHello();??
8. }??
四、指定id和name,id就是標識符,而name就是別名,必須在Ioc容器中唯一;
1. <bean?id=”bean1”name=”alias1”??
2. class=”?cn.javass.spring.chapter2.helloworld.HelloImpl”/>??
3. <!--?如果id和name一樣,IoC容器能檢測到,并消除沖突?-->??
4. <bean?id="bean3"?name="bean3"?class="cn.javass.spring.chapter2.helloworld.HelloImpl"/>??????????????(4)??
測試代碼片段如下:
1. @Test??
2. public?void?test4()?{??
3. BeanFactory?beanFactory?=??
4. new?ClassPathXmlApplicationContext("chapter2/namingbean4.xml");??
5. //根據id獲取bean??
6. HelloApi?bean1?=?beanFactory.getBean("bean1",?HelloApi.class);??
7. bean1.sayHello();??
8. //根據別名獲取bean??
9. HelloApi?bean2?=?beanFactory.getBean("alias1",?HelloApi.class);??
10. bean2.sayHello();??
11. //根據id獲取bean??
12. HelloApi?bean3?=?beanFactory.getBean("bean3",?HelloApi.class);??
13. bean3.sayHello();??
14. String[]?bean3Alias?=?beanFactory.getAliases("bean3");??
15. //因此別名不能和id一樣,如果一樣則由IoC容器負責消除沖突??
16. Assert.assertEquals(0,?bean3Alias.length);??
17. }??
五、指定多個name,多個name用“,”、“;”、“ ”分割,第一個被用作標識符,其他的(alias1、alias2、alias3)是別名,所有標識符也必須在Ioc容器中唯一;
1. <bean?name=”?bean1;alias11,alias12;alias13?alias14”??
2. class=”?cn.javass.spring.chapter2.helloworld.HelloImpl”/>?????
3. <!--?當指定id時,name指定的標識符全部為別名?-->??
4. <bean?id="bean2"?name="alias21;alias22"??
5. class="cn.javass.spring.chapter2.helloworld.HelloImpl"/>??????????????(5)??
測試代碼片段如下:
1. @Test??
2. public?void?test5()?{??
3. BeanFactory?beanFactory?=??
4. new?ClassPathXmlApplicationContext("chapter2/namingbean5.xml");??
5. //1根據id獲取bean??
6. HelloApi?bean1?=?beanFactory.getBean("bean1",?HelloApi.class);??
7. bean1.sayHello();??
8. //2根據別名獲取bean??
9. HelloApi?alias11?=?beanFactory.getBean("alias11",?HelloApi.class);??
10. alias11.sayHello();??
11. //3驗證確實是四個別名?????????
12. String[]?bean1Alias?=?beanFactory.getAliases("bean1");??
13. System.out.println("=======namingbean5.xml?bean1?別名========");??
14. for(String?alias?:?bean1Alias)?{??
15. System.out.println(alias);??
16. }??
17. Assert.assertEquals(4,?bean1Alias.length);??
18. //根據id獲取bean??
19. HelloApi?bean2?=?beanFactory.getBean("bean2",?HelloApi.class);??
20. bean2.sayHello();??
21. //2根據別名獲取bean??
22. HelloApi?alias21?=?beanFactory.getBean("alias21",?HelloApi.class);??
23. alias21.sayHello();??
24. //驗證確實是兩個別名??
25. String[]?bean2Alias?=?beanFactory.getAliases("bean2");??
26. System.out.println("=======namingbean5.xml?bean2?別名========");??
27. for(String?alias?:?bean2Alias)?{??
28. System.out.println(alias);??
29. }?????
30. Assert.assertEquals(2,?bean2Alias.length);?????
31. }??
六、使用<alias>標簽指定別名,別名也必須在IoC容器中唯一
1. <bean?name="bean"?class="cn.javass.spring.chapter2.helloworld.HelloImpl"/>??
2. <alias?alias="alias1"?name="bean"/>??
3. <alias?alias="alias2"?name="bean"/>??????????????????????????????????(6)??
測試代碼片段如下:
1. @Test??
2. public?void?test6()?{??
3. BeanFactory?beanFactory?=??
4. new?ClassPathXmlApplicationContext("chapter2/namingbean6.xml");??
5. //根據id獲取bean??
6. HelloApi?bean?=?beanFactory.getBean("bean",?HelloApi.class);??
7. bean.sayHello();??
8. //根據別名獲取bean??
9. HelloApi?alias1?=?beanFactory.getBean("alias1",?HelloApi.class);??
10. alias1.sayHello();??
11. HelloApi?alias2?=?beanFactory.getBean("alias2",?HelloApi.class);??
12. alias2.sayHello();??
13. String[]?beanAlias?=?beanFactory.getAliases("bean");??
14. System.out.println("=======namingbean6.xml?bean?別名========");??
15. for(String?alias?:?beanAlias)?{??
16. System.out.println(alias);??
17. }??
18. System.out.println("=======namingbean6.xml?bean?別名========");??
19. Assert.assertEquals(2,?beanAlias.length);??
20. }??
以上測試代碼在cn.javass.spring.chapter2.NamingBeanTest.java文件中。
從定義來看,name或id如果指定它們中的一個時都作為“標識符”,那為什么還要有id和name同時存在呢?這是因為當使用基于XML的配置元數據時,在XML中id是一個真正的XML id屬性,因此當其他的定義來引用這個id時就體現出id的好處了,可以利用XML解析器來驗證引用的這個id是否存在,從而更早的發現是否引用了一個不存在的bean,而使用name,則可能要在真正使用bean時才能發現引用一個不存在的bean。
●**Bean命名約定:**Bean的命名遵循XML命名規范,但最好符合Java命名規范,由“字母、數字、下劃線組成“,而且應該養成一個良好的命名習慣, 比如采用“駝峰式”,即第一個單詞首字母開始,從第二個單詞開始首字母大寫開始,這樣可以增加可讀性。
### 2.3.4? 實例化Bean
Spring IoC容器如何實例化Bean呢?傳統應用程序可以通過new和反射方式進行實例化Bean。而Spring IoC容器則需要根據Bean定義里的配置元數據使用反射機制來創建Bean。在Spring IoC容器中根據Bean定義創建Bean主要有以下幾種方式:
一、使用構造器實例化Bean:這是最簡單的方式,Spring IoC容器即能使用默認空構造器也能使用有參數構造器兩種方式創建Bean,如以下方式指定要創建的Bean類型:
使用空構造器進行定義,使用此種方式,class屬性指定的類必須有空構造器
1. <bean?name="bean1"?class="cn.javass.spring.chapter2.HelloImpl2"/>??
使用有參數構造器進行定義,使用此中方式,可以使用< constructor-arg >標簽指定構造器參數值,其中index表示位置,value表示常量值,也可以指定引用,指定引用使用ref來引用另一個Bean定義,后邊會詳細介紹:
1. <bean?name="bean2"?class="cn.javass.spring.chapter2.HelloImpl2">??
2. <!--?指定構造器參數?-->??
3. <constructor-arg?index="0"?value="Hello?Spring!"/>??
4. </bean>??
知道如何配置了,讓我們做個例子的例子來實踐一下吧:
(1)準備Bean class(HelloImpl2.java),該類有一個空構造器和一個有參構造器:
1. package?cn.javass.spring.chapter2;???
2. public?class?HelloImpl2?implements?HelloApi?{??
3. private?String?message;??
4. public?HelloImpl2()?{??
5. this.message?=?"Hello?World!";??
6. }??
7. Public?HelloImpl2(String?message)?{??
8. this.message?=?message;??
9. }??
10. @Override??
11. public?void?sayHello()?{??
12. System.out.println(message);??
13. }??
14. }??
(2)在配置文件(resources/chapter2/instantiatingBean.xml)配置Bean定義,如下所示:
1. <!--使用默認構造參數-->??
2. <bean?name="bean1"?class="cn.javass.spring.chapter2.HelloImpl2"/>??
3. <!--使用有參數構造參數-->??
5. <bean?name="bean2"?class="cn.javass.spring.chapter2.HelloImpl2">??
6. <!--?指定構造器參數?-->??
7. <constructor-arg?index="0"?value="Hello?Spring!"/>??
8. </bean>??
(3)配置完了,讓我們寫段測試代碼(InstantiatingContainerTest)來看下是否工作吧:
1. @Test??
2. public?void?testInstantiatingBeanByConstructor()?{??
3. //使用構造器??
4. BeanFactory?beanFactory?=??
5. new?ClassPathXmlApplicationContext("chapter2/instantiatingBean.xml");??
6. HelloApi?bean1?=?beanFactory.getBean("bean1",?HelloApi.class);??
7. bean1.sayHello();??
8. HelloApi?bean2?=?beanFactory.getBean("bean2",?HelloApi.class);??
9. bean2.sayHello();??
10. }??
二、使用靜態工廠方式實例化Bean,使用這種方式除了指定必須的class屬性,還要指定factory-method屬性來指定實例化Bean的方法,而且使用靜態工廠方法也允許指定方法參數,spring IoC容器將調用此屬性指定的方法來獲取Bean,配置如下所示:
(1)先來看看靜態工廠類代碼吧HelloApiStaticFactory:
1. public?class?HelloApiStaticFactory?{??
2. //工廠方法??
3. public?static?HelloApi?newInstance(String?message)?{??
4. //返回需要的Bean實例??
5. return?new?HelloImpl2(message);??
6. }??
7. }??
(2)靜態工廠寫完了,讓我們在配置文件(resources/chapter2/instantiatingBean.xml)配置Bean定義:
1. <!--?使用靜態工廠方法?-->??
2. <bean?id="bean3"?class="cn.javass.spring.chapter2.HelloApiStaticFactory"?factory-method="newInstance">??
3. <constructor-arg?index="0"?value="Hello?Spring!"/>??
4. </bean>??
(3)配置完了,寫段測試代碼來測試一下吧,InstantiatingBeanTest:
1. @Test??
2. public?void?testInstantiatingBeanByStaticFactory()?{??
3. //使用靜態工廠方法??
4. BeanFactory?beanFactory?=??
5. new?ClassPathXmlApplicationContext("chaper2/instantiatingBean.xml");??
6. HelloApi?bean3?=?beanFactory.getBean("bean3",?HelloApi.class);??
7. bean3.sayHello();??
8. }??
三、使用實例工廠方法實例化Bean,使用這種方式不能指定class屬性,此時必須使用factory-bean屬性來指定工廠Bean,factory-method屬性指定實例化Bean的方法,而且使用實例工廠方法允許指定方法參數,方式和使用構造器方式一樣,配置如下:
(1)實例工廠類代碼(HelloApiInstanceFactory.java)如下:
2. package?cn.javass.spring.chapter2;??
3. public?class?HelloApiInstanceFactory?{??
4. public?HelloApi?newInstance(String?message)?{??
5. return?new?HelloImpl2(message);??
6. }??
7. }??
(2)讓我們在配置文件(resources/chapter2/instantiatingBean.xml)配置Bean定義:
1. <!—1、定義實例工廠Bean?-->??
2. <bean?id="beanInstanceFactory"??
3. class="cn.javass.spring.chapter2.HelloApiInstanceFactory"/>??
4. <!—2、使用實例工廠Bean創建Bean?-->??
5. <bean?id="bean4"??
6. factory-bean="beanInstanceFactory"??
7. factory-method="newInstance">??
8. <constructor-arg?index="0"?value="Hello?Spring!"></constructor-arg>??
9. </bean>??
(3)測試代碼InstantiatingBeanTest:
1. @Test??
2. public?void?testInstantiatingBeanByInstanceFactory()?{??
3. //使用實例工廠方法??
4. BeanFactory?beanFactory?=??
5. new?ClassPathXmlApplicationContext("chapter2/instantiatingBean.xml");??
6. HelloApi?bean4?=?beanFactory.getBean("bean4",?HelloApi.class);??
7. bean4.sayHello();??
8. }??
通過以上例子我們已經基本掌握了如何實例化Bean了,大家是否注意到?這三種方式只是配置不一樣,從獲取方式看完全一樣,沒有任何不同。這也是Spring IoC的魅力,Spring IoC幫你創建Bean,我們只管使用就可以了,是不是很簡單。
### 2.3.5? 小結
到此我們已經講完了Spring IoC基礎部分,包括IoC容器概念,如何實例化容器,Bean配置、命名及實例化,Bean獲取等等。不知大家是否注意到到目前為止,我們只能通過簡單的實例化Bean,沒有涉及Bean之間關系。接下來一章讓我們進入配置Bean之間關系章節,也就是依賴注入。?
- 跟我學 Spring3
- 【第二章】 IoC 之 2.1 IoC基礎 ——跟我學Spring3
- 【第二章】 IoC 之 2.2 IoC 容器基本原理 ——跟我學Spring3
- 【第二章】 IoC 之 2.3 IoC的配置使用——跟我學Spring3
- 【第三章】 DI 之 3.1 DI的配置使用 ——跟我學spring3
- 【第三章】 DI 之 3.2 循環依賴 ——跟我學spring3
- 【第三章】 DI 之 3.3 更多DI的知識 ——跟我學spring3
- 【第三章】 DI 之 3.4 Bean的作用域 ——跟我學spring3
- 【第四章】 資源 之 4.1 基礎知識 ——跟我學spring3
- 【第四章】 資源 之 4.2 內置Resource實現 ——跟我學spring3
- 【第四章】 資源 之 4.3 訪問Resource ——跟我學spring3
- 【第四章】 資源 之 4.4 Resource通配符路徑 ——跟我學spring3
- 【第五章】Spring表達式語言 之 5.1 概述 5.2 SpEL基礎 ——跟我學spring3
- 【第五章】Spring表達式語言 之 5.3 SpEL語法 ——跟我學spring3
- 【第五章】Spring表達式語言 之 5.4在Bean定義中使用EL—跟我學spring3
- 【第六章】 AOP 之 6.1 AOP基礎 ——跟我學spring3
- 【第六章】 AOP 之 6.2 AOP的HelloWorld ——跟我學spring3
- 【第六章】 AOP 之 6.3 基于Schema的AOP ——跟我學spring3
- 【第六章】 AOP 之 6.4 基于@AspectJ的AOP ——跟我學spring3
- 【第六章】 AOP 之 6.5 AspectJ切入點語法詳解 ——跟我學spring3
- 【第六章】 AOP 之 6.6 通知參數 ——跟我學spring3
- 【第六章】 AOP 之 6.7 通知順序 ——跟我學spring3
- 【第六章】 AOP 之 6.8 切面實例化模型 ——跟我學spring3
- 【第六章】 AOP 之 6.9 代理機制 ——跟我學spring3
- 【第七章】 對JDBC的支持 之 7.1 概述 ——跟我學spring3
- 【第七章】 對JDBC的支持 之 7.2 JDBC模板類 ——跟我學spring3
- 【第七章】 對JDBC的支持 之 7.3 關系數據庫操作對象化 ——跟我學spring3
- 【第七章】 對JDBC的支持 之 7.4 Spring提供的其它幫助 ——跟我學spring3【私塾在線原創】
- 【第七章】 對JDBC的支持 之 7.5 集成Spring JDBC及最佳實踐 ——跟我學spring3
- 【第八章】 對ORM的支持 之 8.1 概述 ——跟我學spring3
- 【第八章】 對ORM的支持 之 8.2 集成Hibernate3 ——跟我學spring3
- 【第八章】 對ORM的支持 之 8.3 集成iBATIS ——跟我學spring3
- 【第八章】 對ORM的支持 之 8.4 集成JPA ——跟我學spring3
- 【第九章】 Spring的事務 之 9.1 數據庫事務概述 ——跟我學spring3
- 【第九章】 Spring的事務 之 9.2 事務管理器 ——跟我學spring3
- 【第九章】 Spring的事務 之 9.3 編程式事務 ——跟我學spring3
- 【第九章】 Spring的事務 之 9.4 聲明式事務 ——跟我學spring3
- 【第十章】集成其它Web框架 之 10.1 概述 ——跟我學spring3
- 【第十章】集成其它Web框架 之 10.2 集成Struts1.x ——跟我學spring3
- 【第十章】集成其它Web框架 之 10.3 集成Struts2.x ——跟我學spring3
- 【第十章】集成其它Web框架 之 10.4 集成JSF ——跟我學spring3
- 【第十一章】 SSH集成開發積分商城 之 11.1 概述 ——跟我學spring3
- 【第十一章】 SSH集成開發積分商城 之 11.2 實現通用層 ——跟我學spring3
- 【第十一章】 SSH集成開發積分商城 之 11.3 實現積分商城層 ——跟我學spring3
- 【第十二章】零配置 之 12.1 概述 ——跟我學spring3
- 【第十二章】零配置 之 12.2 注解實現Bean依賴注入 ——跟我學spring3
- 【第十二章】零配置 之 12.3 注解實現Bean定義 ——跟我學spring3
- 【第十二章】零配置 之 12.4 基于Java類定義Bean配置元數據 ——跟我學spring3
- 【第十二章】零配置 之 12.5 綜合示例-積分商城 ——跟我學spring3
- 【第十三章】 測試 之 13.1 概述 13.2 單元測試 ——跟我學spring3
- 【第十三章】 測試 之 13.3 集成測試 ——跟我學spring3
- 跟我學 Spring MVC
- SpringMVC + spring3.1.1 + hibernate4.1.0 集成及常見問題總結
- Spring Web MVC中的頁面緩存支持 ——跟我學SpringMVC系列
- Spring3 Web MVC下的數據類型轉換(第一篇)——《跟我學Spring3 Web MVC》搶先看
- Spring3 Web MVC下的數據格式化(第二篇)——《跟我學Spring3 Web MVC》搶先看
- 第一章 Web MVC簡介 —— 跟開濤學SpringMVC
- 第二章 Spring MVC入門 —— 跟開濤學SpringMVC
- 第三章 DispatcherServlet詳解 ——跟開濤學SpringMVC
- 第四章 Controller接口控制器詳解(1)——跟著開濤學SpringMVC
- 第四章 Controller接口控制器詳解(2)——跟著開濤學SpringMVC
- 第四章 Controller接口控制器詳解(3)——跟著開濤學SpringMVC
- 第四章 Controller接口控制器詳解 (4)——跟著開濤學SpringMVC
- 第四章 Controller接口控制器詳解(5)——跟著開濤學SpringMVC
- 跟著開濤學SpringMVC 第一章源代碼下載
- 第二章 Spring MVC入門 源代碼下載
- 第四章 Controller接口控制器詳解 源代碼下載
- 第四章 Controller接口控制器詳解(6)——跟著開濤學SpringMVC
- 第四章 Controller接口控制器詳解(7 完)——跟著開濤學SpringMVC
- 第五章 處理器攔截器詳解——跟著開濤學SpringMVC
- 源代碼下載 第五章 處理器攔截器詳解——跟著開濤學SpringMVC
- 注解式控制器運行流程及處理器定義 第六章 注解式控制器詳解——跟著開濤學SpringMVC
- 源代碼下載 第六章 注解式控制器詳解
- SpringMVC3強大的請求映射規則詳解 第六章 注解式控制器詳解——跟著開濤學SpringMVC
- Spring MVC 3.1新特性 生產者、消費者請求限定 —— 第六章 注解式控制器詳解——跟著開濤學SpringMVC
- SpringMVC強大的數據綁定(1)——第六章 注解式控制器詳解——跟著開濤學SpringMVC
- SpringMVC強大的數據綁定(2)——第六章 注解式控制器詳解——跟著開濤學SpringMVC
- SpringMVC數據類型轉換——第七章 注解式控制器的數據驗證、類型轉換及格式化——跟著開濤學SpringMVC
- SpringMVC數據格式化——第七章 注解式控制器的數據驗證、類型轉換及格式化——跟著開濤學SpringMVC
- SpringMVC數據驗證——第七章 注解式控制器的數據驗證、類型轉換及格式化——跟著開濤學SpringMVC