Spring之IOC容器裝配Bean
1、Spring裝配Bean的過程大致如下:
Spring啟動時讀取應用程式提供的bean配置資訊,並在Spring容器中生成一份該Bean的配置資訊登錄檔,再根據該登錄檔例項化Bean,裝配Bean的屬性資訊,Bean之間的依賴關係和Bean的行為配置。需要滿足的三個條件:Spring框架的相關jar包(Spring容器)、Bean的配置資訊、Bean的實現類。
2、bean配置資訊的裝載方式:XML的配置方式,基於註解的配置方式,基於Java類的配置方式,Groovy動態語言的配置方式。
3、XML配置方式之Schema配置大致包含兩部分:一部分需要對用到的名稱空間進行宣告;另一部分則需要對宣告的名稱空間進行定義,定義包括名稱空間名稱和位置。
名稱空間的宣告:通過xmlns:別名=“名稱空間名稱”的格式,如下:
//預設名稱空間的宣告
xmlns="http://www.springframework.org/schema/beans"
//標準名稱空間的宣告
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
//aop名稱空間的宣告
xmlns:aop="http://www.springframework.org/schema/aop"
注:預設名稱空間沒有別名,常用標籤<beans></beans>,<bean></bean>
注:aop是自定義名稱空間,常用標籤<aop:config></aop:config>
名稱空間的定義:通過xsi:schemaLocation=“名稱空間全稱 schema檔案位置”的格式,如下:
xsi:schemaLocation=
"http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans-4.0.xsd
http://www.springframework.org/schema/aop
http://www.springframework.org/schema/aop/spring-aop-4.0.xsd"
4、XML配置方式之Spring常用的Schema檔案:
spring-beans-4.0.xsd:用於配置Bean; spring-aop-4.0.xsd:用於AOP的配置; spring-tx-4.0.xsd:用於宣告式事務的配置; spring-mvc-4.0.xsd:用於MVC的配置; spring-util-4.0.xsd:用於簡化某些標準配置; spring-jee-4.0.xsd:用於簡化JavaEE中EJB、JNDI等功能的配置; spring-jdbc-4.0.xsd:用於Spring內嵌資料庫的配置; spring-jms-4.0.xsd:用於JMS的配置; spring-lang-4.0.xsd:用於整合Groovy等動態語言; spring-oxm-4.0.xsd:用於物件XML對映的配置; spring-task-4.0.xsd:用於任務排程; spring-tool-4.0.xsd:用於整合一些工具。
5、XML配置方式之裝配Bean,如下:
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation=
"http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans-4.0.xsd">
<bean id="car" class="com.smart.simple.Car"/>
<bean name="boss" class="com.smart.simple.Boss"/>
</beans>
注:bean的命名可以用id或name,其中id被要求必須以字母開頭且不能出現逗號、空格等非結束符號,name沒有字元限制。
注:bean可以指定多個名稱,如下:
<bean id="car,car1,car2" calss="com.smart.simple.Car"/>
<bean name="boss1,boss2,boss3" calss="com.smart.simple.Boss">
6、XML配置方式之屬性注入,大致有三種注入方式:第一種屬性注入,第二種建構函式注入,第三種工廠方法注入。
屬性注入是通過該屬性的setter方法進行注入的方式,一般需要兩個條件:一個是需要被注入物件有空引數的建構函式,另一個是需要被注入物件有該屬性的setter方法設定值。Spring容器先呼叫空構造例項化被注入的bean,再呼叫其setter方法注入屬性值,被注入物件示例如下:
package com.smart.ditype
public class Car{
private String color;
//被注入物件的空構造
public Car(){}
//被注入物件屬性的setter方法
public void setColor(String color){
this.color = color;
}
}
注:如果類中沒有定義任何建構函式,那麼JVM會自動生成一個預設的空構造,上述Bean的配置檔案如下:
<bean id="car" class="com.smart.ditype.Car">
<property name="color" value="紅色">
</bean>
7、XML配置方式之建構函式注入:
建構函式注入是Bean在例項化時以引數的形式注入,大致有三種入參方式:根據型別入參、根據索引入參、型別和索引的聯合、通過自身型別的反射入參。被注入物件的有參建構函式如下:
package com.smart.ditype
public class Car{
private String color;
private int maxSpeed;
//被注入物件的有參構造
public Car(String color,int maxSpeed){
this.color = color;
this.maxSpeed = maxSpeed;
}
}
該物件Bean的配置檔案如下:
<bean id="Car" class="com.smart.ditype.Car">
<constructor-arg type="java.lang.String">
<value>紅色</value>
</constructor-arg>
<constructor-arg type="java.lang.Integer">
<value>200</value>
</constructor-arg>
</bean>
注:在被注入物件的有參建構函式裡,引數型別各不相同時,採用型別入參。若是有多個相同型別的引數,一般採取根據索引入參,其有參建構函式如下:
package com.smart.ditype
public class Car{
private String color;
private String type;
//被注入物件的有參構造
public Car(String color,String type){
this.color = color;
this.type = type;
}
}
該物件Bean的配置檔案如下:
<bean id="car" class="com.smart.ditype.Car">
<constructor-arg index="0" value="紅色"/>
<constructor-arg index="1" value="X-LL130"/>
</bean>
注:在屬性注入中Spring會通過屬性名找到Bean物件中的setter方法設定屬性,而在建構函式注入中Spring不能通過屬性名找到建構函式的引數,需要通過型別或索引間接設定引數。若是過載多個引數個數相同的建構函式,被注入物件如下:
package com.smart.ditype
public Car{
private String color;
private String type;
private double price;
private int maxSpeed;
//被注入物件的有參構造
public Car(String color,String type,int maxSpeed){
this.color = color;
this.type = type;
this.maxSpeed = maxSpeed;
}
//過載有參構造
public Car(String color,String type,double price){
this.color = color;
this.type = type;
this.price = price;
}
}
注:上述使用索引入參不能準確的注入到需要的建構函式中,需要在Bean物件的配置檔案中聯合使用型別入參和索引入參,如下:
<bean id="car" class="com.smart.ditype.Car">
<constructor-arg index="0" value="紅色"/>
<constructor-arg index="1" value="x-ll123"/>
<constructor-arg index="3" type="java.lang.Integer" value="200"/>
</bean>
注:這樣就能準確的將屬性值注入到被注入物件的第一個有參構造中。但是使用有參建構函式注入方式可能出現迴圈依賴的問題,如下:
package com.smart.ditype
public class Car{
private Boss boss;
//被注入物件注入Bean
public Car(Boss boss){
this.boss = boss;
}
}
package com.smart.ditype
public class Boss{
private Car car;
//被注入物件注入Bean
public Boss(Car car){
this.car = car;
}
}
bean的配置檔案如下:
<bean id="car" class="com.smart.ditype.Car">
<constructor-arg index="0" ref="boss"/>
</bean>
<bean id="boss" class="com.smart.ditype.Boss">
<constructor-arg index="0" ref="car"/>
</bean>
注:Spring容器通過建構函式例項化Bean,前提是Bean建構函式引入的引數必須是準備就緒的。當①物件需要注入一個Bean,注入方式採用的是建構函式注入,而這個Bean需要注入①物件,注入方式也採用的是建構函式注入,那麼這兩個bean都不能通過Spring容器進行例項化,這個問題就是迴圈依賴,類似於執行緒死鎖的迴圈。