前言
一直說(shuō)自己會(huì)spring,其實(shí)只是會(huì)用而已雨涛。對(duì)它的原理及核心很多都不了解碗旅。IoC控制反轉(zhuǎn)作為Spring的核心,只有不斷慢慢的了解镜悉。
什么是IoC祟辟? ? 侣肄?
我們先來(lái)看一下比較官方的解釋旧困。
IoC,Inversion of Control的縮寫(xiě)稼锅,中文名稱為控制反轉(zhuǎn)吼具,意思是將對(duì)象的控制權(quán)轉(zhuǎn)移至第三方,例如IoC容器矩距,即可由IoC容器來(lái)管理對(duì)象的生命周期拗盒、依賴關(guān)系等。
反正我沒(méi)有看懂锥债。_
舉個(gè)例子
在傳統(tǒng)的人員招聘模式中陡蝇,流程一般都是這樣:HR從多如海的應(yīng)聘簡(jiǎn)歷中挑選然后進(jìn)行筆試痊臭、面試等等一系列篩選后發(fā)放offer。這一系列過(guò)程復(fù)雜而且費(fèi)時(shí)登夫,最關(guān)鍵的是結(jié)果還不理想广匙,特別是針對(duì)某些特定的崗位很難通過(guò)這一模式物色到合適的人才資源。
后來(lái)逐漸出現(xiàn)了一些公司專門提供類似的人才尋訪服務(wù)恼策,這就是大名鼎鼎的獵頭行業(yè)鸦致。獵頭的興起可以說(shuō)很大程度上改變了人才招聘的模式,現(xiàn)在公司需要招聘某個(gè)職位的人才涣楷,只需要告訴獵頭我要一個(gè)怎樣的人干怎樣的工作等等要求分唾,獵頭就會(huì)通過(guò)自己的渠道去物色人才,經(jīng)過(guò)篩選后提供給客戶狮斗,大大簡(jiǎn)化了招聘過(guò)程的繁瑣绽乔,提高了招聘的質(zhì)量和效率。
這其中一個(gè)很重要的變化就是公司HR將繁瑣的招聘尋訪人才的過(guò)程轉(zhuǎn)移至了第三方情龄,也就是獵頭迄汛。相對(duì)比而言,IoC在這里充當(dāng)了獵頭的角色骤视,開(kāi)發(fā)者即公司HR鞍爱,而對(duì)象的控制權(quán)就相當(dāng)于人才尋訪過(guò)程中的一系列工作。
IoC設(shè)計(jì)模式和IoC容器
回到我們所說(shuō)的IoC专酗,首先我們需要肯定的是 IoC并不是特指某種技術(shù)睹逃,而是指一種思想或者說(shuō)一種設(shè)計(jì)模式。我們可以簡(jiǎn)單的理解為我們?cè)谶M(jìn)行程序業(yè)務(wù)邏輯的編程時(shí)通常需要大量的對(duì)象來(lái)協(xié)作完成祷肯,而這些對(duì)象都需要我們通過(guò)類似如下語(yǔ)句
Object object=new Object();//對(duì)象申請(qǐng)
object.setName("XXX");//對(duì)象屬性初始化賦值
的方式申請(qǐng)和初始化沉填,而這些就是所謂的對(duì)象的控制權(quán),IoC設(shè)計(jì)模式的目的就是把這些對(duì)象的控制權(quán)轉(zhuǎn)移至第三方佑笋,由第三方來(lái)進(jìn)行和管理類似對(duì)象申請(qǐng)翼闹、初始化、銷毀對(duì)象的控制權(quán)工作
對(duì)于開(kāi)發(fā)者來(lái)說(shuō)蒋纬,對(duì)象的控制權(quán)的轉(zhuǎn)移意味著我們編程將更加簡(jiǎn)便猎荠,不用再去關(guān)心如何申請(qǐng)、初始化對(duì)象蜀备,甚至是管理對(duì)象关摇、銷毀等復(fù)雜的過(guò)程,這些都將由第三方完成碾阁,只需要告訴第三方我需要怎樣的對(duì)象使用即可输虱。
這里還需要解釋一個(gè)概念,所謂的IoC容器脂凶,就是實(shí)現(xiàn)了IoC設(shè)計(jì)模式的框架宪睹。
Spring IoC
Spring IoC實(shí)現(xiàn)了IoC設(shè)計(jì)模式愁茁,所以是IoC容器。所以横堡,Spring IoC主要任務(wù)就是創(chuàng)建并且管理JavaBean的生命周期埋市,即之前提到的對(duì)象的控制權(quán)冠桃。
那么對(duì)于Spring而言命贴,JavaBean的生命周期包括哪些方面呢?這是我們需要了解的問(wèn)題食听。
Spring IoC的JavaBean的生命周期
(1)實(shí)例化JavaBean:Spring IoC容器實(shí)例化JavaBean
(2)初始化JavaBean:Spring IoC容器對(duì)JavaBean通過(guò)注入依賴進(jìn)行初始化
(3)使用JavaBean:基于Spring應(yīng)用對(duì)JavaBean實(shí)例的使用
(4)銷毀JavaBean:Spring IoC容器銷毀JavaBean實(shí)例
舉個(gè)例子
我們來(lái)看一個(gè)Spring IoC的例子胸蛛。
編寫(xiě)一個(gè)動(dòng)物接口,代碼如下:
package com.demo;
public interface Animal {
void printWhoAmI();
}
編寫(xiě)一個(gè)老虎類實(shí)現(xiàn)動(dòng)物接口樱报,代碼如下:
package com.demo;
public class Tiger implements Animal {
private String name;
private int age;
//省略屬性的set和get方法
@Override
public void printWhoAmI() {
// TODO Auto-generated method stub
System.out.println("I am " + name);
System.out.println("I am " + age + " years old");
}
}
編寫(xiě)Spring配置文件applicationContext.xml葬项,代碼如下:
<?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:p="http://www.springframework.org/schema/p" xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans-3.0.xsd">
<bean id="tiger" class="com.demo.Tiger">
<property name="name">
<value>Tom</value>
</property>
<property name="age">
<value>3</value>
</property>
</bean>
</beans>
編寫(xiě)主測(cè)試類,代碼如下:
package com.demo;
public class Test {
public static void main(String[] args) {
Resource resource = new ClassPathResource("applicationContext.xml");
BeanFactory beanFactory = new XmlBeanFactory(resource);
Animal tiger = (Tiger) beanFactory.getBean("tiger"); // 獲取Tiger類對(duì)象tiger
tiger.printWhoAmI();
}
}
我們可以發(fā)現(xiàn)Spring通過(guò)配置文件完成了Tiger類對(duì)象tiger申請(qǐng)和初始化迹蛤,我們?cè)谑褂肨iger類對(duì)象tiger時(shí)不再通過(guò)
// 創(chuàng)建Tiger類對(duì)象tiger
Animal tiger = new Tiger();
// Tiger類對(duì)象tiger初始化
tiger.setName("Tom");
tiger.setAge(3);
這種方式民珍,而是將所有的JavaBean的生命周期操作和管理托管至Spring IoC容器,對(duì)于開(kāi)發(fā)者而言盗飒,我們只需要關(guān)心業(yè)務(wù)邏輯需要怎樣的JavaBean對(duì)象嚷量,告訴容器,使用即可逆趣,這里再次體現(xiàn)了所謂的控制反轉(zhuǎn)的思想蝶溶。
依賴注入
我們可能會(huì)遇見(jiàn)這樣的情況,Spring IoC容器管理的對(duì)象中可能會(huì)依賴其他對(duì)象宣渗,這是很常見(jiàn)的抖所。這就意味著Spring IoC的一個(gè)重點(diǎn)是在系統(tǒng)運(yùn)行中,動(dòng)態(tài)的向某個(gè)對(duì)象提供它所需要的其他對(duì)象痕囱。這也是我們接下來(lái)要了解的依賴注入田轧。
接著上述例子我們來(lái)看一下依賴注入的情況:
編寫(xiě)一個(gè)籠子接口,代碼如下:
package com.demo;
public interface Cage {
void printInfo();
}
編寫(xiě)一個(gè)鐵籠子類實(shí)現(xiàn)籠子接口鞍恢,并且具有一個(gè)動(dòng)物類型的屬性傻粘,代碼如下:
package com.demo;
public class IronCage implements Cage {
private String id;
private Animal animal;
//省略屬性的set和get方法
@Override
public void printInfo() {
// TODO Auto-generated method stub
System.out.println("I am a IronCage");
System.out.println("My id is " + id);
System.out.println("There is the animal information");
animal.printWhoAmI();
}
}
將Spring配置文件applicationContext.xml改寫(xiě)如下:
<?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:p="http://www.springframework.org/schema/p" xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans-3.0.xsd">
<bean id="tiger" class="com.demo.Tiger">
<property name="name">
<value>Tom</value>
</property>
<property name="age">
<value>3</value>
</property>
</bean>
<bean id="ironCage" class="com.demo.IronCage">
<property name="id">
<value>001</value>
</property>
<property name="animal">
<ref bean="tiger" />
</property>
</bean>
</beans>
IronCage類對(duì)象ironCage中依賴Animal類型的animal屬性,Spring IoC容器將Tiger類tiger對(duì)象注入作為animal的值有序,這就是依賴注入抹腿。
這里提一下,Spring支持多種屬性賦值的情況旭寿,例如list警绩、map:
<bean id="school" class="School">
<!--1.value 普通賦值-->
<property name="name">
<value>XX學(xué)校</value>
</property>
<!--2.ref 引用其他JavaBean實(shí)例對(duì)象賦值-->
<property name="student">
<ref bean="student1" />
</property>
<!--3.list 集合類或者數(shù)組賦值-->
<property name="studentList">
<list>
<ref bean="student1" />
<value>student2</value>
</list>
</property>
<!--4.map Map集合賦值-->
<property name="studentMap">
<map>
<entry key="student1">
<ref bean="student1" />
</entry>
<entry key="key2">
<value>student2</value>
</entry>
</map>
</property>
</bean>
Spring 如何實(shí)現(xiàn)IoC?
了解了Spring IoC的強(qiáng)大功能之后盅称,我們可能都會(huì)好奇Spring究竟是如何做到這樣肩祥?
Java一個(gè)很重要的特性就是支持反射(reflection)機(jī)制后室,它允許程序在運(yùn)行的時(shí)候動(dòng)態(tài)的生成對(duì)象、執(zhí)行對(duì)象的方法混狠、改變對(duì)象的屬性岸霹,Spring就是通過(guò)反射來(lái)實(shí)現(xiàn)注入的。
簡(jiǎn)單的說(shuō)将饺,Spring首先會(huì)根據(jù)bean的XML配置文件贡避,將一個(gè)bean的配置讀入以HashMap的數(shù)據(jù)結(jié)構(gòu)存儲(chǔ),在實(shí)例化一個(gè)類時(shí)予弧,它通過(guò)反射調(diào)用類中set方法將事先保存在HashMap中的類屬性注入到類中刮吧。
這里強(qiáng)烈建議大家看一篇文章,對(duì)于Spring IoC的原理解釋的很清楚掖蛤。 spring ioc原理(看完后大家可以自己寫(xiě)一個(gè)spring)
BeanFactory和ApplicationContext
Spring使用BeanFactory和ApplicationContext兩個(gè)接口來(lái)定義IoC杀捻,它們是Spring針對(duì)不同應(yīng)用領(lǐng)域的兩個(gè)IoC容器。
首先它們兩者的關(guān)系是蚓庭,ApplicationContext繼承BeanFactory致讥。
BeanFactory處于Spring的核心,所以可以理解為Spring統(tǒng)一使用BeanFactory訪問(wèn)Spring IoC容器器赞,主要用于開(kāi)發(fā)Java應(yīng)用垢袱,尤其是在物理資源(內(nèi)存有限)受限的場(chǎng)合,這是因?yàn)?strong>在調(diào)用getBean()方法之前不會(huì)實(shí)例化任何對(duì)象拳魁,只有在需要?jiǎng)?chuàng)建JavaBean實(shí)例對(duì)象時(shí)惶桐,才會(huì)為其分配資源空間。
ApplicationContext在繼承BeanFactory基礎(chǔ)上增加了很多其他功能潘懊,如國(guó)際化支持姚糊、事件發(fā)布和監(jiān)聽(tīng)等,非常適合J2EE的開(kāi)發(fā)授舟。
總結(jié)
對(duì)spring的反轉(zhuǎn)控制有一定的理解了救恨,但是還有很多不清楚的地方。
感謝
感謝Wwwwei作者的文章释树,長(zhǎng)話短說(shuō)Spring(1)之IoC控制反轉(zhuǎn)對(duì)我有很大的啟發(fā)肠槽。