在Spring-IoC簡介中簡單介紹了什么是IoC以及一些相關(guān)的概念,這里將詳細(xì)介紹如何通過IoC容器提供的方法進(jìn)行注入和如何進(jìn)行注入配置。
依賴注入
IoC提供的依賴注入方法主要有屬性注入多糠、構(gòu)造函數(shù)注入和工廠方法注入,這里依次介紹如何通過各個方法注入Bean
。
屬性注入
屬性注入要求Bean
提供一個默認(rèn)的構(gòu)造器,并為需要注入的屬性提供對應(yīng)的setter
方法巡李。Spring會檢查Bean
中是否有setter
方法,但不會檢查是否有對應(yīng)的屬性成員扶认。
Bean
的代碼如下侨拦。
public class Car{
private int maxSpeed;
private String brand;
//如果要通過屬性注入則必須實(shí)現(xiàn)setter方法
public void setXX(<T> XX){
this.XX=XX;
}
}
我們這里通過XML文件對Bean
進(jìn)行設(shè)置,后面會詳細(xì)介紹所有的配置方式和配置內(nèi)容辐宾。
<bean id="car" class="Car">
<property name="maxSpeed"><value>200</value></property>
<property name="brand"><value>紅旗CA72</value></property>
</bean>
這樣設(shè)置完成后狱从,當(dāng)Spring啟動后,就會自動生成id
為car
叠纹,class
為Car
季研,屬性分別為200
和紅旗CA72
的Bean
。
對于屬性的命名吊洼,要求變量的前兩個字母要么全部大寫训貌,要么全部小寫,iCCard
冒窍、iDCode
是非法的。如果取非法的變量名豺鼻,在試圖啟動Spring時综液,將會失敗。因此命名的建議是像QQ儒飒、MSN谬莹、ID等正常以大寫字母出現(xiàn)的專業(yè)術(shù)語,在Java中一律使用小寫形式桩了。
構(gòu)造函數(shù)注入
當(dāng)想要通過構(gòu)造函數(shù)注入時附帽,需要在Bean
中實(shí)現(xiàn)相應(yīng)的構(gòu)造函數(shù),并以想要注入的屬性為參數(shù)井誉。
Bean
的代碼如下蕉扮。
public class Car{
private int maxSpeed;
private String brand;
public Car(int maxSpeed,String brand){...};
}
然后我們在XML文件中進(jìn)行配置。
<bean id="car" class="Car">
<constructor-arg type="java.lang.String">
<value>紅旗</value>
</constructor-arg>
<constructor-arg type="double">
<value>200</value>
</constructor-arg>
</bean>
在通過構(gòu)造器注入時颗圣,配置文件中arg
的順序與構(gòu)造器中的參數(shù)順序無關(guān)喳钟,當(dāng)只有一個構(gòu)造器的情況下上述配置文件才會生效屁使。因此建議使用索引匹配入?yún)ⅲ?code><constructor-arg index="0" value="紅旗">奔则。
當(dāng)兩個構(gòu)造器僅有int
和double
的區(qū)別(如下)蛮寂,則此時還需要在配置文件中加上參數(shù)類型以作區(qū)分,即<constructor-arg index="0" type="int" value="200"/>
易茬。
public class Car{
private int maxSpeed;
private double averageSpeed;
private String brand;
public Car(int maxSpeed,String brand){...};
public Car(double averageSpeed,String brand){...};
}
如果構(gòu)造函數(shù)的參數(shù)的類型是可以辨別的(非基礎(chǔ)數(shù)據(jù)類型且入?yún)㈩愋透鳟悾?/strong>酬蹋,則可以不提供類型和索引的信息。
構(gòu)造器注入可能會出現(xiàn)循環(huán)依賴的問題抽莱,即A
類需要注入B
類范抓,B
類需要注入A
類,在這種情況下岸蜗,使用屬性注入就可以解決了尉咕。
工廠方法注入
在使用框架的過程中很少會使用到工廠方法注入,以下僅舉2個例子璃岳。
- 非靜態(tài)工廠類
public class CarFactory{
public Car createHongQiCar(){}
}
<bean id="carFactory" class="CarFactory"/>
<bean id="car" factory-bean="carFactory" factory-method="createHongQiCar"/>
由于工廠類不是靜態(tài)的年缎,因此需要先定義工廠類的bean。
- 靜態(tài)工廠類
public class CarFactory{
public static Car createHongQiCar(){}
}
<bean id="car" class="CarFactory" factory-method="createCar"/>
Bean的配置方式
配置Bean
可以通過XML铃慷、注解单芜、Java類和Groovy DSL這四種方式,下面來詳細(xì)介紹各個配置方法的細(xì)節(jié)犁柜。
基于XML的配置
對于基于XML的配置洲鸠,Spring2.0以后采用Schema格式,使得配置文件更具擴(kuò)展性馋缅,但文件頭聲明會復(fù)雜一些扒腕,下面是一個例子。
<?xml version="1.0" encoding="utf-8"?>
<beans
xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:aop="http://www.springframework.org/schema/aop"
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"
>
<!-- 默認(rèn)命名空間的配置 -->
<bean id="foo" class="com.smart.Foo"/>
<!-- aop命名空間的配置 -->
<aop:config>
<aop:advisor pointcut="execution(* *..PetStoreFacade.*(..))" advice-ref="txAdvice"/>
</aop:config>
</beans>
在上面的代碼中定義了3個命名空間:
-
xmlns="http://www.springframework.org/schema/beans"
萤悴,默認(rèn)命名空間:沒有空間名瘾腰,用于Spring Bean的定義。 -
xsi
標(biāo)準(zhǔn)命名空間:這個命名空間用于指定自定義命名空間的Schema樣式文件覆履,是W3C定義的標(biāo)準(zhǔn)命名空間蹋盆。 -
xmlns:aop="http://www.springframework.org/schema/aop"
,aop命名空間:這個命名空間是Spring配置aop的命名空間硝全,即一種自定義的命名空間栖雾。
命名空間的定義分為兩個步驟:
- 第一步指定命名空間的名稱,如
xmlns:aop="http://www.springframework.org/schema/aop"
伟众。aop
為命名空間的別名析藕,而"http://www.springframework.org/schema/aop"
是命名空間的全限定名,習(xí)慣上用文檔發(fā)布機(jī)構(gòu)的官方網(wǎng)站和相關(guān)網(wǎng)站目錄作為全限定名赂鲤。如果命名空間的別名為空噪径,則表示該命名空間為文檔默認(rèn)的命名空間柱恤。 - 第二步指定命名空間的Schema文檔格式文件的位置,用空格或回車換行進(jìn)行分隔找爱。定義的語法如下
<命名空間1> <命名空間1Schema文件> <命名空間2> <命名空間2Schema文件>
(注意之間的分隔符可以為空格或換行符)梗顺。Schema地址有2個用途:一是XML解析器可以獲取Schema文件并對文檔進(jìn)行格式合法性驗(yàn)證;二是IDE可以引用Schema文件對文檔編輯提供自動補(bǔ)全功能车摄。
以上就是一個XML配置文件的結(jié)構(gòu)介紹寺谤,接下來將介紹如何對Bean
進(jìn)行定制。
-
字面值
對于基本類型或其封裝類吮播,我們在XML中可以直接進(jìn)行設(shè)置变屁。對于字符串來說,如果其中包含了&意狠、<粟关、>、"环戈、'這5種特殊字符闷板,可以通過下面的![CDATA[]]
進(jìn)行包裝,使得XML解析器將其中的內(nèi)容當(dāng)成純文本院塞;或者可以通過轉(zhuǎn)義序列來表示&遮晚、<、>拦止、"县遣、&apos。<bean id="car" class="Car"> <property name="maxSpeed"> <value>200</value> </property> <property name="brand"> <value><![CDATA[紅旗&CA72]]></value> </property> </bean>
-
引用其他bean
可以通過以下3種標(biāo)簽對其他的bean進(jìn)行引用汹族。- bean:可以引用同一容器或父容器總的Bean萧求,這是最常見的形式。
- local:只引用同一配置文件中的Bean顶瞒。
- parent:只引用父容器中的Bean饭聚。
<!--通過bean--> <bean id="car" class="Car"/> <bean id="boss" class="Boss"> <property name="car"> <ref bean="car"/> </property> </bean> <!--通過local與通過bean的方式類似--> <!--通過parent--> <!--在父容器中定義car--> <bean id="car" class="Car"/> <!--在子容器中定義另一個car--> <bean id="car" class="Car"/> <bean id="boss" class="Boss"> <ref parent="car"><!--將引用父容器中的car--> </bean>
-
內(nèi)部bean
我們也可以通過隱藏類那樣定義bean。<bean id="boss" class="Boss"> <property name="car"> <bean class="Car"> <property name="brand" value="紅旗"/> </bean> </property> </bean>
-
null值
如果想要注入null值搁拙,需要顯示的將值設(shè)為<null/>
,即<property name="brand"><value><null/></value></property>
法绵。 -
級聯(lián)屬性
如果想要通過這種方式直接對<bean id="boss" class="Boss"> <property name="car.brand" value="紅旗"/> </bean>
boss
中的car
的屬性進(jìn)行設(shè)置箕速,則需要在Boss
類中聲明一個初始化對象并實(shí)現(xiàn)getter()
方法。public class Boss{ private Car car=new Car(); public Car getCar(){return car;} }
-
集合類
- List
如果List的屬性類型可以通過字符串字面值進(jìn)行配置朋譬,那么就可以使用這種方式盐茎,如<bean id="boss" class="Boss"> <property name="favorites"> <list> <value>看報(bào)</value> <value>滑雪</value> </list> </property> </bean>
String[]
、int[]
等徙赢。
此外字柠,List還可以通過<ref>注入容器中其他的Bean探越。- Set
<bean id="boss" class="Boss"> <property name="favorites"> <set> <value>看報(bào)</value> <value>滑雪</value> </set> </property> </bean>
- Map
<bean id="boss" class="Boss"> <property name="jobs"> <map> <entry> <key><value>AM</value><key> <value>會見客戶</value> </entry> <entry> <key><value>PM</value><key> <value>開會</value> </entry> <!--如果鍵值對都是對象--> <entry> <key><ref bean="keyBean"/><key> <ref bean="valueBean"/> </entry> </map> </property> </bean>
-
Properties
Properties屬性可以看成鍵值都是字符串的Map類型。<bean id="boss" class="Boss"> <property name="jobs"> <props> <prop key="mail">123@gmail.com</prop> </props> </property> </bean>
-
強(qiáng)類型集合
Spring配置強(qiáng)類型和非強(qiáng)類型集合相同窑业,會將值自動轉(zhuǎn)換為目標(biāo)類型钦幔。public class Car{ private Map<Integer,String> passengers=new HashMap<Integer,String>(); }
-
集合合并
<bean id="boss1" class="Boss"> <property name="favorites"> <set> <value>看報(bào)</value> </set> </property> </bean> <bean id="boss2" class="Boss" parent="boss1"> <property name="favorites"> <set merge="true"> <!--合并父類中的同名set--> <value>看報(bào)</value> </set> </property> </bean>
-
配置集合類型的Bean
如果想要配置集合類型的Bean,而不是屬性類型的集合常柄,可以通過在Spring配置文件中引入util命名空間的聲明鲤氢,然后進(jìn)行配置。<beans xmlns:util="http://www.springframework.org/schema/util"> xsi:shcemaLocation="http://www.springframework.org/schema/util http://www.springframework.org/schema/util/spring-util-4.0.xsd" <util:list id="favorite" list-class="java.util.LinkedList"> <value>喝茶</value> <value>看報(bào)</value> </util:list> </beans>
簡化XML配置方式
- 字面值屬性
類型 | 簡化前 | 簡化后 |
---|---|---|
字面值屬性 | <property name="maxSpeed"><value>200</value></property> | <property name="maxSpeed" value="200"/> |
構(gòu)造函數(shù)參數(shù) | <constructor-arg index="0"><value>200</value></constructor-arg> | <constructor-arg index="0" value="200"/> |
集合元素 | <map> <entry> <key><value>AM</value></key> <value>見客戶</value> </entry> </map> |
<map> <entry key="AM" value="見客戶"/> </map> |
- 引用對象屬性
類型 | 簡化前 | 簡化后 |
---|---|---|
字面屬性值 | <property name="car"> <ref-bean="car"/></property> | <property name="car" ref="car"> |
構(gòu)造函數(shù) | <constructor-arg> <ref-bean="car"></property> | <constroctor-arg ref="car"/> |
集合元素 | <entry> <key><ref bean="keyBean"/></key> <ref bean="valueBean"> </entry> |
<entry key-ref="keyBean" value-ref="valueBean"/> |
<ref>的簡化形式對應(yīng)于<ref bean="xxx">西潘,而<ref local>和<ref parent>沒有對應(yīng)的簡化形式卷玉。
- 使用p命名空間
<beans xmlns:p="http://www.springframework.org/schema/p"><!--聲明p命名空間-->
<bean id="car" class="Car"
p:brand="紅旗"
p:maxSpeed="200"/>
<bean id="boss" class="Boss"
p:car-ref="car"/>
</beans>
基于注解的配置
采用基于注解的配置文件,則Bean
定義信息通過在Bean
實(shí)現(xiàn)類上標(biāo)注注解實(shí)現(xiàn)喷市。
//這里定義了一個Dao的Bean
/*
與@Component功能相似的還有:
@Repository:用于對DAO實(shí)現(xiàn)類進(jìn)行標(biāo)注
@Service:用于對Service實(shí)現(xiàn)類進(jìn)行標(biāo)注
@Controller:用于對Controller實(shí)現(xiàn)類進(jìn)行標(biāo)注
*/
@Component("carDao")
public class CarDao{
//..
}
對于通過注解定義的bean需要在Spring配置文件中進(jìn)行額外設(shè)置相种。
<beans
xmlns:context="http://www.springframework.org/schema/context"
xsi:"http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context-4.0.xsd"
>
<!--掃描類包以應(yīng)用注解的bean,可以通過resource-pattern進(jìn)行過濾 -->
<!-- 其余過濾的方法還有include-filter和exclude-filter -->
<context:component-scan base-package="package" resource-pattern="./*.class">
</beans>
對Bean
完成配置后品姓,還需要通過注解進(jìn)行自動注入
@Service
public class LoginService{
//注入LogDao的bean
//對required=false設(shè)置寝并,當(dāng)Spring啟動時如果未找到對應(yīng)的bean則不會報(bào)錯
//通過Qualifier可以指定對應(yīng)bean的名稱
@Autowired(required=false)
@Qualifier("logDao")
private LogDao logDao;
//對類方法進(jìn)行標(biāo)注
@Autowired
@Qualifier("logDao")
public void setLogDao(LogDao logDao){}
//或者通過這種形式
public void setLogDao(@Qualifier("logDao")LogDao logDao){}
//如果對類中集合類的變量或方法入?yún)⑦M(jìn)行標(biāo)注,那么Spring會將容器中類型匹配的所有Bean都注入
@Autowired
private List<Plugin> plugins;
//Spring如果發(fā)現(xiàn)變量是一個list和一個map缭黔,會將容器中匹配集合元素類型的所有bean都注入
//這里將會把plugins的bean注入map集合食茎,key是bean的名字,value是所有實(shí)現(xiàn)了plugin的bean馏谨。
@Autowired
private Map<String,Plugin> pluginMaps别渔;
//如果Plugin有多個實(shí)現(xiàn)類,那么可以在不同的實(shí)現(xiàn)類前用@Order(value=1)對注入順序進(jìn)行設(shè)置惧互,越小越先加載
}
基于Java類的配置哎媚、基于Groovy DSL的配置
一般來說,使用XML和標(biāo)注的方式就能解決幾乎所有的任務(wù)喊儡。建議使用XML配置DataSource拨与、SessionFactory等資源bean,在XML中利用aop艾猜、context命名空間進(jìn)行相關(guān)主題的配置买喧,其余所有項(xiàng)目中開發(fā)的Bean都通過基于注解配置的方式進(jìn)行配置。
Bean基本配置
Bean的命名
Bean
的id屬性命名與Java變量的命名要求相同匆赃,而name屬性命名沒有任何字符上的限制淤毛。可以通過不設(shè)置id屬性命名來實(shí)例化匿名Bean
算柳。
<bean class="Car"/>
<bean class="Car"/>
<bean class="Car"/>
這樣就實(shí)例化了3個匿名Bean
低淡,第一個Bean
通過getBean("Car")
獲得,第二個通過getBean("Car#1")
獲得。
依賴注入
Spring支持屬性注入和構(gòu)造函數(shù)注入蔗蹋,除此之外還支持工廠法注入方式何荚。