Spring知識一(bean配置)
IOC與DI概念
IOC(Inversion of Control):其思想是反轉資源獲取的方向. 傳統的資源查詢方式要求元件向容器發起請求查
找資源. 作為迴應, 容器適時的返回資源. 而應用了 IOC 之後, 則是容器主動地將資源推送給它所管理的元件, 元件所要做的僅是選擇一種合適的方式來接受資源. 這種行為也被稱為查詢的被動形式。
DI(Dependency Injection) — IOC 的另一種表述方式:即元件以一些預先定義好的方式(例如: setter 方法)接受來自如容器的資源注入. 相對於 IOC 而言,這種表述更直接。
bean配置,ApplicationContext.xml中配置
<!-- 配置一個 bean
id為在程式碼中引用的名稱,唯一,且可以為多個,利用逗號、分號、或空格分隔
class執向全類名,spring就是根據全類名,通過反射生成一個例項物件,id為這個例項物件的引用,所以我們必須在這個類中新增預設的構造方法,並且屬性要有setter方法
-->
<bean id="user" class="com.wf.springbean.User">
<property name="name" value="tom"></property>
<property name="sex" value="boy"></property>
</bean>
載入配置檔案,獲取bean
在 Spring IOC 容器讀取 Bean 配置建立 Bean 例項之前, 必須對它進行例項化. 只有在容器例項化後, 才可以從 IOC 容器裡獲取 Bean 例項並使用。
Spring 兩種型別的 IOC 容器實現—重點
1.BeanFactory: IOC 容器的基本實現.
2.ApplicationContext: 提供了更多的高階特性. 是 BeanFactory 的子介面,可以根據不同的實現類,去載入配置檔案。
注意:BeanFactory 是 Spring 框架的基礎設施,面向 Spring 本身;ApplicationContext 面向使用 Spring 框架的開發者,幾乎所有的應用場合都直接使用 ApplicationContext 而非底層的 BeanFactory。
ApplicationContext 的主要實現類:
ClassPathXmlApplicationContext:從 類路徑下載入配置檔案
FileSystemXmlApplicationContext: 從檔案系統中載入配置檔案
ConfigurableApplicationContext :擴充套件於 ApplicationContext,新增加兩個主要方法:refresh() 和 close(), 讓 ApplicationContext 具有啟動、重新整理和關閉上下文的能力
ApplicationContext 在初始化上下文時就例項化所有單例的 Bean。【載入配置檔案時】
WebApplicationContext 是專門為 WEB 應用而準備的,它允許從相對於 WEB 根目錄的路徑中完成初始化工作
//1. 建立 Spring 的 IOC 容器
//2. ClassPathXmlApplicationContext為一個介面,ClassPathXmlApplicationContext是其中的一個實現類
//3. ClassPathXmlApplicationContext 是根據classpath路徑進行載入
ClassPathXmlApplicationContext cxt = new ClassPathXmlApplicationContext("ApplicationContext.xml");
// 1. 利用getBean方法獲取容器中bean例項
User user = (User) cxt.getBean("user");
/*
根據型別來獲取 bean 的例項: 要求在 IOC 容器中只有一個與之型別匹配的 bean, 若有多個則會丟擲異常. 建議使用id進行匹配
一般情況下, 該方法可用, 因為一般情況下, 在一個 IOC 容器中一個型別對應的 bean 也只有一個.
HelloWorld helloWorld1 = ctx.getBean(HelloWorld.class);
*/
// 1. 呼叫方法
System.out.println(user.say());
System.out.println(user);
依賴注入的方式—重點
屬性注入(最常用,記住)
構造器注入(一般用,瞭解)
工廠方法注入(很少使用,不推薦,可以忘記)
屬性注入:
屬性注入即通過 setter 方法注入Bean 的屬性值或依賴的物件,使用 元素, 使用 name 屬性指定 Bean 類的屬性名稱,value 屬性或 子節點指定屬性值。【在這裡,注入是根據setter方法來的而不是屬性名稱,但是一般我們都是直接生成setter方法,而不去更改這個名稱,所以就是說成name為屬性名稱】
<bean id="user" class="com.wf.springbean.User">
<property name="name" value="tom"></property>
<property name="sex" value="boy"></property>
</bean>
構造方法注入:
通過構造方法注入Bean 的屬性值或依賴的物件,它保證了 Bean 例項在例項化後就可以使用。
構造器注入在 【constructor-arg】 元素裡宣告屬性,
<bean id="user01" class="com.wf.springbean.User">
<!-- 要求: 在 Bean 中必須有對應的構造器. -->
<constructor-arg value="Mike" name="name"></constructor-arg>
<constructor-arg value="girl" name="sex"></constructor-arg>
</bean>
<!-- 若一個 bean 有多個構造器, 如何通過構造器來為 bean 的屬性賦值 -->
<!-- 可以根據 index(引數位置) 和 value 進行更加精確的定位. (瞭解) -->
<bean id="car" class="com.wf.springbean.Car">
<constructor-arg value="KUGA" index="1"></constructor-arg>
<constructor-arg value="ChangAnFord" index="0"></constructor-arg>
<constructor-arg value="250000" type="float"></constructor-arg>
</bean>
<bean id="car2" class="com.wf.springbean.Car">
<constructor-arg value="ChangAnMazda"></constructor-arg>
<!-- 若字面值中包含特殊字元, 則可以使用 DCDATA 來進行賦值. (瞭解) -->
<constructor-arg>
<value><![CDATA[<ATARZA>]]></value>
</constructor-arg>
<constructor-arg value="180" type="int"></constructor-arg>
</bean>
引用其它 Bean—重點
組成應用程式的 Bean 經常需要相互協作以完成應用程式的功能. 要使 Bean 能夠相互訪問, 就必須在 Bean配置檔案中指定對 Bean 的引用。
在 Bean 的配置檔案中, 可以通過 【ref】 元素或 【ref】 屬性為 Bean 的屬性或構造器引數指定對 Bean 的引用。
也可以在屬性或構造器裡包含 Bean 的宣告, 這樣的 Bean 稱為內部 Bean。當 Bean 例項僅僅給一個特定的屬性使用時, 才將其宣告為內部 Bean. 內部 Bean 宣告直接包含在 【property】 或【constructor-arg】 元素裡, 不需要設定任何 id 或 name 屬性,內部 Bean 不能使用在任何其他地方。
<!-- 引用其他bean -->
<bean id="company" class="com.wf.springbean.Person">
<property name="name" value="longchuang"></property>
<property name="car" ref="car"></property>
<!-- <property name="car">
<ref bean="car"/>
</property>
-->
</bean>
<!-- 使用內部bean,不能被外部訪問-->
<bean id="company01" class="com.wf.springbean.Person">
<property name="name" value="dazhong"></property>
<property name="car">
<bean class="com.wf.springbean.Car">
<constructor-arg value="KUGA001" ></constructor-arg>
<constructor-arg value="ChangAnFord001" ></constructor-arg>
<constructor-arg value="250000" type="float"></constructor-arg>
</bean>
</property>
</bean>
注入引數詳解:null 值和級聯屬性—瞭解
可以使用專用的 【null】 元素標籤為 Bean 的字串或其它物件型別的屬性注入 null 值
和 Struts、Hiberante 等框架一樣,Spring 支援級聯屬性的配置。不建議使用級聯屬性這樣賦值,這樣的賦值,會覆蓋掉前面的bean中的此屬性的值
<!-- null測試及級聯屬性 利用構造注入時,必須保證建構函式-->
<bean id="person02" class="com.wf.springbean.Person">
<constructor-arg name="name" value="jack"></constructor-arg>
<!-- <constructor-arg name="car" ><null/></constructor-arg> -->
<constructor-arg name="car" ref="car"></constructor-arg>
<property name="car.maxSpeed" value="251"></property>
<!-- 這種方式的賦值會將ref關聯的car的maxSpeed屬性進行更改。這樣的話,只要有涉及到car的都會更改-->
</bean>
集合屬性的配置—重點
在 Spring中可以通過一組內建的 xml 標籤(例如: 【list】, 【set】 或 【map】) 來配置集合屬性.
配置 java.util.List 型別的屬性, 需要指定 【list】 標籤, 在標籤裡包含一些元素. 這些標籤可以通過 【value】 指定簡單的常量值, 通過 【ref】 指定對其他 Bean 的引用. 通過【bean】 指定內建 Bean 定義. 通過 【null/】 指定空元素. 甚至可以內嵌其他集合.
陣列的定義和 List 一樣, 都使用 【list】
配置 java.util.Set 需要使用 【set】 標籤, 定義元素的方法與 List 一樣.
Java.util.Map 通過 【map】 標籤定義, 【map】 標籤裡可以使用多個 【entry】 作為子標籤. 每個條目包含一個鍵和一個值.
必須在 【key】 標籤裡定義鍵
因為鍵和值的型別沒有限制, 所以可以自由地為它們指定 【value】, 【ref】, 【bean】 或 【null】 元素.
可以將 Map 的鍵和值作為 【entry】 的屬性定義: 簡單常量使用 key 和 value 來定義; Bean 引用通過 key-ref 和 value-ref 屬性定義
使用 【props】 定義 java.util.Properties, 該標籤使用多個 【prop】 作為子標籤. 每個 【prop】 標籤必須定義 key 屬性,在整合hibernate時,會利用這個屬性
<!-- list 集合配置 -->
<bean id="person" class="com.wf.springcollection.Person">
<property name="name" value="rose"></property>
<property name="cars">
<list>
<ref bean="car1"/>
<ref bean="car2"/>
<ref bean="car3"/>
<bean class="com.wf.springcollection.Car">
<property name="company" value="tutu04"></property>
<property name="brand" value="HaFu04"></property>
<property name="maxSpeed" value="254"></property>
<property name="price" value="25400"></property>
</bean>
</list>
</property>
</bean>
<!-- map集合配置 -->
<bean id="personmap" class="com.wf.springcollection.Person">
<property name="name" value="jack"></property>
<property name="mapscars">
<map>
<entry key="AA" value-ref="car1"></entry>
<entry key="BB" value-ref="car2"></entry>
<entry key="CC" value-ref="car3"></entry>
</map>
</property>
</bean>
<!-- prop配置,在整合hibernate使用 -->
<bean id="datasource" class="com.wf.springcollection.DataSource">
<property name="properties">
<props>
<prop key="user">root</prop>
<prop key="psaaword">1234</prop>
<prop key="jbbcUrl">jdbc:mysql:///test</prop>
<prop key="driverClass">com.mysql.jdbc.Driver</prop>
</props>
</property>
</bean>
<!-- 將集合屬性進行單獨配置,這樣的話可以供多個bean使用,需要引入名稱空間util -->
<util:list id="carslist">
<ref bean="car1"/>
<ref bean="car2"/>
</util:list>
<bean id="personlist" class="com.wf.springcollection.Person">
<property name="name" value="jack"></property>
<property name="cars" ref="carslist"></property>
</bean>
<!--p:名稱空間的使用,可以簡化屬性配置 -->
<bean id="personp" class="com.wf.springcollection.Person"
p:name="Queen" p:cars-ref="carslist">
</bean>
自動裝配配置—瞭解
Spring IOC 容器可以自動裝配 Bean. 需要做的僅僅是在 【bean】 的 autowire 屬性裡指定自動裝配的模式。
1、byName(根據名稱自動裝配): 必須將目標 Bean 的名稱和屬性名設定的完全相同。
2、byType(根據型別自動裝配): 若 IOC 容器中有多個與目標 Bean 型別一致的 Bean. 在這種情況下, Spring 將無法判定哪個 Bean 最合適該屬性, 所以不能執行自動裝配。報錯。利用註解時,會用到bytype。
3、constructor(通過構造器自動裝配): 當 Bean 中存在多個構造器時, 此種自動裝配方式將會很複雜. 不推薦使用。
自動裝配的缺點:
在 Bean 配置檔案裡設定 autowire 屬性進行自動裝配將會裝配 Bean 的所有屬性. 然而, 若只希望裝配個別屬性時, autowire 屬性就不夠靈活了.
autowire 屬性要麼根據型別自動裝配, 要麼根據名稱自動裝配, 不能兩者兼而有之.
一般情況下,在實際的專案中很少使用自動裝配功能,因為和自動裝配功能所帶來的好處比起來,明確清晰的配置文件更有說服力一些
<!--正常配置 -->
<bean id="user" class="com.wf.springauto.User">
<property name="name" value="zhangsan"></property>
<property name="car" ref="car"></property>
<property name="address" ref="address"></property>
</bean>
<!-- 根據Name進行匹配。根據bean類的名字和當前setter風格的屬性名稱進行自動匹配 ,都是用在bean與bean之間的關聯中-->
<bean id="userautoname" class="com.wf.springauto.User" autowire="byName">
<property name="name" value="zhangsan"></property>
<!-- <property name="car" ref="car"></property>
<property name="address" ref="address"></property> -->
</bean>
<!-- 根據type進行匹配。根據bean類的型別和bean的屬性型別進行自動裝配,都是用在bean與bean之間的關聯中-->
<bean id="userautotype" class="com.wf.springauto.User" autowire="byType">
<property name="name" value="zhangsan"></property>
<!-- <property name="car" ref="car"></property>
<property name="address" ref="address"></property> -->
</bean>
現在的專案一般都是利用註解進行配置,因為註解的方式可以大大縮減程式碼量。但是在一些全域性的屬性配置中,利用xml的配置還是比較方便。