2019-06-11
? Ioc即Inverse of Control,中文為控制反轉。
? 在Spring中,創(chuàng)建對象的工作不再由應用程序主動完成,而是由Spring容器負責創(chuàng)建,然后注入給應用程序,由Spring來管理應用程序中的所有對象及其依賴關系。所以控制反轉是說創(chuàng)建對象的控制權進行轉移,以前創(chuàng)建對象是由應用程序自己把控的,而現(xiàn)在這種權力轉移交給了Spring容器。
? 應用程序在使用了Spring后,就無需再進行對象的創(chuàng)建工作了,而是通過Spring配置文件描述對象的創(chuàng)建方法、參數(shù)以及對象間的依賴關系。Spring會自動依據(jù)配置文件中對象之間的依賴關系運用Java的反射技術創(chuàng)建所需要的對象。
創(chuàng)建對象
在Spring核心文件中使用<bean>標簽創(chuàng)建對象
<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>
獲取對象
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實例的生存空間或有效范圍??赏ㄟ^配置文件中<bean>元素的scope屬性配置。
| 作用域名稱 | 功 能 描 述 |
|---|---|
| singleton | 單實例作用域,這是Spring容器默認的作用域。使用singleton作用域生成的是單實例,在整個Bean容器中僅保留一個實例對象供所有調(diào)用者共享引用。Spring容器負責跟蹤Bean實例的狀態(tài),負責維護Bean實例的生命周期行為。單例模式對于那些無會話狀態(tài)的Bean(如輔助工具類、DAO組件、業(yè)務邏輯組件等)是最理想的選擇。 注意:Spring通過AOP與LocalThread功能解決了DAO中Connection的非線程安全問題。 |
| prototype | 原型模式,這是多實例作用域,每次從容器中獲取Bean時,都會創(chuàng)建一個新的實例以供調(diào)用者使用。prototype作用域非常適用于那些需要保持會話狀態(tài)的Bean實例,但其內(nèi)存開銷太大。 有一點值得注意的就是,Spring不能對一個prototype Bean的整個生命周期負責,容器在初始化、裝配好一個prototype實例后,將它交給客戶端,隨后就對該prototype實例不聞不問了。因此,客戶端要負責prototype實例的生命周期管理。 |
| request | 針對每次HTTP請求,Spring容器會根據(jù)Bean的定義創(chuàng)建一個全新的Bean實例, 且該Bean實例僅在當前HTTP request內(nèi)有效,因此可以根據(jù)需要放心地更改所建實例的內(nèi)部狀態(tài), 而其他請求中根據(jù)Bean定義創(chuàng)建的實例,將不會看到這些特定于某個請求的狀態(tài)變化。 當處理請求結束,request作用域的Bean實例將被銷毀。該作用域僅在基于web的Spring ApplicationContext情形下有效。 |
| session | 針對某個HTTP Session,Spring容器會根據(jù)Bean定義創(chuàng)建一個全新的Bean實例,且該Bean實例僅在當前HTTP Session內(nèi)有效。 與request作用域一樣,我們可以根據(jù)需要放心地更改所創(chuàng)建實例的內(nèi)部狀態(tài),而別的HTTP Session中根據(jù)Bean定義創(chuàng)建的實例, 將不會看到這些特定于某個HTTP Session的狀態(tài)變化。 當HTTP Session最終被廢棄的時候,在該HTTP Session作用域內(nèi)的Bean實例也會被廢棄掉。該作用域僅在基于Web的Spring ApplicationContext情形下有效。 |
| global session | global session作用域類似于標準的HTTP Session作用域,不過它僅僅在基于portlet的Web應用中才有意義。portlet規(guī)范定義了全局Session的概念,它被所有構成某個portlet Web應用的各種不同的portlet所共享。在global session作用域中定義的Bean被限定于全局portlet Session的生命周期范圍內(nèi)。如果我們是在編寫一個標準的基于Servlet的Web應用,并且定義了一個或多個具有global session作用域的Bean,系統(tǒng)會使用標準的HTTP Session作用域,并且不會引起任何錯誤。該作用域僅在基于Web的Spring ApplicationContext情形下有效。 |
當系統(tǒng)創(chuàng)建Spring容器時,默認會預初始化所有的singleton Bean。即容器初始化完成后,容器中所有的singleton Bean也實例化完成。這意味著系統(tǒng)前期初始化時將有較大的開銷,但一旦初始化完成,程序后面獲取singleton Bean實例時將擁有較好性能。
可以通過指定<bean>元素中的lazy-init屬性來延遲初始化Bean,這樣將會在第一次獲取Bean的時候初始化Bean。
<bean id="" class="" lazy-init="true"/>
如果想對所有的Bean都延遲初始化,可以修改<beans>元素
<beans lazy-init="true">
ApplicationContext接口的常用方法
boolean containsBean(String name)
判斷IoC容器是否包含id為name的Bean實例。
Class<?> getType(String name)
返回容器中指定Bean實例的類型。
Boolean isSingleton(String)
判斷給定名稱的Bean實例是否為單例(Singleton)模式。
T getBean(Class<T> requiredType)
獲取IoC容器中屬于requiredType類型的、唯一的Bean實例。
Object getBean(String name)
返回容器id為name的Bean實例。
T getBean(String name,Class requiredType)
返回容器中id為name,但在返回之前會進行類型檢查。如果不能轉換成requiredType類型,則會拋出異常。
Spring DI配置
DI即依賴注入,是Ioc思想的具體體現(xiàn),表示對象之間的依賴關系由Spring管理,應用程序在運行時由Spring容器動態(tài)地將對象的依賴關系裝配好,而不是由應用程序手動裝配。
基于setter方法的依賴注入
<!-- 注冊一個Country實例名稱為country -->
<bean id="country" class="com.model.Country">
<property name="id" value="101"/>
<property name="name" value="中華人民共和國"/>
</bean>
<!-- 注冊一個User實例名稱為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實例 -->
</bean>
基于構造器的依賴注入
通過調(diào)用帶參數(shù)的構造器實現(xiàn)。配置<constructor-arg>元素時可指定index屬性,用于指定該構造參數(shù)將作為第幾個構造參數(shù)值。如index="0"表明該構造參數(shù)值將作為第一個構造參數(shù)。可以通過type屬性指定參數(shù)類型,以避免出現(xiàn)構造器重載的匹配問題。
<!-- 注冊一個Country實例名稱為country -->
<bean id="country" class="com.model.Country">
<property name="id" value="101"/>
<property name="name" value="中華人民共和國"/>
</bean>
<!-- 注冊一個User實例名稱為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>標簽分別用來設置類型為List、Set、Map、數(shù)組的屬性值。
主要參數(shù):
- value:指定集合元素值是基本數(shù)據(jù)類型值或字符串類型值
- ref:指定集合元素值是容器中另一個Bean實例
- bean:指定集合元素值是一個嵌套Bean
public class User {
private String id;// ID號
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>
<!-- 注冊一個User實例名稱為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>
分層開發(fā)依賴注入
<!-- 注冊UserDaoImpl實例userDao -->
<bean id="userDao" class="com.dao.impl.UserDaoImpl" />
<!-- 注冊UserServiceImpl實例userService -->
<bean id="userService" class="com.service.impl.UserServiceImpl">
<!--調(diào)用set方法,將UserDaoImpl實例userDao注入給UserServiceImpl實例的userDao屬性-->
<property name="userDao" ref="userDao"/>
</bean>
<!-- 注冊LoginController實例名稱為loginController -->
<bean id="loginController" class="com.controller.LoginController">
<!--調(diào)用set方法,將UserServiceImpl實例userService注入給LoginController實例的userService屬性-->
<property name="userService" ref="userService" />
</bean>
自動裝配
Spring IoC容器可以使用自動裝配(autowire)管理Bean之間的依賴關系,以減少配置量。
自動裝配方式可以通過<bean>元素的autowire屬性指定, 取值如下:
- no:不使用自動裝配,默認值。需要通過ref屬性進行依賴關系的指定。在較大的部署環(huán)境中不鼓勵改變這個配置,顯式配置能夠得到清晰的依賴關系。
- byName:根據(jù)屬性名自動裝配。查找id值與屬性名完全一致的Bean,并將其與屬性自動裝配。
- byType:如果容器中存在一個與指定屬性類型相同的Bean,那么將與該屬性自動裝配。如果存在多個該類型的Bean,那么將會拋出異常。
方法一:給bean元素設置autowire屬性
<bean id="" class="" autowire="byName" />
方法二:設置beans全局自動裝配
<beans default-autowire="byName">
基于注解的Ioc實現(xiàn)
Spring提供了完全基于注解配置Bean、裝配Bean的功能,用于替換原來基于XML的配置方法,減少配置量。
首先要在配置文件中啟用注解掃描:
<context:component-scan base-package="com"/>
<context:component-scan />標簽負責掃描哪些類有注解,如果掃描到有注解的類,則將其注冊為bean,并將bean的名字設置為該類的類名,但首字母小寫。base-package為需要掃描的包路徑(含所有子包)。
常用Spring注解:
- @Controller:用于標注控制器組件
- @Service:用于標注業(yè)務層組件
- @Repository:用于標注數(shù)據(jù)訪問組件
- @Component:用于對比較中立的類進行注解。與前三個注解等效。
- @Resource:用于依賴關系裝配。默認按名稱裝配。名稱可以通過@Resource的name屬性指定。如果沒有指定name屬性,則支持自動裝配。
- @Autowired:自動裝配