<rt id="bn8ez"></rt>
<label id="bn8ez"></label>

  • <span id="bn8ez"></span>

    <label id="bn8ez"><meter id="bn8ez"></meter></label>

    posts - 28,  comments - 15,  trackbacks - 0

        我們知道Spring框架提供基于依賴注入的IOC容器,完成對象的構造、依賴注入、對象聲明周期維護等功能,下面將以FileSystemXmlApplicationContext為例來分析Spring IOC容器的實現。

    1.容器類圖

        從整體上看Spring容器可以分為兩大部分:外部容器和內部容器。我們經常使用的FileSystemXmlApplicationContext、ClassPathXmlApplicationContext表現為外部容器,他們的父類都繼承了ResourceLoader(資源加載),因此他們主要側重于對外部資源的注入、解釋方面的處理,而對于對象的構造、注入等聲明周期維護則委托給內部對象實現,通過區分外部容器和內部容器,可以有效保護內部容器管理的bean,防止外部錯誤的調用破壞對象狀態。
                                                                            圖-1 外部容器類圖
      
                                                                               圖2 內部容器類圖
        從類圖分析可以看到SpringIOC容器可以分成兩部分:外部容器和內部容器。外部容器(FileSystemXmlApplicationContext)主要負責與外部的調用進行溝通,包括接收外部的配置信息、為外部提供受容器管理的Bean、外部配置信息的解釋、BeanDefinition的緩存等。內部容器(DefaultListableBeanFactory--深綠色)主要負責Bean的聲明周期管理,包括Bean的注冊、Bean的緩存、Bean的銷毀等。
        

    1.1 接口和類說明

    類圖中列出了多種類和接口,下面列出重點的進行說明。注意官方說明,翻譯自API。

    接口
    ListableBeanFactory

    官方說明

    BeanFactory接口的擴展,由那些能夠列舉它們所管理的所有bean實例的bean工廠所實現。而不是試圖通過來自于客戶端的by name方式的bean查找。預載所有bean definitionsBeanFactory實現可能會實現該接口。

    個人理解:提供bean factory所管理bean的枚舉的接口

    接口HierarchicalBeanFactory

    官方說明

           bean factory實現的子接口,實現了該接口的bean factory能成為一個層次結構的一部分。

    個人理解:用以組織bean factory層次的一個接口。


    接口ApplicationContext

    官方說明:

    中心接口,以提供應用程序的配置。當應用程序正在運行,這是只讀的,但如果實現支持,它是允許重新加載的。

    一個ApplicationContext提供如下功能:

    用來訪問應用程序組件的bean factory方法,其繼承自ListableBeanFactory

    能以通用的方式加載文件資源,其繼承自ResourceLoader

    能夠向注冊的監聽器發布事件,其繼承自ApplicationEventPublisher

    能夠解析消息,支持國際化,繼承自MessageSource

    繼承自父上下文,后代上下文中的Definition將總能獲得優先級,這意味著,例如,一個單親上下文能夠被整個應用程序使用,而每個servlet有它自己的孩子上下文,它獨立于其他的servlet

    接口AutowireCapableBeanFactory

    官方說明

        BeanFactory接口的擴展,可以被那些有能力自動裝配的bean factory實現,用以達到為存在的bean暴露此項功能的目的。

        該接口不應在常見的應用程序中使用,黏合BeanFactory或者ListableBeanFactory是其典型的應用案例。

        應該注意的是,該接口不應被ApplicationContext直接實現,因為應用程序代碼幾乎不曾被應用程序代碼使用。也就是說,它也可以通過訪問ApplicationContextgetAutowireCapableBeanFactory()方法從應用程序上下文中獲得,即獲得一個AutowireCapableBeanFactory實例。
    個人理解

        從接口定義的方法中可以看出,該接口主要用于自動裝配bean,包括創建bean、裝配bean的屬性、裝配bean的依賴、注冊bean等。該接口對于外部的應用程序而言,幾乎不需要使用,其只應用于Spring容器的內部管理,實際上只有內部bean factory實現此功能。關于內部bean factory后面會有說明。


    接口
    ConfigurableApplicationContext

    官方說明

    SPI(單個程序啟動)接口將會被大多數而不是全部的應用程序上下文實現,除了在ApplicationContext中的應用程序上下文客戶端方法,其還提供設施來配置上下文。

             配置和生命周期方法被封裝在這里,以避免使他們暴漏給ApplicationContext的客戶端代碼。這些方法應該只用于啟動和關閉代碼中。

    個人理解:


    抽象類
    AbstractApplicationContext

    官方說明:

    ApplicationContext接口的抽象實現。其不要求配置使用的存儲類型,只是簡單的實現了常見上下文功能。它采用了模板方法模式,因此要求具體子類實現抽象方法。

    與普通的BeanFactory相比,ApplicationContext支持檢測定義在其內部的bean工廠中的特殊的bean。因此,該類能自動注冊BeanFactoryPostProcessorBeanPostProcessorApplicationListener,它們在上下文中都被定義為beans

    通過擴展DefaultResourceLoader實現資源加載,因此,視非URL資源路徑為類路徑資源(支持完整類路徑資源命名,包括包路徑,例如mypackage/myresource.dat),否則getResourceByPath方法需要在子類中覆寫。

    個人理解:

           該類提供了BeanFactory的后置processor的注冊、應用上下文的雙親維護、資源加載的功能。


    抽象類
    AbstractRefreshableApplicationContext

    ApplicationContext的基類的實現,其支持多次refreshs,每次創建一個內部bean工廠實例。通常(但不一定),一個上下文將會由一系列的配置定位來驅動,加載bean definations

    子類唯一需要實現的方法是loadBeanDefinitions,該方法主要是獲取每次刷新調用。具體的實現應該是加載bean定義到給定的org.springframework.beans.factory.support.DefaultListableBeanFactory,通常委托給一個或多個特定的bean definition readers


    抽象類
    AbstractRefreshableConfigApplicationContext

    官方說明

    AbstractRefreshableApplicationContext子類,增加了針對 指定的配置位置(configLocations)的常見的處理。可以作為基于XML應用程序上下文實現的基類,例如ClassPathXmlApplicationContexFileSystemXmlApplicationContext也可以是XmlWebApplicationContextXmlPortletApplicationContext
    個人理解:

     主要為配置文件位置的設置提供入口,即實現了setConfigLocation方法。這就提供了不依賴于Spring的且更靈活、通用的配置注入方式。


    抽象類
    AbstractXmlApplicationContext說明:

    ApplicationContext便利基類的實現。用于提取包含bean definition信息的XML文檔,該文檔由XmlBeanDefinitionReader負責解釋。

    子類要實getConfigResources/getConfigLocations,此外,他們可能會覆蓋
    getResourceByPath
    鉤子來解釋相對路徑。

    FileSystemXmlApplicationContext說明

    獨立的XML應用程序上下文,它從文件系統或者URLs獲得上下文定義,解釋普通路徑為相對文件系統位置(如“MYDIR/ myfile.txt”),同時它也是有用的測試工具與獨立環境。

    普通路徑總是會被解釋為相對當前VM的工作目錄,即使他們以斜線開頭。(這與Servlet容器的語義是一致的。)使用一個明確的“file:”前綴,以執行一個絕對文件路徑。

    配置文件位置默認值可以通過getConfigLocations覆蓋,配置位置可以表示為/ MYFILES/ context.xml”之類的具體文件,也可以像/ MYFILES/ *- context.xml”似Ant風格模式(org.springframework.util.AntPathMatcher)。

    注意:在多個配置位置的情況下,以后的bean定義覆蓋先前加載的文件中定義的。這可以通過一個額外的XML文件,來故意覆蓋某些bean定義。

    這是一個簡單的,一站式的便利的ApplicationContext。考慮結合使用GenericApplicationContextXmlBeanDefinitionReader提供更靈活的上下文設置。


    接口
    ResourceLoader

    加載資源(例如,類路徑和文件路徑)的策略接口,ApplicationContext需要提供此功能,加上擴展的ResourcePatternResolver支持。DefaultResourceLoader是該接口的獨立實現,它可用于ApplicationContext以外,也可以被ResourceEditor使用。


    接口
    ResourcePatternResolver

        解釋位置模式的策略接口,其擴展自ResourcePatternResolver接口。


    PathMatchingResourcePatternResolver

    ResourcePatternResolver接口的實現,能夠把指定的資源位置路徑轉化為一個或者多個匹配資源。源路徑可能是一個簡單的路徑,它一對一映射到目標(Resource),或者可能選擇性地包含特定的“classpath*:”前綴和/或者Ant-style正則表達式(由org.springframework.util.AntPathMatcher匹配)

    在一般的情況,如果指定的位置路徑沒有以“classpath*:”前綴開始,并且未包含PathMatcher模式,解釋器將通過調用ResourceLoadergetResource方法返回單一的資源。例子可包括真實的 URLs,例如file:C:/context.xml;偽URLs,例如classpath:/context.xml;簡單的無前綴的路徑,例如,/WEB-INF/context.xml

    2容器啟動分析

    2.1容器的構建
     我們以FileSystemXmlApplicationContext為例來分析容器的啟動過程,首先看看FileSystemXmlApplicationContext的構造函數:

    public FileSystemXmlApplicationContext(String[] configLocations, boolean refresh, ApplicationContext parent)
                                      
    throws BeansException {
            
    super(parent);
            setConfigLocations(configLocations);
            
    if (refresh) {
    //refresh方法是容器啟動的核心,包括內部容器的維護,資源定位處理,資源的解析、注冊等。
                refresh();
            }

    }

    關于super的調用,以下代碼是個重點:
    以下代碼來自于AbstractApplicationContext,這里要注意的是容器在構造時自動構造了資源模式解釋器,關于資源模式解釋器后面會有介紹.
    //資源模式解釋器,用于解釋處理ant-style配置信息,也可以把它理解為批量資源解釋器,并把解釋的一組資源定位解釋成Resource.該實例在容器創建時會自動創建
    private ResourcePatternResolver resourcePatternResolver;
    public AbstractApplicationContext(ApplicationContext parent) {
            
    this.parent = parent;
            
    this.resourcePatternResolver = getResourcePatternResolver();
    }

    protected ResourcePatternResolver getResourcePatternResolver() {
            
    return new PathMatchingResourcePatternResolver(this);
    }

    一般情況下,我們可以通過編碼的方式來啟動容器,例如,如下:

    ApplicationContext context = new FileSystemXmlApplicationContext (
            
    new String[] {"classpath:applicationContext*.xml"},true,null);
    BeanFactory factory 
    = (BeanFactory) context;

    2.2容器的初始化
    2.2.1Refresh方法分析
        我們接下來分析fresh方法,該方法由FileSystemXmlApplicationContext的父類AbstractApplicationContext實現,從圖1可以看到AbstractApplicationContext是ApplicationContext接口的最頂層實現。注意:方法中的子方法調用將在后面的章節中分別介紹。

    public void refresh() throws BeansException, IllegalStateException {
        
    //獲得啟動關閉監視器,防止此刻容器被其他線程操作。
    synchronized (this.startupShutdownMonitor) {
                prepareRefresh();
    //激活容器的活動狀態,采用鎖進行同步
    /** *//**這里是容器初始化最為關鍵的一步,主要完成:
    1.內部容器的初始化,包括對已經存在的內部容器管理的資源的銷毀、內部容器的銷毀、創建新的內部容器等;
    2.資源定位解釋,即把configLocations解釋成一個或者多個Resource;
    3.BeanDefinition加載與注冊,把Resource加載解釋成xml Document,然后對Document進行解釋,形成BeanDefinition,并對Definition進行注冊;
    */

    ConfigurableListableBeanFactory beanFactory 
    = obtainFreshBeanFactory();

                
    //內部工廠的預處理,主要是注冊一些Spring組件
                prepareBeanFactory(beanFactory);

                
    try {
        
    // Allows post-processing of the bean factory in context subclasses.
                    postProcessBeanFactory(beanFactory);
    //調用BeanFactory的后置處理,其處理的流程是:
    /** *//**
    (1)先對在prepareBeanFactory階段注冊的后置處理組件先進行調用;
    (2)然后從容器加載BeanFactoryPostProcessor類型的bean,進行調用處理,這類例子我們經常用到,例如PropertyPlaceholderConfigurer在分離數據庫配置中的使用;
    */

                    invokeBeanFactoryPostProcessors(beanFactory);
                    
    // Register bean processors that intercept bean creation.
                    registerBeanPostProcessors(beanFactory);
                    
    // Initialize message source for this context.
                    initMessageSource();
    // Initialize event multicaster for this context.
                    initApplicationEventMulticaster();
    // Initialize other special beans in specific context subclasses.
                    onRefresh();
                    
    // Check for listener beans and register them.
                    registerListeners();
                    
    // Instantiate all remaining (non-lazy-init) singletons.
                    finishBeanFactoryInitialization(beanFactory);
                    
    // Last step: publish corresponding event.
                    finishRefresh();
                }


                
    catch (BeansException ex) {
                    beanFactory.destroySingletons();
                    cancelRefresh(ex);
                    
    throw ex;
                }

            }

        }


    2.2.2 obtainFreshBeanFactory方法分析
        
    該方法是在refresh方法中調用的,它主要完成了以下任務:
        1.內部容器的初始化,包括對已經存在的內部容器管理的資源(緩存的singleton bean以及bean name)的銷毀、內部容器的銷毀、創建新的內部容器、容器的定制等;
        2.資源定位解釋,即把configLocations解釋成一個或者多個Resource;
        
    3.BeanDefinition加載與注冊,把Resource加載解釋成xml Document,然后對Document進行解釋,形成BeanDefinition,并對Definition進行注冊;BeanDefinition就是spring對bean的定義,在spring構造bean以及維護bean的引用關系時用到。

        obtainFreshBeanFactory方法由抽象類AbstractApplicationContext定義,代碼如下:

    protected ConfigurableListableBeanFactory obtainFreshBeanFactory() {
            refreshBeanFactory();
            ConfigurableListableBeanFactory beanFactory 
    = getBeanFactory();
             …… 
            
    return beanFactory;
    }


    protected abstract void refreshBeanFactory() throws BeansException, IllegalStateException;

    public abstract ConfigurableListableBeanFactory getBeanFactory() throws IllegalStateException;

        從代碼中可以看到方法refreshBeanFactorygetBeanFactory都被定義為抽象方法,這是典型的模板方法模式。其中子類AbstractRefreshableApplicationContextGenericApplicationContext都實現這些方法,接下來以AbstractRefreshableApplicationContext的實現作進一步說明。
    2.2.2.1 refreshBeanFactory方法分析

    /** Bean factory for this context */ 
    //上下文中的beanFactory,這個factory就是所的內部容器,可以在圖2中看到它的繼承關系
    private DefaultListableBeanFactory beanFactory;

    protected final void refreshBeanFactory() throws BeansException {
            
    if (hasBeanFactory()) {//檢查beanFactory是否為空,如果不為空,則銷毀singletonBeans緩存、singletonFactories工廠緩存、beanFactory等;
                destroyBeans();
                closeBeanFactory();
            }

            
    try {
    // 創建internal bean factory,即屬性beanFactory
            DefaultListableBeanFactory beanFactory = createBeanFactory();               customizeBeanFactory(beanFactory);
            loadBeanDefinitions(beanFactory);
    // 加載BeanDefinition,下面重點討論的
            synchronized (this.beanFactoryMonitor) {
                
    this.beanFactory = beanFactory;
                }

            }

            
    catch (IOException ex) {
                
    throw new ApplicationContextException(
                        
    "I/O error parsing XML document for application context [" + getDisplayName() + "]", ex);
            }

        }

     

    容器可以有雙親(AbstractApplicationContext類的parent),每個容器下都有一個beanFactory(AbstractRefreshableApplicationContext),該beanFactory的類型為DefaultListableBeanFactory,我們稱之為內部容器。它才是真正意義上bean的管理容器,因為緩存相關bean的信息的載體是由其父類DefaultSingletonBeanRegistry負責的,這一點在下面的destroyBeans方法分析中將能看到。

    refreshBeanFactory()方法詳細說明:

    <1>檢查內部的beanFactory是否存在,如果存在則要銷毀beanFactory內存在的相關資

    (關于銷毀的資源參看destroyBeans方法的說明)以及關閉beanFactory

    <2>構造新的內部bean factory,并定制該工廠,定制的選項主要包括:allowBeanDefinitionOverriding(是否允許bean definition覆蓋)

    allowCircularReferences(是否允許bean之間循環引用)

    <3>加載bean definition

    destroyBeans()方法解析

        在解析之前我們先明確一件事情,springbean分為單實例(singleton)與原型(prototype)兩種類型。對于singleton類型的bean,容器只保留一個實例,而原型類型的bean是容器每次接受請求通過defination創建的一個新實例。因此,我們都能夠推斷出容器是要緩存singleton bean的,事實上spring也確實這樣做的。

       destroyBeans主要完成了以下任務,銷毀singleton beansearly singleton beanssingleton factory beansdisposable beans以及disposable beans的依賴beansdestroyBeans方法由DefaultListableBeanFactory父類DefaultSingletonBeanRegistry實現的,包括對singleton beans的相關緩存實現,其代碼如下:

     

    protected void destroyBeans() {
            getBeanFactory().destroySingletons();
    //destroySingletons()的實現在下面
    //這里的getBeanFactory()獲得的是上面提到的內部容器beanFactory
    }


    /** *//*************以下代碼摘自DefaultSingletonBeanRegistry**********/
    //緩存singleton對象集合,映射關系為bean name--> bean instance
    /** *//**ConcurrentMap的創建:jdk5以及以上使用juc包的ConcurrentMap;否則,存在edu的ConcurrentMap則使用edu的ConcurrentMap,否則使用Collection.synchronizedMap(HashMap);*/
    private final Map singletonObjects = CollectionFactory.createConcurrentMapIfPossible(16);

    /** *//** Cache of singleton factories: bean name --> ObjectFactory */
    /** *//**緩存singleton factory bean集合,這是不是說明一個singleton的beanName需要對應一個真實的singleton bean以及一個singleton factory bean呢?答案是否定的,FactoryBean存在的意義在于:在開發中可能存在需要類似于工廠模式創建類的需求,即一個對象是由工廠代理創建的,尤其是在第三方庫結合的時候,可以用FactoryBean來創建合適的bean.*/
    private final Map singletonFactories = new HashMap();

    /** *//** Cache of early singleton objects: bean name --> bean instance */
    //緩存早期的singlton bean,那么早期是如何定義的呢?spring又是如何管理的呢?實際上,earlySingletonObjects 存儲的是FactoryBean的getObject方法獲得的bean,singletonFactories 存儲FactoryBean(詳見:getSingleton()方法)
    //當調用外部容器的getBean方法時,外部容器將調用轉交給DefaultListalbeBeanFactory,它會依次檢查singletonObjects 、earlySingletonObjects 、singletonFactories 是否存在。
    private final Map earlySingletonObjects = new HashMap();

    /** *//** Set of registered singletons, containing the bean names in registration order */
    //注冊的singleton bean集合,主要包含以注冊順序存儲的bean names
    private final Set registeredSingletons = new LinkedHashSet(16);

    /** *//** Names of beans that are currently in creation */
    //當前創建的singleton bean的name
    private final Set singletonsCurrentlyInCreation = Collections.synchronizedSet(new HashSet());

    /** *//** List of suppressed Exceptions, available for associating related causes */
    private Set suppressedExceptions;

    /** *//** Flag that indicates whether we're currently within destroySingletons */
    //表示當前是否處于銷毀singleton的狀態
    private boolean singletonsCurrentlyInDestruction = false;

    /** *//** Disposable bean instances: bean name --> disposable instance */
    //處置bean,主要在bean銷毀時需要調用該bean的destroy方法,即實現了disposable接口
    private final Map disposableBeans = new LinkedHashMap(16);

    /** *//** Map between dependent bean names: bean name --> Set of dependent bean names */
    //用于保存bean的依賴關系,即一個bean依賴于哪幾個bean
    private final Map dependentBeanMap = CollectionFactory.createConcurrentMapIfPossible(16);
    //上一個的反向存儲,可以理解為從屬于
    /** *//** Map between depending bean names: bean name --> Set of bean names for the bean's dependencies */
    private final Map dependenciesForBeanMap = CollectionFactory.createConcurrentMapIfPossible(16);

    public void destroySingletons() {//銷毀單例
            synchronized (this.singletonObjects) {
                
    this.singletonsCurrentlyInDestruction = true;
            }

            
    synchronized (this.disposableBeans) {
        String[] disposableBeanNames 
    = StringUtils.toStringArray(this.disposableBeans.keySet());
                
    for (int i = disposableBeanNames.length - 1; i >= 0; i--{
                    destroySingleton(disposableBeanNames[i]);
                }

            }

            
    synchronized (this.singletonObjects) {
                
    this.singletonObjects.clear();  //清除singleton對象
                this.singletonFactories.clear();//清除single factory bean
                this.earlySingletonObjects.clear();//清除早期的single對象
                this.registeredSingletons.clear();
                
    this.singletonsCurrentlyInDestruction = false;
            }

    }



    下一節 《Spring 源碼閱讀(IOC容器)-容器啟動2

    posted on 2012-02-07 11:10 zhangxl 閱讀(722) 評論(0)  編輯  收藏 所屬分類: IOC/AOP

    只有注冊用戶登錄后才能發表評論。


    網站導航:
     
    <2012年2月>
    2930311234
    567891011
    12131415161718
    19202122232425
    26272829123
    45678910

    常用鏈接

    留言簿(1)

    隨筆分類(17)

    隨筆檔案(28)

    文章分類(30)

    文章檔案(30)

    相冊

    收藏夾(2)

    hibernate

    java基礎

    mysql

    xml

    關注

    壓力測試

    算法

    最新隨筆

    搜索

    •  

    積分與排名

    • 積分 - 96260
    • 排名 - 601

    最新評論

    閱讀排行榜

    評論排行榜

    主站蜘蛛池模板: 久久综合九色综合97免费下载| 亚洲 综合 国产 欧洲 丝袜| 羞羞视频免费网站在线看| 亚洲人配人种jizz| 2022年亚洲午夜一区二区福利| 日韩亚洲国产综合久久久| 最近免费中文字幕视频高清在线看| 久久免费看少妇高潮V片特黄| www成人免费视频| 精品免费AV一区二区三区| 亚洲人成777在线播放| 久久精品亚洲中文字幕无码麻豆| 中文字幕亚洲综合久久菠萝蜜 | 亚洲色婷婷六月亚洲婷婷6月| 丁香亚洲综合五月天婷婷| 日韩在线a视频免费播放| 国内免费高清在线观看| 天天影视色香欲综合免费| 久操免费在线观看| 日本不卡免费新一区二区三区| 在线免费视频你懂的| fc2免费人成在线| 一个人看的www在线免费视频 | 国产特级淫片免费看| 日韩免费视频播播| 午夜免费福利在线观看| 暖暖免费高清日本一区二区三区| 免费看大美女大黄大色| 四虎影视免费在线| 日本免费人成黄页在线观看视频| 无码日韩精品一区二区免费| 国产免费看JIZZ视频| 国产精品视频免费一区二区 | 亚洲色大成网站www| 亚洲熟妇AV日韩熟妇在线| 亚洲日产乱码一二三区别 | 啦啦啦www免费视频| 日本一道在线日本一道高清不卡免费| 成人午夜18免费看| 女人18毛片免费观看| 国产婷婷高清在线观看免费 |