Spring Ioc容器

什么是Ioc?

控制反轉(zhuǎn)((Inversion of Control惯驼,英文縮寫為IoC)把創(chuàng)建對象的權(quán)利交給框架,是框架的重要特征论笔,并非面向?qū)ο缶幊痰膶S眯g(shù)語徘意。它包括依賴注入(Dependency Injection汁雷,簡稱DI和依賴查找(Dependency Lookup)净嘀。

說得簡單一點(diǎn)就是我們在寫Java代碼的時候我們的對象不需要自己來創(chuàng)建,而是通過容器來幫助我們生成侠讯。用我們生活中的例子來說挖藏,打個比方,我們想要一輛汽車厢漩,我們不可能去自己造一輛汽車膜眠,而是去買一輛。

所有的類都會在spring容器中登記袁翁,告訴spring你是個什么東西柴底,你需要什么東西,然后spring會在系統(tǒng)運(yùn)行到適當(dāng)?shù)臅r候粱胜,把你要的東西主動給你,同時也把你交給其他需要你的東西狐树。所有的類的創(chuàng)建焙压、銷毀都由 spring來控制,也就是說控制對象生存周期的不再是引用它的對象抑钟,而是spring涯曲。對于某個具體的對象而言,以前是它控制其他對象在塔,現(xiàn)在是所有對象都被spring控制幻件,所以這叫控制反轉(zhuǎn)。

Ioc容器的初始化

image.png
IoC容器初始化過程主要經(jīng)過以下幾個階段:
1.解析階段:Spring會解析Bean的XML配置文件蛔溃,將XML元素進(jìn)行抽象绰沥,抽象成Resource對象篱蝇。
2.轉(zhuǎn)換階段:通過Resource對象將配置文件進(jìn)行抽象后轉(zhuǎn)換成Spring能夠理解的BeanDefinition結(jié)構(gòu)。
3.注冊階段:Spring IoC容器的實(shí)現(xiàn)徽曲,從根源上是beanfactory零截,但真正可以作為一個可以獨(dú)立使用的ioc容器還是DefaultListableBeanFactory。
DefaultListableBeanFactory間接實(shí)現(xiàn)了BeanFactory接口秃臣,是整個bean加載的核心部分涧衙,是Spring注冊及加載bean的默認(rèn)實(shí)現(xiàn),我們可以理解為Spring bean工廠的發(fā)動機(jī)奥此。

Spring Bean 定義

被稱作 bean 的對象是構(gòu)成應(yīng)用程序的支柱也是由 Spring IoC 容器管理的弧哎。bean 是一個被實(shí)例化,組裝稚虎,并通過 Spring IoC 容器所管理的對象撤嫩。這些 bean 是由用容器提供的配置元數(shù)據(jù)創(chuàng)建的。

屬性 描述
class 這個屬性是強(qiáng)制性的祥绞,并且指定用來創(chuàng)建 bean 的 bean 類非洲。
name 這個屬性指定唯一的 bean 標(biāo)識符。在基于 XML 的配置元數(shù)據(jù)中蜕径,你可以使用 ID 和/或 name 屬性來指定 bean 標(biāo)識符两踏。
scope 這個屬性指定由特定的 bean 定義創(chuàng)建的對象的作用域,它將會在 bean 作用域的章節(jié)中進(jìn)行討論兜喻。
lazy-initialization mode 延遲初始化的 bean 告訴 IoC 容器在它第一次被請求時梦染,而不是在啟動時去創(chuàng)建一個 bean 實(shí)例。
initialization 在 bean 的所有必需的屬性被容器設(shè)置之后朴皆,調(diào)用回調(diào)方法
destruction 當(dāng)包含該 bean 的容器被銷毀時帕识,使用回調(diào)方法

Spring Bean作用域

當(dāng)在 Spring 中定義一個 bean 時,你必須聲明該 bean 的作用域的選項(xiàng)遂铡。例如肮疗,為了強(qiáng)制 Spring 在每次需要時都產(chǎn)生一個新的 bean 實(shí)例,你應(yīng)該聲明 bean 的作用域的屬性為prototype扒接。同理伪货,如果你想讓 Spring 在每次需要時都返回同一個bean實(shí)例,你應(yīng)該聲明 bean 的作用域的屬性為singleton钾怔。

Spring框架支持以下五個作用域:

作用域 描述
singleton 該作用域?qū)?bean 的定義的限制在每一個 Spring IoC 容器中的一個單一實(shí)例(默認(rèn))碱呼。
prototype 該作用域?qū)我?bean 的定義限制在任意數(shù)量的對象實(shí)例。
request 該作用域?qū)?bean 的定義限制為 HTTP 請求宗侦。只在 web-aware Spring ApplicationContext 的上下文中有效愚臀。
session 該作用域?qū)?bean 的定義限制為 HTTP 會話。 只在web-aware Spring ApplicationContext的上下文中有效矾利。
global-session 該作用域?qū)?bean 的定義限制為全局 HTTP 會話姑裂。只在 web-aware Spring ApplicationContext 的上下文中有效馋袜。

看下面的例子:第一個是singleton,第二個是prototype炭分。

Hello.java

package com.tutorialspoint;

public class Hello {
    private String message;
    public void setMessage(String message) {
        this.message = message;
    }
    public void getMessage() {
        System.out.println("Your message is:" + message);
    }
}

MainApp.java

package com.tutorialspoint;
import org.springframework.context.support.AbstractApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;

public class MainApp {

    public static void main(String[] args) {
        AbstractApplicationContext context = new ClassPathXmlApplicationContext("Beans.xml");
        Hello object1 = (Hello) context.getBean("bean");
        object1.setMessage("這不大傻瓜嗎");
        object1.getMessage();
        Hello object2 = (Hello) context.getBean("bean");
        object2.getMessage();
    }

}

Beans.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"
    xsi:schemaLocation="http://www.springframework.org/schema/beans
    http://www.springframework.org/schema/beans/spring-beans-3.0.xsd">

   <bean id="bean" class="com.tutorialspoint.Hello" scope="singleton">
   </bean>
</beans>

輸出的結(jié)果為如圖:

image.png

Beans.xml中的scope="singleton"改為scope="prototype"后桃焕,其余代碼不變,輸出結(jié)果可以猜到了捧毛,第二個Bean將不會得到實(shí)例化观堂,因此輸出的值為空即null

結(jié)果正確:

image.png

Spring Bean的生命周期

Spring的生命周期跟Servlet的生命周期像呀忧,都有初始化跟銷毀的方法师痕,參數(shù)分別為:init-mehtoddestroy-methodinit-method屬性指定一個方法而账,在實(shí)例化 bean 時胰坟,立即調(diào)用該方法。同樣泞辐,destroy-method指定一個方法笔横,只有從容器中移除 bean 之后,才能調(diào)用該方法咐吼。

Hello.java

package com.tutorialspoint;

public class Hello {
    private String message;
    public void setMessage(String message) {
        this.message = message;
    }
    public void getMessage() {
        System.out.println("Your message is:" + message);
    }
    public void init() {
        System.out.println("bean正在被初始化");
    }
    public void destroy() {
        System.out.println("bean正在被銷毀");
    }
}

MainApp.java

package com.tutorialspoint;
import org.springframework.context.support.AbstractApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;

public class MainApp {

    public static void main(String[] args) {
        AbstractApplicationContext context = new ClassPathXmlApplicationContext("Beans.xml");
        Hello object1 = (Hello) context.getBean("bean");
        object1.setMessage("這不大傻瓜嗎");
        object1.getMessage();
        //在非web應(yīng)用中關(guān)閉Ioc容器
        context.registerShutdownHook();
    }

}

Beans.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"
    xsi:schemaLocation="http://www.springframework.org/schema/beans
    http://www.springframework.org/schema/beans/spring-beans-3.0.xsd">

   <bean id="bean" class="com.tutorialspoint.Hello" init-method="init" destroy-method="destroy">
   </bean>
</beans>
image.png

這是關(guān)于registryShutdownHook()的詳細(xì)解釋吹缔。

Spring Bean定義繼承

bean 定義可以包含很多的配置信息,包括構(gòu)造函數(shù)的參數(shù)锯茄,屬性值厢塘,容器的具體信息例如初始化方法,靜態(tài)工廠方法名肌幽,等等晚碾。子 bean 的定義繼承父定義的配置數(shù)據(jù)。子定義可以根據(jù)需要重寫一些值喂急,或者添加其他值格嘁。Spring Bean 定義的繼承與 Java 類的繼承無關(guān),但是繼承的概念是一樣的廊移。你可以定義一個父 bean 的定義作為模板和其他子 bean 就可以從父 bean 中繼承所需的配置讥蔽。當(dāng)你使用基于 XML 的配置元數(shù)據(jù)時,通過使用父屬性画机,指定父 bean 作為該屬性的值來表明子 bean 的定義。

看例子:

Hello.java

package com.tutorialspoint;

public class Hello {
    private String message1;
    private String message2;
    public void setMessage1(String message) {
        this.message1 = message;
    }
    public void getMessage1() {
        System.out.println("Your message is:" + message1);
    }
    public void setMessage2(String message) {
        this.message2 = message;
    }
    public void getMessage2() {
        System.out.println("Your message is:" + message2);
    }
}

HelloWorld.java

package com.tutorialspoint;

public class HelloWorld {
    private String message1;
    private String message2;
    private String message3;
    public void setMessage1(String message){
          this.message1  = message;
       }

       public void setMessage2(String message){
          this.message2  = message;
       }

       public void setMessage3(String message){
          this.message3  = message;
       }

       public void getMessage1(){
          System.out.println("Your message is: " + message1);
       }

       public void getMessage2(){
          System.out.println("Your message is:" + message2);
       }

       public void getMessage3(){
          System.out.println("Your message is: " + message3);
       }
}

MainApp.java

package com.tutorialspoint;
import org.springframework.context.support.AbstractApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;

public class MainApp {

    public static void main(String[] args) {
        AbstractApplicationContext context = new ClassPathXmlApplicationContext("Beans.xml");
        Hello obj1 = (Hello) context.getBean("hello");
        obj1.getMessage1();
        obj1.getMessage2();
        HelloWorld obj2 = (HelloWorld) context.getBean("helloworld");
        obj2.getMessage1();
        obj2.getMessage2();
        obj2.getMessage3();
    }
}

Beans.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"
    xsi:schemaLocation="http://www.springframework.org/schema/beans
    http://www.springframework.org/schema/beans/spring-beans-3.0.xsd">

   <bean id="hello" class="com.tutorialspoint.Hello">
        <property name="message1" value="message1" />
        <property name="message2" value="message2" />
   </bean>
   <bean id="helloworld" class="com.tutorialspoint.HelloWorld" parent="hello">
        <property name="message1" value="helloworld1" />
        <property name="message3" value="helloworld2"/>
   </bean>
</beans>

輸出結(jié)果如下:

image.png

可以看出新症,我們在HelloWorld.java中并未定義有getMessage2()的方法步氏,但是在主類中我們調(diào)用了該方法,因此Bean就繼承了主類的該方法徒爹,所以子類調(diào)用的是父類的方法荚醒,輸出跟父類的結(jié)果一致芋类。

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市界阁,隨后出現(xiàn)的幾起案子侯繁,更是在濱河造成了極大的恐慌,老刑警劉巖泡躯,帶你破解...
    沈念sama閱讀 211,561評論 6 492
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件贮竟,死亡現(xiàn)場離奇詭異,居然都是意外死亡较剃,警方通過查閱死者的電腦和手機(jī)咕别,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 90,218評論 3 385
  • 文/潘曉璐 我一進(jìn)店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來写穴,“玉大人惰拱,你說我怎么就攤上這事“∷停” “怎么了偿短?”我有些...
    開封第一講書人閱讀 157,162評論 0 348
  • 文/不壞的土叔 我叫張陵,是天一觀的道長馋没。 經(jīng)常有香客問我昔逗,道長,這世上最難降的妖魔是什么披泪? 我笑而不...
    開封第一講書人閱讀 56,470評論 1 283
  • 正文 為了忘掉前任纤子,我火速辦了婚禮,結(jié)果婚禮上款票,老公的妹妹穿的比我還像新娘控硼。我一直安慰自己,他們只是感情好艾少,可當(dāng)我...
    茶點(diǎn)故事閱讀 65,550評論 6 385
  • 文/花漫 我一把揭開白布卡乾。 她就那樣靜靜地躺著,像睡著了一般缚够。 火紅的嫁衣襯著肌膚如雪幔妨。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 49,806評論 1 290
  • 那天谍椅,我揣著相機(jī)與錄音误堡,去河邊找鬼。 笑死雏吭,一個胖子當(dāng)著我的面吹牛锁施,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播,決...
    沈念sama閱讀 38,951評論 3 407
  • 文/蒼蘭香墨 我猛地睜開眼悉抵,長吁一口氣:“原來是場噩夢啊……” “哼肩狂!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起姥饰,我...
    開封第一講書人閱讀 37,712評論 0 266
  • 序言:老撾萬榮一對情侶失蹤傻谁,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后列粪,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體审磁,經(jīng)...
    沈念sama閱讀 44,166評論 1 303
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 36,510評論 2 327
  • 正文 我和宋清朗相戀三年篱竭,在試婚紗的時候發(fā)現(xiàn)自己被綠了力图。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點(diǎn)故事閱讀 38,643評論 1 340
  • 序言:一個原本活蹦亂跳的男人離奇死亡掺逼,死狀恐怖吃媒,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情吕喘,我是刑警寧澤赘那,帶...
    沈念sama閱讀 34,306評論 4 330
  • 正文 年R本政府宣布,位于F島的核電站氯质,受9級特大地震影響募舟,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜闻察,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 39,930評論 3 313
  • 文/蒙蒙 一拱礁、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧辕漂,春花似錦呢灶、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,745評論 0 21
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至跋涣,卻和暖如春缨睡,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背陈辱。 一陣腳步聲響...
    開封第一講書人閱讀 31,983評論 1 266
  • 我被黑心中介騙來泰國打工奖年, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留,地道東北人沛贪。 一個月前我還...
    沈念sama閱讀 46,351評論 2 360
  • 正文 我出身青樓拾并,卻偏偏與公主長得像揍堰,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子嗅义,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 43,509評論 2 348

推薦閱讀更多精彩內(nèi)容

  • Spring Cloud為開發(fā)人員提供了快速構(gòu)建分布式系統(tǒng)中一些常見模式的工具(例如配置管理,服務(wù)發(fā)現(xiàn)隐砸,斷路器之碗,智...
    卡卡羅2017閱讀 134,633評論 18 139
  • Spring Boot 參考指南 介紹 轉(zhuǎn)載自:https://www.gitbook.com/book/qbgb...
    毛宇鵬閱讀 46,773評論 6 342
  • 文章作者:Tyan博客:noahsnail.com 3.4 Dependencies A typical ente...
    SnailTyan閱讀 4,133評論 2 7
  • 讀完《百年孤獨(dú)》,有一種失戀的感覺季希,不褪那,是與世訣別的哀傷,如同在馬恭多小鎮(zhèn)上活了一百多年式塌,最后在颶風(fēng)里和小鎮(zhèn)一起消...
    常吉清才閱讀 460評論 0 1
  • 問題: 這里發(fā)布的東西是不公開的嗎博敬? 這里發(fā)布的東西是不公開的嗎?
    蓋世武俠閱讀 123評論 0 0