BeanFactory和ApplicationContext

??通過一個配置文件描述Bean及Bean之間的依賴關(guān)系王滤,利用Java語言的反射功能實例化Bean并建立Bean之間的依賴關(guān)系敛苇。Sping的IoC容器在完成這些底層工作的基礎(chǔ)上,還提供了Bean實例緩存抄邀,生命周期管理暗赶,Bean實例代理,事件發(fā)布,資源裝載等高級服務(wù)夯辖。
??Bean工廠(com.springframework.beans.factory.BeanFactory)是Spring框架最核心的接口琉预,它提供了高級IoC的配置機制。BeanFactory使管理不同類型的Java對象成為可能蒿褂,應(yīng)用上下文(com.springframework.context.ApplicationContext)建立在BeanFactory基礎(chǔ)之上娩井,提供了更多面向應(yīng)用的功能毕泌,它提供了國際化支持和框架事件體系激率,更易于創(chuàng)建實際應(yīng)用。我們一般稱BeanFactory為IoC容器也祠,而稱ApplicationContext為應(yīng)用上下文。但有時為了行文方便近速。

我們可以進行簡單劃分:
BeanFactory是Sping框架的基礎(chǔ)設(shè)施诈嘿,而面向sping本身;ApplicationContext面向使用Sping框架的開發(fā)者削葱,幾乎所有的應(yīng)用場合我們都是直接使用ApplicationContet而非底層的BeanFactory奖亚。

BeanFactory介紹

??誠如其名,BeanFactory是一個類工廠析砸,但和傳統(tǒng)的類工廠不同昔字,傳統(tǒng)的類工廠僅負責(zé)構(gòu)造一個或幾個類的實例。而BeanFactory是類的通用工廠首繁,它可以創(chuàng)建并管理各種類的對象作郭。這些可被創(chuàng)建和管理的對象本身沒有什么特別之處,僅是一個POJO弦疮。Sping稱這些被創(chuàng)建和管理的Java對象為Bean夹攒。我們知道JavaBean是要滿足一定規(guī)范的,如必須提供一個默認不帶參的構(gòu)造函數(shù)挂捅,不依賴于某一特定的容器等芹助,但Spring中所說的Bean比JavaBean更寬泛一些,所有可以被Sping容器實例化并管理的Java類都可以成為Bean闲先。

BeanFactory的類體系結(jié)構(gòu)

??Spring為BeanFactory提供了多種實現(xiàn)状土,最常用的是XmlBeanFactory。XmlBeanFactory的類繼承體系設(shè)計優(yōu)雅伺糠,堪稱經(jīng)典蒙谓。通過繼承體系,我們可以很容易了解到XmlBeanFactory具有哪些功能:
BeanFactory的類體系結(jié)構(gòu)

??BeanFactory接口位于類結(jié)構(gòu)樹的頂端训桶,它最主要的方法就是getBean(String beanName),該方法從容器中返回特定名稱的Bean,BeanFactory的功能通過其他的接口得到不斷擴展累驮。下面對上圖涉及到的其他接口分別進行說明。

  • ListableBeanFactory:該接口定義了訪問容器中Bean基本信息的若干方法舵揭,如查看Bean的個數(shù)谤专,獲取某一個類型Bean的配置名,查看容器中是否包括某一Bean等方法午绳;
  • HierarchicalBeanFactory:父子級聯(lián)IoC容器的接口置侍,子容器可以通過接口方法訪問父容器;
  • ConfigurableBeanFactory:是一個重要的接口,增強了IoC容器的可定制性蜡坊,它定義了設(shè)置類裝載器杠输,屬性編輯器,容器初始化后置處理器等方法秕衙;
  • AutowireCapableBeanFactory;

初始化BeanFactory
??下面蠢甲,我們使用sping配置文件為Car提供配置信息,然后通過BeanFactory裝在配置文件据忘,啟動sping IoC容器鹦牛。sping配置文件如下:

<?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="car" class="com.hhxs.bbt.web.Car"
        p:brand="紅旗CA72"
        p:color="黑色"
        p:maxSpeed="200" />
</beans>

下面我們通過XmlBeanFactory實現(xiàn)類啟動sping IoC容器:

public class BeanFactoryTest {
    public static void main(String[] args) throws Throwable{
       ResourcePatternResolver resolver = new PathMatchingResourcePatternResolver();
       Resource res = resolver.getResource("classpath:spring/beans.xml");
       System.out.println(res.getURL());
       BeanFactory bf = new XmlBeanFactory(res);
       System.out.println("init BeanFactory.");

       Car car = bf.getBean("car",Car.class);
       System.out.println("car bean is ready for use!");
       car.introduce();
    }
}

??XmlBeanFactory通過Resource裝裝載sping配置信息并啟動IoC容器,然后就可以通過BeanFactory#getBean(beanName)方法從IoC容器中獲取Bean了若河。通過BeanFactory啟動IoC容器時能岩,并不會初始化配置文件中定義的Bean,初始化動作發(fā)生在第一個調(diào)用時萧福。對于單實例(singleton)的Bean來說拉鹃,BeanFactory會緩存Bean實例,所以第二次使用getBean()獲取Bean時將直接從IoC容器的緩存中獲取Bean實例鲫忍。
??sping在DefaultSingletonBeanRegistry類中提供了一個用于緩存單實例Bean的緩存器膏燕,它是一個用HashMap實現(xiàn)的緩存器,單實例的Bean以beanName為鍵保存在這個HashMap中悟民。
??值得一提的是坝辫,在初始化BeanFactory時,必須為其提供一種日志框架射亏,我們使用Log4J,即在類路徑下提供Log4J配置文件近忙,這樣啟動Sping容器才不會報錯。

ApplicationContext介紹

??如果說BeanFactory是Sping的心臟智润,那么ApplicationContext就是完整的身軀了及舍。ApplicationContext由BeanFactory派生而來,提供了更多面向?qū)嶋H應(yīng)用的功能窟绷。在Beanfactory中锯玛,很多功能需要以編程的方式實現(xiàn),而在ApplicationContext中則可以通過配置的方式實現(xiàn)兼蜈。

ApplicationContext類體系結(jié)構(gòu)
??ApplicationContext的主要實現(xiàn)類是ClassPathXmlApplicationContext和FileSystemXmlApplicationContext攘残,前者默認從類路徑加載配置文件,后者默認從文件系統(tǒng)中裝載配置文件为狸,我們了解一下ApplicationContext的類繼承體系:

ApplicationContext體系結(jié)構(gòu)及與BeanFactory的關(guān)系

??從上圖中我們可以看出ApplicationContext繼承了hierarchicalBeanFactory和ListableBeanFactory接口歼郭,在此基礎(chǔ)上,還通過多個其他的接口擴展了BeanFactory的功能辐棒,這些接口包括:

  • ApplicationEventPublisher:讓容器擁有發(fā)布應(yīng)用上下文事件的功能病曾,包括容器啟動事件姊途,關(guān)閉事件等。實現(xiàn)了ApplicationListener事件監(jiān)聽接口的Bean可以接收到容器事件知态,并對事件進行響應(yīng)處理。在ApplicationContext抽象實現(xiàn)類AbstractApplicationContext中立叛,我們可以發(fā)現(xiàn)存在一個ApplicationEventMulticaster负敏,它負責(zé)保存所有監(jiān)聽器,以便在容器產(chǎn)生上下文事件時通知這些事件監(jiān)聽者秘蛇。
  • MessageSource:為應(yīng)用提供i18n國際化消息訪問的功能其做;
  • ResourcePatternResolver:所有ApplicationContext實現(xiàn)類都實現(xiàn)了類似于PathMatchingResourcePatternResolver的功能,可以通過帶前綴的Ant風(fēng)格的資源文件路徑裝載sping的配置文件赁还。
  • LifeCycle:該接口是Sping2.0加入的妖泄,該接口提供了start()和stop()兩個方法,主要用于控制異步處理過程艘策。在具體使用時蹈胡,ApplicationContext及具體的Bean都必須同時該接口,ApplicationContext會將start/stop的信息傳遞給容器中所有實現(xiàn)了該接口的Bean朋蔫,已達到管理和控制JMX,任務(wù)調(diào)度等目的罚渐。

??在獲取ApplicationContext實例后,就可以像BeanFactory一樣調(diào)用getBean(beanName)返回Bean了驯妄。ApplicationContext的初始化和BeanFactory有一個重大的區(qū)別:BeanFactory在初始化容器時荷并,并未實例化Bean,直到第一次訪問某個Bean時才實例化目標Bean;而ApplicationContext則在初始化應(yīng)用上下文時就實例化所有單實例的Bean青扔。因此ApplicationContext的初始化時間會比BeanFactory稍長一些源织,不過稍后的調(diào)用則沒有“第一次懲罰”問題。

??spring3.0支持基于類注解的配置方式微猖,主要功能來自于sping的名為JavaConfig子項目谈息,目前JavaConfig已經(jīng)升級為spring核心框架的一部分。一個標注@Configuration注解的POJO即可提供sping所需的Bean配置信息:

package com.yeren;

public class Car {
    private String brand;
    private String color;
    private int maxSpeed;

    public Car(){}

    public Car(String brand,String color,int maxSpeed){
        this.brand=brand;
        this.color=color;
        this.maxSpeed=maxSpeed;
    }

    public String getBrand() {
        return brand;
    }

    public void setBrand(String brand) {
        this.brand = brand;
    }

    public String getColor() {
        return color;
    }

    public void setColor(String color) {
        this.color = color;
    }

    public int getMaxSpeed() {
        return maxSpeed;
    }

    public void setMaxSpeed(int maxSpeed) {
        this.maxSpeed = maxSpeed;
    }

    public void introduce(){
        System.out.println("brand:"+brand+";color:"+color+";maxSpeed:"+maxSpeed);
    }
}

package com.yeren;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import java.awt.*;

@Configuration
public class BeanA {
    @Bean(name="car")
    public Car buildCar(){
        Car car=new Car();
        car.setBrand("紅旗CA72");
        car.setMaxSpeed(200);
        return car;
    }
}

package com.yeren;


import org.springframework.context.ApplicationContext;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;
import org.springframework.core.io.Resource;
import org.springframework.core.io.support.PathMatchingResourcePatternResolver;
import org.springframework.core.io.support.ResourcePatternResolver;

/**
 * Hello world!
 *
 */
public class App 
{
    public static void main(String []args)throws Throwable{
        ApplicationContext ctx=new AnnotationConfigApplicationContext(BeanA.class);
        Car car=ctx.getBean("car",Car.class);
        System.out.println();
    }
}

??和基于XML文件配置方式的優(yōu)勢在于励两,類注解的配置方式可以很容易地讓開發(fā)者控制Bean的初始化過程黎茎,比基于XML的配置更加靈活。sping為基于注解類的配置提供了專門的ApplicationContext實現(xiàn)類:AnnotationConfigApplicationContext当悔。

WebApplicationContext類體系結(jié)構(gòu)

WebApplicationContext類體系結(jié)構(gòu)與BeanFactory和ApplicationContext的關(guān)系

WebApplicationContext是專門為Web應(yīng)用準備的傅瞻,它允許從相對于Web根目錄的路徑中裝載配置文件完成初始化工作。從WebApplicationContext中可以獲得ServletContextde引用盲憎,整個Web應(yīng)用上下文對象將作為屬性放置到ServletContext中嗅骄,以便Web應(yīng)用環(huán)境可以訪問Sping應(yīng)用上下文。sping專門為此提供一個工具類WebApplicationContextUtils饼疙,通過該類的getWebApplicationContext(ServletContext sc)方法溺森,即可以從ServletContext中獲取WebApplicationContext實例慕爬。
??由于Web應(yīng)用比一般的應(yīng)用擁有更多的特性,因此WebApplicationContext擴展了ApplicationContext屏积。WebApplicationContext定義了一個常量ROOT_WEB_APPLICATION_CONTEXT_ATTRIBUTE,在上下文啟動時医窿,WebApplicationContext實例即以此為鍵放置在ServletContext的屬性列表中,因此我們可以直接通過以下話語從Web容器中獲取WebApplicationContext:

WebApplicationContext wac=(WebApplicationContext)servletContext.getAttribute(ROOT_WEB_APPLICATION_CONTEXT_ATTRIBUTE);

這正是我們前面提到的WebApplicationContextUtils工具類getWebApplicationContext(ServletContext sc)方法的內(nèi)部實現(xiàn)方式炊林。這樣sping的web應(yīng)用上下文和web容器的上下文就可以實現(xiàn)互訪姥卢,二者實現(xiàn)了融合:

sping和Web應(yīng)用的上下文融合

??ConfigurableWebApplicationContext擴展了WebApplicationContext,它允許通過配置的方式實例化WebaApplicationContext渣聚,它定義了兩個重要的方法:

  • setServletContext(ServletContext servletContext):為sping設(shè)置web應(yīng)用上下文独榴,以便兩者整合;
  • setConfigLocations(String[] configLocations):設(shè)置sping配置文件地址奕枝,一般情況下棺榔,配置文件地址是相對于web根目錄的地址,如/WEB-INF/baobaotao-dao.xml,/WEB-INF/baobaotao-service.xml等隘道。但用戶也可以使用帶資源類型前綴的地址症歇,如classpath:com/baobaotao/beans.xml等。
    WebApplicationContext初始化
    ??WebApplicationContext的初始化方式和BeanFactory薄声,ApplicationContext有所區(qū)別当船,因為WebApplicationContext需要Servlet或定義Web容器監(jiān)聽器(ServletContextListener),借助這兩者中的任何一個,我們就可以完成啟動sping web應(yīng)用上下文的工作默辨。
    ??sping分別提供了用于啟動WebApplicationContext的Servlet和Web容器監(jiān)聽器:
  • org.spingframework.web.context.ContextLoaderServlet;
  • org.spingframework.web.context.ContextLoaderListener德频。
    ??兩者的內(nèi)部都實現(xiàn)了啟動WebApplicationContext實例的邏輯,我們只要根據(jù)Web容器的具體情況選擇兩者之一缩幸,并在web.xml中完成配置就可以了壹置。

父子容器
??通過HierarchicalBeanFactory接口,sping的IoC容器可以建立父子層級關(guān)聯(lián)的容器體系表谊,子容器可以訪問父容器中的Bean钞护,但父容器不能訪問子容器的Bean。在容器內(nèi)爆办,Bean的id必須是唯一的难咕,但子容器可以擁有一個和父容器id相同的Bean。父子容器層級體系增強了sping容器架構(gòu)的擴展性和靈活性距辆,因為第三方可以通過編程的方式余佃,為一個已經(jīng)存在的容器添加一個或多個特殊用途的子容器,以提供一些額外的功能跨算。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末爆土,一起剝皮案震驚了整個濱河市,隨后出現(xiàn)的幾起案子诸蚕,更是在濱河造成了極大的恐慌步势,老刑警劉巖氧猬,帶你破解...
    沈念sama閱讀 206,126評論 6 481
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場離奇詭異坏瘩,居然都是意外死亡盅抚,警方通過查閱死者的電腦和手機,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 88,254評論 2 382
  • 文/潘曉璐 我一進店門倔矾,熙熙樓的掌柜王于貴愁眉苦臉地迎上來泉哈,“玉大人,你說我怎么就攤上這事破讨。” “怎么了奕纫?”我有些...
    開封第一講書人閱讀 152,445評論 0 341
  • 文/不壞的土叔 我叫張陵提陶,是天一觀的道長。 經(jīng)常有香客問我匹层,道長隙笆,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 55,185評論 1 278
  • 正文 為了忘掉前任升筏,我火速辦了婚禮撑柔,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘您访。我一直安慰自己铅忿,他們只是感情好,可當(dāng)我...
    茶點故事閱讀 64,178評論 5 371
  • 文/花漫 我一把揭開白布灵汪。 她就那樣靜靜地躺著檀训,像睡著了一般。 火紅的嫁衣襯著肌膚如雪享言。 梳的紋絲不亂的頭發(fā)上峻凫,一...
    開封第一講書人閱讀 48,970評論 1 284
  • 那天,我揣著相機與錄音览露,去河邊找鬼荧琼。 笑死,一個胖子當(dāng)著我的面吹牛差牛,可吹牛的內(nèi)容都是我干的命锄。 我是一名探鬼主播,決...
    沈念sama閱讀 38,276評論 3 399
  • 文/蒼蘭香墨 我猛地睜開眼多糠,長吁一口氣:“原來是場噩夢啊……” “哼累舷!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起夹孔,我...
    開封第一講書人閱讀 36,927評論 0 259
  • 序言:老撾萬榮一對情侶失蹤被盈,失蹤者是張志新(化名)和其女友劉穎析孽,沒想到半個月后,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體只怎,經(jīng)...
    沈念sama閱讀 43,400評論 1 300
  • 正文 獨居荒郊野嶺守林人離奇死亡袜瞬,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 35,883評論 2 323
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發(fā)現(xiàn)自己被綠了身堡。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片邓尤。...
    茶點故事閱讀 37,997評論 1 333
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖贴谎,靈堂內(nèi)的尸體忽然破棺而出汞扎,到底是詐尸還是另有隱情,我是刑警寧澤擅这,帶...
    沈念sama閱讀 33,646評論 4 322
  • 正文 年R本政府宣布澈魄,位于F島的核電站,受9級特大地震影響仲翎,放射性物質(zhì)發(fā)生泄漏痹扇。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點故事閱讀 39,213評論 3 307
  • 文/蒙蒙 一溯香、第九天 我趴在偏房一處隱蔽的房頂上張望鲫构。 院中可真熱鬧,春花似錦玫坛、人聲如沸结笨。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,204評論 0 19
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽禀梳。三九已至,卻和暖如春肠骆,著一層夾襖步出監(jiān)牢的瞬間算途,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 31,423評論 1 260
  • 我被黑心中介騙來泰國打工蚀腿, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留嘴瓤,地道東北人。 一個月前我還...
    沈念sama閱讀 45,423評論 2 352
  • 正文 我出身青樓莉钙,卻偏偏與公主長得像廓脆,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子磁玉,可洞房花燭夜當(dāng)晚...
    茶點故事閱讀 42,722評論 2 345

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