一、IOC和DI的概念描述
1.1概念
控制反轉(Inversion of Control,縮寫爲IoC),是面向對象編程中的一種設計原則,可以用來減低計算機代碼之間的耦合度。其中最常見的方式叫做依賴注入(Dependency Injection,簡稱DI)。
1.2技術描述
Class A中用到了Class B的對象b,一般情況下,需要在A的代碼中顯式的new一個B的對象。
採用依賴注入技術之後,A的代碼只需要定義一個私有的B對象,不需要直接new來獲得這個對象,而是通過相關的容器控制程序來將B對象在外部new出來並注入到A類裏的引用中。而具體獲取的方法、對象被獲取時的狀態由配置文件(如XML)來指定。
1.3實現方法
實現控制反轉主要有兩種方式:依賴注入和依賴查找。兩者的區別在於,前者是被動的接收對象,在類A的實例創建過程中即創建了依賴的B對象,通過類型或名稱來判斷將不同的對象注入到不同的屬性中,而後者是主動索取響應名稱的對象,獲得依賴對象的時間也可以在代碼中自由控制。
二、Spring IOC詳解
Spring的控制反轉:把對象的創建、初始化、銷燬等工作都交給Spring容器來做。由Spring容器控制對象的聲明週期。
2.1步驟
A.啓動spring容器
1、在類路徑下尋找配置文件來實例化容器
ApplicationContext ctx = new ClassPathXmlApplicationContext(new String[]{"beans.xml"});可以在整個類路徑中尋找xml文件
* 通過這種方式加載。需要將spring的配置文件放到當前項目的classpath路徑下
* classpath路徑指的是當前項目的src目錄,該目錄是java源文件的存放位置。
2、在文件系統路徑下尋找配置文件來實例化容器
ApplicationContext ctx = new FileSystemXmlApplicationContext(new String[]{“d:\\beans.xml“});Spring的配置文件可以指定多個,可以通過String數組傳入。
注:經常用第一種方法啓動容器
B.從spring容器中提取對象
2.2 配置文件中的屬性
2.2.1 別名(alias)
<beans>
<bean name="person" class="cn.alias.spring.Person"/>
<alias name="person" alias="p"/>
</beans>
通過這樣的配置,可以達到在一個地方命名,在多個地方使用不同的名字的效果。
2.2.2 bean對象的scope
singleton(默認值)
在每個Spring IoC容器中一個bean定義只有一個對象實例(共享)。
默認情況下會在容器啓動時初始化bean,但我們可以指定Bean節點的lazy-init=“true”來延遲初始化bean,這時候,只有第一次獲取bean會才初始化bean。如:
<bean id="xxx" class="cn.OrderServiceBean" lazy-init="true"/>
如果想對所有bean都應用延遲初始化,可以在根節點beans設置default-lazy-init=“true“,如下:
<beans default-lazy-init="true“ ...>
prototype
允許bean可以被多次實例化(使用一次就創建一個實例) . Spring不能對一個prototype bean的整個生命週期負責.這就意味着清楚prototype作用域的對象並釋放任何prototype bean所持有的昂貴資源都是客戶端的責任。
2.2.3 Lazy-init
Spring默認在啓動時將所有singleton bean提前進行實例化。提前實例化意味着作爲初始化的一部分,ApplicationContext會自動創建並配置所有的singleton bean.通常情況下這是件好事。因爲這樣在配置中有任何錯誤能立即發現。
Lazy-init=”true or false”
Lazy-init 爲false,spring容器將在啓動的時候報錯(比較好的一種方式)
Lazy-init 爲true,spring容器將在調用該類的時候出錯。
2.2.4init、destroy
Spring初始化bean或銷燬bean時,有時需要作一些處理工作,因此spring可以在創建和拆卸bean的時候調用bean的兩個生命週期方法。
<bean id=“foo” class=“...Foo” init-method=“setup” destory-method=“teardown”/>
當foo被載入到Spring容器中時調用init-method方法。當foo從容器中刪除時調用destory-method(scope = singleton有效)
2.3 創建對象的三種方式
2.3.1 無參構造函數
<bean id=“personService" class="cn.bean.impl.PersonServiceImpl"/>
* 要求PersonServiceImpl有無參構造方法
* spring容器在默認的情況下使用默認的構造函數創建對象
2.3.2 靜態工廠方法
<bean id="personService" class="com.factory.PersonServiceFactory" factory-method="createPersonService" />
public class PersonServiceFactory {
public static PersonService createPersonService(){
return new PersonServiceImpl();
}
}
/**
* 在spring容器 內部,調用了PersonServiceFactory中的createPersonService方法
* 而該方法的內容就是創建對象的過程,是由程序員來完成
*/
2.3.3 實例工廠
<bean id="helloWorldFactory" class="com.spring.ioc.createobject.method.HelloWorldFactory2"></bean>
<!--
factory-bean指向了實力工廠的bean
factory-method實例工廠對象的方法
-->
<bean id="helloWorld" factory-bean="helloWorldFactory" factory-method="getInstance"></bean>
/**
* 實例工廠
* 1、spring容器創建一個實例工廠bean
* 2、該bean調用了工廠方法getInstance產生對象
*/
三、Spring DI詳解
依賴注入(Dependence Injection)是把Spring創建的對象注入到Java類中
有三種注入方式,分別爲setter注入,構造器注入,註解注入,其中前兩種方法都是在xml文件中配置
3.1 setter注入
<bean id="person" class="com.spring.di.xml.setter.Person">
<!--
property描述的就是bean中的屬性
name屬性就是描述屬性的名稱
value就是值 如果是基本屬性(String),就用value賦值
ref 如果是引用類型,用ref賦值
-->
<property name="pid" value="1"></property>
<property name="name" value="王二麻子"></property>
<property name="student" ref="student"></property>
<property name="lists">
<list>
<value>list1</value>
<value>list2</value>
<!--
list中存放一個student對象
-->
<ref bean="student"/>
</list>
</property>
<property name="objects">
<list>
<value>obj1</value>
<ref bean="student"/>
</list>
</property>
<property name="sets">
<set>
<value>set1</value>
<ref bean="student"/>
</set>
</property>
<property name="map">
<map>
<entry key="m1">
<value>m1</value>
</entry>
<entry key="m2">
<ref bean="student"/>
</entry>
</map>
</property>
<property name="properties">
<props>
<prop key="p1">p1</prop>
<prop key="p2">p2</prop>
</props>
</property>
</bean>
3.2 構造器注入
<bean id="person" class="com.spring.di.xml.constructor.Person">
<!--
constructor-arg 代表某一個構造器的參數
index 構造器參數的下標
value
ref
type 類型
-->
<constructor-arg index="0" value="1" type="java.lang.String"></constructor-arg>
<constructor-arg index="1" ref="student"></constructor-arg>
</bean>
Person類中:
public Person(String name,Student student){
this.name = name;
this.student = student;
}
3.3 註解注入
3.3.1 步驟
步驟:
A.在配置文件中,引入context命名空間
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:context="http://www.springframework.org/schema/context"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring- beans-2.5.xsd
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context-2.5.xsd">
B.在配置文件中加入context:annotation-config標籤
<context:annotation-config/>
這個配置隱式註冊了多個對註釋進行解析處理的處理器
AutowiredAnnotationBeanPostProcessor,CommonAnnotationBeanPostProcessor,
PersistenceAnnotationBeanPostProcessor,RequiredAnnotationBeanPostProcessor
注: @Resource註解在spring安裝目錄的lib\j2ee\common-annotations.jar
3.3.2 @Resource
1、@Resource註解和@Autowired一樣,也可以標註在字段或屬性的setter方法上.
2、@Resource註解默認按名稱裝配。
名稱可以通過@Resource的name屬性指定,如果沒有指定name屬性,
•當註解標註在字段上,即默認取字段的名稱作爲bean名稱尋找依賴對象
•當註解標註在屬性的setter方法上,即默認取屬性名作爲bean名稱尋找依賴對象。
/**
* 1、啓動spring容器
* 2、把spring配置文件中的bean實例化(person,student)
* 3、當spring容器解析配置文件
* <context:annotation-config></context:annotation-config>
* spring容器會在納入spring管理的bean的範圍內查找哪些類的屬性上是否加有@Resource註解
* 4、如果在屬性上找到@Resource註解
* 如果@Resource的註解的name屬性的值爲""
* 則把@Resource所在的屬性的名稱和spring容器中的id作匹配
* 如果匹配成功,則賦值
* 如果匹配不成功,則會按照類型進行匹配
* 如果匹配成功,則賦值,匹配不成功,報錯
* 如果@Resource的註解的name屬性的值不爲""
* 則解析@Resource註解name屬性的值,把值和spring容器中的ID進行匹配
* 如果匹配成功,則賦值
* 如果匹配不成功,則報錯
*
* 說明:
* 註解代碼越來越簡單,效率越來越低
* 註解只能應用於引用類型
*/
@Autowired和@Qualifier結合起來用與@Resource效果一樣
3.3.3 @Autowired
這兩個註解的區別是:@Autowired 默認按類型裝配,@Resource默認按名稱裝配,當找不到與名稱匹配的bean纔會按類型裝配。
3.3.4 @Qualifier
3.3.4 @PostConstruct
指定Bean的初始化方法
3.3.4 @PreDestroy
指定Bean的銷燬方法
3.4 Spring中的繼承
Spring-Context之九:在bean定義中使用繼承
作者:黃博文@無敵北瓜