Spring中的Bean配置
IOC&DI概述
OPC(Inversion of Control):其思想是反轉資源獲取的方向。傳統的資源查找方式要求組件向容器發起請求查找資源。作為回應,容器適時的返回資源。而應用了IOC之後,則是容器主動地將資源推送給它所管理的組件,組件索要做的僅是選擇一種和氏的方式來接受資源。這種行為也被稱為查找的被動形式
DI(Dependency Injection)--IOC的另一種表述方式:即組件以一些預先定義好的方式(例如:setter方法)接受來自如容器的資源註入。相對於IOC而言,這種表述更直接
配置Bean
--配置形式:①基於XML文件的方式基②於註解的方式
--Bean的配置方式:通過全類名(反射)、通過工廠方法(靜態工廠方法&實例工廠方法)、FactoryBean
--IOC容器BeanFactory&ApplicationContext概述
依賴註入的方式:屬性註入;構造器註入
註入屬性值細節
class: javaBean的全類名,通過反射的方式在IOC容器中創建Bean,所以要求Bean中必須有無參數的構造器
id:標識容器中的Bean,id唯一.
<bean id="HelloSpring" class="cn.bdqn.spring.HelloSpring"> <property name="who" value="spring"></property> </bean> |
Spring 容器
在Spring IOC容器讀取Bean配置創建Bean實例之前,必須對它進行實例化,只有在容器實例後,才可以從IOC容器裏獲取Bean實例並使用
Spring 提供了兩種類型的IOC容器實現
① BeanFactory:IOC容器的基本實現
BeanFactory是Spring框架的基礎設施,面向Spring本身
② ApplicationContext: 提供了更多的高級特性,是BeanFactory的子接口.面向使用Spring框架的開發者,幾乎所有的應用場合都直接使用ApplicationContext而非底層的BeanFactory
無論使用何種方式,配置文件時相同
ApplicationContext的繼承架構:
ApplicationContext的主要實現類
ClassPathXmlApplicationContext:從類路徑下加載配置文件
FileSystemXmlApplicationContext:從文件系統中加載配置文件
ApplicationContext的實現接口:
ConfigurableApplicationContext:是ApplicationContext的實現接口,新增兩個主要方法:refresh()和close(),讓ApplicationContext具有啟動刷新和關閉上下文的能力
ApplicationContext在初始化上下文時就實例化所有單例的Bean.
/*ApplicationContext代表IOC容器 ClassPathXmlApplicationContext是ApplicationContext的實現類,該實現類從類路徑下來加載配置文件*/
ApplicationContext context = new ClassPathXmlApplicationContext("applicationContext.xml"); |
/* 從IOC容器中獲取Bean實例 "HelloSpring"是我們applicationContext.xml中配置的id屬性的值利用id定位到IOC中的Bean */ HelloSpring bean = (HelloSpring)context.getBean("HelloSpring"); |
依賴註入的方式:
①屬性註入
屬性註入即通過setter方法註入Bean的屬性值或依賴的對象,
屬性註入使用<property>元素,使用name屬性指定Bean的屬性名稱,value屬性或<value>子節點指定屬性值
屬性主圖是實際應用中最常見的註入方式
實例:
<!-- 配置bean class javaBean的全類名,通過反射的方式在IOC容器中創建Bean,所以要求Bean中必須有無參數的構造器 id:標識容器中的Bean,id唯一.
--> <bean id="HelloSpring" class="cn.bdqn.spring.HelloSpring"> <property name="who" value="spring"></property> </bean> |
②構造器註入
<constructor-arg> 代表我們構造器中的參數,一個標簽僅能為我們構造器中的一個參數賦值
實例:
我們編寫的javaBean代碼為:
public class Person { private String name; private String country; private int age; //工資 private double salary; public Person(String name, String country, double salary) { super(); this.name = name; this.country = country; this.salary = salary; } public Person(String name, String country, int age) { super(); this.name = name; this.country = country; this.age = age; } |
配置文件如下:
<bean id="p1" class="cn.bdqn.spring.Person"> <constructor-arg value="zhangsna" ></constructor-arg> <constructor-arg value="zhongguo" ></constructor-arg> <constructor-arg value="23 " ></constructor-arg> </bean> <bean id="p2" class="cn.bdqn.spring.Person"> <constructor-arg value="lisi"></constructor-arg> <constructor-arg value="meiguo"></constructor-arg> <constructor-arg value="4000"></constructor-arg> </bean> |
最後程序運行後出現以下結果:
|
這個結果顯然和我們預期的不一致
程序運行時會將我們的給定的參數與javaBean中的構造方法進行匹配,當匹配成功時選擇對應的構造器進行執行,我們在配置文件中將salary屬性的值設置為整數時,jvm就會將這個配置與我們構造器中的參數為int型的構造器進行匹配,如果不存在int型參數的構造器,才會正確執行
也就是說,我們程序中如果將以下構造器刪除,程序便會將int自動轉換為double進行匹配
public Person(String name, String country, int age) { super(); this.name = name; this.country = country; this.age = age; } |
如果我們想保留兩個構造器,並且讓程序正確執行的話,我們可以在配置文件中的constructor-arg標簽中添加type屬性.為value指定一個類型:
<bean id="p1" class="cn.bdqn.spring.Person"> <constructor-arg value="zhangsna" ></constructor-arg> <constructor-arg value="zhongguo" ></constructor-arg> <constructor-arg value="23 " type="int" ></constructor-arg> </bean> <bean id="p2" class="cn.bdqn.spring.Person"> <constructor-arg value="lisi"></constructor-arg> <constructor-arg value="meiguo"></constructor-arg> <constructor-arg value="4000" type="double"></constructor-arg> </bean> |
程序便會正確執行
在constructor-arg標簽中還有index屬性,該屬性的屬性值從0開始,給構造器中指定位置的參數賦值.
③工廠方法註入(很少使用,不推薦)
註入屬性值的詳解
① 字面值
可以通過value元素標簽或value屬性進行入
<constructor-arg value="lisi"></constructor-arg> |
可用如下代碼進行替換
<constructor-arg> <value>lili</value> </constructor-arg> |
基本數據類型及其封裝類、String等類型都可以采用字面值註入的方式,若字面值中包含特殊字符,可以使用<![CDATA[值]]>把字面值包裹起來
例如:我們要給屬性賦一個郵箱
<constructor-arg> <value><![CDATA[[email protected]]]></value> </constructor-arg> |
引用其它javaBean
組成應用程序的Bean經常需要相互寫作以完成應用程序的功能,要使用Bean能夠相互訪問,就必須在Bean配置文件中指定對Bean的引用
Bean配置的形式:
① 使用外部Bean進行配置
在Bean的配中可以通過<ref>元素或ref屬性為Bean的屬性或構造器參數指定對Bean的引用。
實例1:使用外部bean和ref屬性進行配置
</bean> <bean id="car1" class="cn.bdqn.spring.Car"> <property name="brand" value="ford"></property> <property name="price" value="230000"></property> </bean> <bean id="p3" class="cn.bdqn.spring.Person"> <property name="name" value="bell"></property> <property name="age" value="23"></property> <property name="car" ref="car1"></property> </bean> |
實例2:使用外部bean和ref節點進行配置
<bean id="car1" class="cn.bdqn.spring.Car"> <property name="brand" value="ford"></property> <property name="price" value="230000"></property> </bean> <bean id="p3" class="cn.bdqn.spring.Person"> <property name="name" value="bell"></property> <property name="age" value="23"></property> <property name="car"> <ref bean="car1" /> </property> </bean> |
也可以使用構造器的方式進行配置,其配置操作也不經相同
② 使用內部Bean進行配置
也可以在屬性或構造器中包含Bean的聲明,這樣的Bean稱為內部Bean
實例:
<bean id="p3" class="cn.bdqn.spring.Person"> <property name="name" value="bell"></property> <property name="age" value="23"></property> <property name="car"> <bean id="car1" class="cn.bdqn.spring.Car"> <property name="brand" value="ford"></property> <property name="price" value="230000"></property> </bean> </property> </bean> |
內部Bean和外部Bean的區別:內部Bean不能被外部所訪問,僅供所在Bean的引用
註入參數詳解:null值和級聯屬性
可以使用專用的</null>標簽為Bean的字符串或其他對象類型的屬性註入null值(意義不大,因為引用類型的屬性的默認值就是null)
和Strus、Hibernate 等框架一樣,Spring支持級聯屬性的配置
級聯屬性實例:
<bean id="p2" class="cn.bdqn.spring.Person"> <!-- <constructor-arg value="lisi"></constructor-arg> --> <constructor-arg> <value><![CDATA[[email protected]]]></value> </constructor-arg> <constructor-arg value="meiguo"></constructor-arg> <constructor-arg value="4000" type="double"></constructor-arg> <constructor-arg ref="car"></constructor-arg> <property name="car.brand" value="changan"></property> <property name="car.price" value="100000"></property> </bean> <bean id="car" class="cn.bdqn.spring.Car"></bean> |
註意:為級聯屬性賦值,屬性需要先初始化後才可以為級聯屬性賦值。否則會報異常
集合屬性:
在Spring中可以通過一組內置的xml標簽(例如:<list>、<set>或<map>)來配置集合屬性。
① 配置java.util.List類型的屬性
需要指定<list>標簽,在標簽裏包含一些元素,這些標簽可以通過<value>指定簡單的常量值,通過<ref>指定對其他Bean的引用,通過<bean>指定內置Bean的定義,通過<null/>指定空元素,甚至可以內嵌其他集合。
② 數組的定義和List一樣,都是用<list>
③ 配置java.util.Set需要使用<set>標簽,定義元素的方法與List一樣
實例:
模擬,一人有多輛車
<bean id="car1" class="cn.bdqn.spring.Car"> <property name="brand" value="ford"></property> <property name="price" value="100000"></property> </bean> <bean id="car2" class="cn.bdqn.spring.Car"> <property name="brand" value="寶馬"></property> <property name="price" value="200000"></property> </bean> <bean id="car3" class="cn.bdqn.spring.Car"> <property name="brand" value="奔馳"></property> <property name="price" value="300000"></property> </bean> <bean id="person" class="cn.bdqn.spring.Person"> <property name="name" value="baoqiang"></property> <property name="age" value="23"></property> <property name="car"> <list> <ref bean="car1" /> <ref bean="car2" /> <ref bean="car3" /> </list>
</property> </bean> |
也可以寫成內部Bean的樣式
<bean id="person" class="cn.bdqn.spring.Person"> <property name="name" value="baoqiang"></property> <property name="age" value="23"></property> <property name="car"> <list> <bean id="car1" class="cn.bdqn.spring.Car"> <property name="brand" value="ford"></property> <property name="price" value="100000"></property> </bean> <bean id="car2" class="cn.bdqn.spring.Car"> <property name="brand" value="寶馬"></property> <property name="price" value="200000"></property> </bean> <bean id="car3" class="cn.bdqn.spring.Car"> <property name="brand" value="奔馳"></property> <property name="price" value="300000"></property> </bean> </list>
</property> </bean> |
④ Java.util.Map通過<map>標簽定義
<map>標簽裏可以使用多個entry作為子標簽,每個條目包含一個鍵和一個值
必須在<key>標簽裏定義鍵
因為鍵和值的類型沒有限制,所以可以自由地為它們指定<value>,<ref>,<bean>,<null>元素
可以將Map的鍵和值作為<entry>的屬性定義:簡單敞亮可以使用key和value來定義;Bean引用通過key-ref和value-ref屬性定義
實例:模擬一人有多量車(使用外部Bean的方式)
<bean id="car1" class="cn.bdqn.spring.Car"> <property name="brand" value="ford"></property> <property name="price" value="100000"></property> </bean> <bean id="car2" class="cn.bdqn.spring.Car"> <property name="brand" value="寶馬"></property> <property name="price" value="200000"></property> </bean> <bean id="car3" class="cn.bdqn.spring.Car"> <property name="brand" value="奔馳"></property> <property name="price" value="300000"></property> </bean> <!-- 配置Map屬性值 --> <bean id="newPerson" class="cn.bdqn.spring.Person"> <property name="name" value="jielun"></property> <property name="age" value="32"></property> <property name="car"> <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> |
Map中key的值由我們指定,value是引用的實例
⑤使用<props>定義java.util.Properties
該標簽使用多個<prop>作為子標簽,每個<prop>標簽必須定義key屬性。
實例:
<bean id="mysql" class="cn.bdqn.spring.DateSource"> <property name="properties"> <props> <prop key="userName">admin</prop> <prop key="password">admin</prop> <prop key="url">jdbc:mysql://test</prop> <prop key="driver"> com.mysql.jdbc.Driver</prop> </props> </property> </bean> |
⑥使用utility scheme定義集合
使用基本的集合標簽定義集合時,不能將集合作為獨立的Bean定義,導致其他Bean無法引用該集合,所以無法再不同的Bean之間共享集合
可以使用util schema裏的集合標簽定義獨立的集合Bean。需要註意的是,必須在<beans>根元素裏添加util schema定義
實例:模擬一人有多輛車
首先需要導入util命名空間
如下圖:
代碼如下:
<!-- 配置獨立的集合bean,以供多個bean進行引用.需要導入util命名空間 --> <bean id="car1" class="cn.bdqn.spring.Car"> <property name="brand" value="ford"></property> <property name="price" value="100000"></property> </bean> <bean id="car2" class="cn.bdqn.spring.Car"> <property name="brand" value="寶馬"></property> <property name="price" value="200000"></property> </bean> <bean id="car3" class="cn.bdqn.spring.Car"> <property name="brand" value="奔馳"></property> <property name="price" value="300000"></property> </bean>
<util:list id="cars"> <ref bean="car1" /> <ref bean="car2"/> <ref bean="car3"/> </util:list>
<bean id="p1" class="cn.bdqn.spring.Person"> <property name="name" value="xiaozhao"></property> <property name="age" value="25"></property> <property name="car" ref="cars"></property> </bean> |
⑦P命名空間的使用
我們還可以使用P命名空間對bean進行配置
為來簡化XML文件的配置,越來越多的XML文件采用屬性而非子元素配置信息
Spring從2.5版本開始引入一個新的P命名空間,可以通過<bean>元素屬性的方式配置Bean的屬性。
使用P命名空間後,基於XML的配置方式將進一步簡化
實例:模擬一人有多輛車
首先先引入P命名空間
如下圖
使用util和P命名空間代碼:
<bean id="car1" class="cn.bdqn.spring.Car"> <property name="brand" value="ford"></property> <property name="price" value="100000"></property> </bean> <bean id="car2" class="cn.bdqn.spring.Car"> <property name="brand" value="寶馬"></property> <property name="price" value="200000"></property> </bean> <bean id="car3" class="cn.bdqn.spring.Car"> <property name="brand" value="奔馳"></property> <property name="price" value="300000"></property> </bean> <util:list id="cars"> <ref bean="car1" /> <ref bean="car2" /> <ref bean="car3" /> </util:list>
<bean id="person" class="cn.bdqn.spring.Person" p:name="xiaowang" p:age="23" p:car-ref="cars"> </bean> |
Spring中的Bean配置