2019-06-11
? Ioc即Inverse of Control侵贵,中文為控制反轉(zhuǎn)东抹。
? 在Spring中介蛉,創(chuàng)建對(duì)象的工作不再由應(yīng)用程序主動(dòng)完成爆阶,而是由Spring容器負(fù)責(zé)創(chuàng)建燥透,然后注入給應(yīng)用程序,由Spring來(lái)管理應(yīng)用程序中的所有對(duì)象及其依賴關(guān)系扰她。所以控制反轉(zhuǎn)是說(shuō)創(chuàng)建對(duì)象的控制權(quán)進(jìn)行轉(zhuǎn)移,以前創(chuàng)建對(duì)象是由應(yīng)用程序自己把控的芭碍,而現(xiàn)在這種權(quán)力轉(zhuǎn)移交給了Spring容器徒役。
? 應(yīng)用程序在使用了Spring后,就無(wú)需再進(jìn)行對(duì)象的創(chuàng)建工作了窖壕,而是通過(guò)Spring配置文件描述對(duì)象的創(chuàng)建方法忧勿、參數(shù)以及對(duì)象間的依賴關(guān)系。Spring會(huì)自動(dòng)依據(jù)配置文件中對(duì)象之間的依賴關(guān)系運(yùn)用Java的反射技術(shù)創(chuàng)建所需要的對(duì)象瞻讽。
創(chuàng)建對(duì)象
在Spring核心文件中使用<bean>標(biāo)簽創(chuàng)建對(duì)象
<bean id="user" class="com.jevon.model.User">
<property name="id" value="001"></property>
<property name="name" value="張三"></property>
<property name="age" value="20"></property>
</bean>
獲取對(duì)象
ApplicationContext container = new ClassPathXmlApplicationContext("applicationContext.xml");
User obj = container.getBean("user", User.class);
System.out.println(obj.getId());
System.out.println(obj.getName());
Spring Bean的作用域
Bean的作用域就是Bean實(shí)例的生存空間或有效范圍鸳吸。可通過(guò)配置文件中<bean>元素的scope屬性配置速勇。
作用域名稱 | 功 能 描 述 |
---|---|
singleton | 單實(shí)例作用域晌砾,這是Spring容器默認(rèn)的作用域。使用singleton作用域生成的是單實(shí)例烦磁,在整個(gè)Bean容器中僅保留一個(gè)實(shí)例對(duì)象供所有調(diào)用者共享引用养匈。Spring容器負(fù)責(zé)跟蹤Bean實(shí)例的狀態(tài),負(fù)責(zé)維護(hù)Bean實(shí)例的生命周期行為都伪。單例模式對(duì)于那些無(wú)會(huì)話狀態(tài)的Bean(如輔助工具類呕乎、DAO組件、業(yè)務(wù)邏輯組件等)是最理想的選擇陨晶。 注意:Spring通過(guò)AOP與LocalThread功能解決了DAO中Connection的非線程安全問(wèn)題猬仁。 |
prototype | 原型模式,這是多實(shí)例作用域先誉,每次從容器中獲取Bean時(shí)湿刽,都會(huì)創(chuàng)建一個(gè)新的實(shí)例以供調(diào)用者使用。prototype作用域非常適用于那些需要保持會(huì)話狀態(tài)的Bean實(shí)例褐耳,但其內(nèi)存開(kāi)銷(xiāo)太大叭爱。 有一點(diǎn)值得注意的就是,Spring不能對(duì)一個(gè)prototype Bean的整個(gè)生命周期負(fù)責(zé)漱病,容器在初始化买雾、裝配好一個(gè)prototype實(shí)例后把曼,將它交給客戶端,隨后就對(duì)該prototype實(shí)例不聞不問(wèn)了漓穿。因此嗤军,客戶端要負(fù)責(zé)prototype實(shí)例的生命周期管理。 |
request | 針對(duì)每次HTTP請(qǐng)求晃危,Spring容器會(huì)根據(jù)Bean的定義創(chuàng)建一個(gè)全新的Bean實(shí)例叙赚, 且該Bean實(shí)例僅在當(dāng)前HTTP request內(nèi)有效,因此可以根據(jù)需要放心地更改所建實(shí)例的內(nèi)部狀態(tài)僚饭, 而其他請(qǐng)求中根據(jù)Bean定義創(chuàng)建的實(shí)例震叮,將不會(huì)看到這些特定于某個(gè)請(qǐng)求的狀態(tài)變化。 當(dāng)處理請(qǐng)求結(jié)束鳍鸵,request作用域的Bean實(shí)例將被銷(xiāo)毀苇瓣。該作用域僅在基于web的Spring ApplicationContext情形下有效。 |
session | 針對(duì)某個(gè)HTTP Session偿乖,Spring容器會(huì)根據(jù)Bean定義創(chuàng)建一個(gè)全新的Bean實(shí)例击罪,且該Bean實(shí)例僅在當(dāng)前HTTP Session內(nèi)有效。 與request作用域一樣贪薪,我們可以根據(jù)需要放心地更改所創(chuàng)建實(shí)例的內(nèi)部狀態(tài)媳禁,而別的HTTP Session中根據(jù)Bean定義創(chuàng)建的實(shí)例, 將不會(huì)看到這些特定于某個(gè)HTTP Session的狀態(tài)變化画切。 當(dāng)HTTP Session最終被廢棄的時(shí)候竣稽,在該HTTP Session作用域內(nèi)的Bean實(shí)例也會(huì)被廢棄掉。該作用域僅在基于Web的Spring ApplicationContext情形下有效霍弹。 |
global session | global session作用域類似于標(biāo)準(zhǔn)的HTTP Session作用域丧枪,不過(guò)它僅僅在基于portlet的Web應(yīng)用中才有意義。portlet規(guī)范定義了全局Session的概念庞萍,它被所有構(gòu)成某個(gè)portlet Web應(yīng)用的各種不同的portlet所共享拧烦。在global session作用域中定義的Bean被限定于全局portlet Session的生命周期范圍內(nèi)。如果我們是在編寫(xiě)一個(gè)標(biāo)準(zhǔn)的基于Servlet的Web應(yīng)用钝计,并且定義了一個(gè)或多個(gè)具有g(shù)lobal session作用域的Bean恋博,系統(tǒng)會(huì)使用標(biāo)準(zhǔn)的HTTP Session作用域,并且不會(huì)引起任何錯(cuò)誤私恬。該作用域僅在基于Web的Spring ApplicationContext情形下有效债沮。 |
當(dāng)系統(tǒng)創(chuàng)建Spring容器時(shí),默認(rèn)會(huì)預(yù)初始化所有的singleton Bean本鸣。即容器初始化完成后疫衩,容器中所有的singleton Bean也實(shí)例化完成。這意味著系統(tǒng)前期初始化時(shí)將有較大的開(kāi)銷(xiāo)荣德,但一旦初始化完成闷煤,程序后面獲取singleton Bean實(shí)例時(shí)將擁有較好性能童芹。
可以通過(guò)指定<bean>元素中的lazy-init屬性來(lái)延遲初始化Bean,這樣將會(huì)在第一次獲取Bean的時(shí)候初始化Bean鲤拿。
<bean id="" class="" lazy-init="true"/>
如果想對(duì)所有的Bean都延遲初始化假褪,可以修改<beans>元素
<beans lazy-init="true">
ApplicationContext接口的常用方法
boolean containsBean(String name)
判斷IoC容器是否包含id為name的Bean實(shí)例。
Class<?> getType(String name)
返回容器中指定Bean實(shí)例的類型近顷。
Boolean isSingleton(String)
判斷給定名稱的Bean實(shí)例是否為單例(Singleton)模式生音。
T getBean(Class<T> requiredType)
獲取IoC容器中屬于requiredType類型的、唯一的Bean實(shí)例窒升。
Object getBean(String name)
返回容器id為name的Bean實(shí)例缀遍。
T getBean(String name,Class requiredType)
返回容器中id為name,但在返回之前會(huì)進(jìn)行類型檢查饱须。如果不能轉(zhuǎn)換成requiredType類型域醇,則會(huì)拋出異常。
Spring DI配置
DI即依賴注入冤寿,是Ioc思想的具體體現(xiàn)歹苦,表示對(duì)象之間的依賴關(guān)系由Spring管理青伤,應(yīng)用程序在運(yùn)行時(shí)由Spring容器動(dòng)態(tài)地將對(duì)象的依賴關(guān)系裝配好督怜,而不是由應(yīng)用程序手動(dòng)裝配。
基于setter方法的依賴注入
<!-- 注冊(cè)一個(gè)Country實(shí)例名稱為country -->
<bean id="country" class="com.model.Country">
<property name="id" value="101"/>
<property name="name" value="中華人民共和國(guó)"/>
</bean>
<!-- 注冊(cè)一個(gè)User實(shí)例名稱為user -->
<bean id="user" class="com.model.User">
<property name="id" value="0001" />
<property name="name" value="張三" />
<property name="password" value="123456" />
<property name="country" ref="country" /><!-- 引用country實(shí)例 -->
</bean>
基于構(gòu)造器的依賴注入
通過(guò)調(diào)用帶參數(shù)的構(gòu)造器實(shí)現(xiàn)狠角。配置<constructor-arg>元素時(shí)可指定index屬性号杠,用于指定該構(gòu)造參數(shù)將作為第幾個(gè)構(gòu)造參數(shù)值。如index="0"表明該構(gòu)造參數(shù)值將作為第一個(gè)構(gòu)造參數(shù)丰歌∫腆可以通過(guò)type屬性指定參數(shù)類型,以避免出現(xiàn)構(gòu)造器重載的匹配問(wèn)題立帖。
<!-- 注冊(cè)一個(gè)Country實(shí)例名稱為country -->
<bean id="country" class="com.model.Country">
<property name="id" value="101"/>
<property name="name" value="中華人民共和國(guó)"/>
</bean>
<!-- 注冊(cè)一個(gè)User實(shí)例名稱為user -->
<bean id="user" class="com.model.User">
<constructor-arg value="0001" type="String" />
<constructor-arg value="張三" type="String" />
<constructor-arg value="123456" type="String" />
<constructor-arg ref="country" type="com.model.Country" />
</bean>
集合屬性注入
可以使用<list>眼溶、<set>、<map>晓勇、<array>標(biāo)簽分別用來(lái)設(shè)置類型為L(zhǎng)ist堂飞、Set、Map绑咱、數(shù)組的屬性值绰筛。
主要參數(shù):
- value:指定集合元素值是基本數(shù)據(jù)類型值或字符串類型值
- ref:指定集合元素值是容器中另一個(gè)Bean實(shí)例
- bean:指定集合元素值是一個(gè)嵌套Bean
public class User {
private String id;// ID號(hào)
private String name; // 用戶名
private String password;// 密碼
private List<String> friends; // 好友列表
private Set<Account> accounts;// 賬戶列表
}
<bean id="account" class="com.model.Account" scope="prototype">
<property name="id" value="0001" />
<property name="password" value="111111" />
<property name="balance" value="1000" />
</bean>
<!-- 注冊(cè)一個(gè)User實(shí)例名稱為user -->
<bean id="user" class="com.model.User">
<property name="id" value="1000" />
<property name="name" value="張三" />
<property name="password" value="123456" />
<property name="friends">
<list>
<value>"李四"</value>
<value>"王五"</value>
<value>"趙六"</value>
</list>
</property>
<property name="accounts">
<set>
<ref bean="account" />
<bean class="com.model.Account">
<property name="id" value="0002" />
<property name="password" value="222222" />
<property name="balance" value="2000"/>
</bean>
</set>
</property>
</bean>
分層開(kāi)發(fā)依賴注入
<!-- 注冊(cè)UserDaoImpl實(shí)例userDao -->
<bean id="userDao" class="com.dao.impl.UserDaoImpl" />
<!-- 注冊(cè)UserServiceImpl實(shí)例userService -->
<bean id="userService" class="com.service.impl.UserServiceImpl">
<!--調(diào)用set方法,將UserDaoImpl實(shí)例userDao注入給UserServiceImpl實(shí)例的userDao屬性-->
<property name="userDao" ref="userDao"/>
</bean>
<!-- 注冊(cè)LoginController實(shí)例名稱為loginController -->
<bean id="loginController" class="com.controller.LoginController">
<!--調(diào)用set方法描融,將UserServiceImpl實(shí)例userService注入給LoginController實(shí)例的userService屬性-->
<property name="userService" ref="userService" />
</bean>
自動(dòng)裝配
Spring IoC容器可以使用自動(dòng)裝配(autowire)管理Bean之間的依賴關(guān)系铝噩,以減少配置量。
自動(dòng)裝配方式可以通過(guò)<bean>元素的autowire屬性指定, 取值如下:
- no:不使用自動(dòng)裝配窿克,默認(rèn)值骏庸。需要通過(guò)ref屬性進(jìn)行依賴關(guān)系的指定毛甲。在較大的部署環(huán)境中不鼓勵(lì)改變這個(gè)配置,顯式配置能夠得到清晰的依賴關(guān)系敞恋。
- byName:根據(jù)屬性名自動(dòng)裝配丽啡。查找id值與屬性名完全一致的Bean,并將其與屬性自動(dòng)裝配硬猫。
- byType:如果容器中存在一個(gè)與指定屬性類型相同的Bean补箍,那么將與該屬性自動(dòng)裝配。如果存在多個(gè)該類型的Bean啸蜜,那么將會(huì)拋出異常坑雅。
方法一:給bean元素設(shè)置autowire屬性
<bean id="" class="" autowire="byName" />
方法二:設(shè)置beans全局自動(dòng)裝配
<beans default-autowire="byName">
基于注解的Ioc實(shí)現(xiàn)
Spring提供了完全基于注解配置Bean、裝配Bean的功能衬横,用于替換原來(lái)基于XML的配置方法裹粤,減少配置量。
首先要在配置文件中啟用注解掃描:
<context:component-scan base-package="com"/>
<context:component-scan />
標(biāo)簽負(fù)責(zé)掃描哪些類有注解蜂林,如果掃描到有注解的類遥诉,則將其注冊(cè)為bean,并將bean的名字設(shè)置為該類的類名噪叙,但首字母小寫(xiě)矮锈。base-package為需要掃描的包路徑(含所有子包)。
常用Spring注解:
- @Controller:用于標(biāo)注控制器組件
- @Service:用于標(biāo)注業(yè)務(wù)層組件
- @Repository:用于標(biāo)注數(shù)據(jù)訪問(wèn)組件
- @Component:用于對(duì)比較中立的類進(jìn)行注解睁蕾。與前三個(gè)注解等效苞笨。
- @Resource:用于依賴關(guān)系裝配。默認(rèn)按名稱裝配子眶。名稱可以通過(guò)@Resource的name屬性指定瀑凝。如果沒(méi)有指定name屬性,則支持自動(dòng)裝配臭杰。
- @Autowired:自動(dòng)裝配