1. 程式人生 > 實用技巧 >Spring核心IOC原始碼解讀(一)獲取BeanFactory

Spring核心IOC原始碼解讀(一)獲取BeanFactory

  在AbstractApplicationContext.refresh();的過程中,第二步為獲取BeanFactory ->obtainFreshBeanFactory()。在這個方法中,Spring先建立了BeanFactory,然後通過讀取XML配置檔案(或者掃描Java類)的方式初始化了BeanDefinition。這裡面就包括Spring Bean的主要資訊,例如依賴情況、作用域等等。

    @Override
    public void refresh() throws BeansException, IllegalStateException {
        
synchronized (this.startupShutdownMonitor) { // (1)Prepare this context for refreshing. prepareRefresh(); // (2)Tell the subclass to refresh the internal bean factory. ConfigurableListableBeanFactory beanFactory = obtainFreshBeanFactory(); ...... }

一、obtainFreshBeanFactory()方法的具體內容

    /**
     * Tell the subclass to refresh the internal bean factory.
     * @return the fresh BeanFactory instance
     * @see #refreshBeanFactory()
     * @see #getBeanFactory()
     */
    protected ConfigurableListableBeanFactory obtainFreshBeanFactory() {
        refreshBeanFactory();
        
return getBeanFactory(); }

  註釋上寫的:告訴子類重新整理內部的BeanFactory

    protected abstract void refreshBeanFactory() throws BeansException, IllegalStateException;
public abstract ConfigurableListableBeanFactory getBeanFactory() throws IllegalStateException;

  refreshBeanFactory()getBeanFactory()方法是抽象方法,由子類實現,這裡的子類是AbstractRefreshableApplicationContext,它是AbstractApplicationContext的子類。(類圖可以參考:大綱

二、關鍵在於refreshBeanFactory()方法

  看看AbstractRefreshableApplicationContext的實現:

    @Override
    protected final void refreshBeanFactory() throws BeansException {
        if (hasBeanFactory()) {
            destroyBeans();
            closeBeanFactory();
        }
        try {
        //(1)初始化BeanFactory DefaultListableBeanFactory beanFactory
= createBeanFactory(); beanFactory.setSerializationId(getId()); customizeBeanFactory(beanFactory);
        //(2)讀取BeanFefinition loadBeanDefinitions(beanFactory);
synchronized (this.beanFactoryMonitor) { this.beanFactory = beanFactory; } } catch (IOException ex) { throw new ApplicationContextException("I/O error parsing bean definition source for " + getDisplayName(), ex); } }

(1)AbstractRefreshableApplicationContext.createBeanFactory()

  建立DefaultListableBeanFactory物件,這個物件的類圖關係如下

  不僅實現了BeanFactory,還實現了Registry相關介面,意味著和Bean的註冊有很大關係

(2) AbstractRefreshableApplicationContext.loadBeanDefinitions()

  loadBeanDefinitions()是一個抽象方法,由AbstractXmlApplicationContext實現,類圖可參考:大綱

    @Override
    protected void loadBeanDefinitions(DefaultListableBeanFactory beanFactory) throws BeansException, IOException {
        // (1)建立讀取Xml的物件,和BeanFactory是依賴關係
        XmlBeanDefinitionReader beanDefinitionReader = new XmlBeanDefinitionReader(beanFactory);

        // (2)這些都是一些初始化操作
        beanDefinitionReader.setEnvironment(this.getEnvironment());
        beanDefinitionReader.setResourceLoader(this);
        beanDefinitionReader.setEntityResolver(new ResourceEntityResolver(this));

        // (3)真正的初始化操作發生在最後一步loadBeanDefinitions
        initBeanDefinitionReader(beanDefinitionReader);
        loadBeanDefinitions(beanDefinitionReader);
    }

  XmlBeanDefinitionReader初始化的beanFactory物件是BeanDefinitionRegistry介面的實現

    public XmlBeanDefinitionReader(BeanDefinitionRegistry registry) {
        super(registry);
    }

三、loadBeanDefinitions(beanDefinitionReader);通過Reader將XML Bean資訊讀取到BeanFactory中

  BeanFactory和Reader之間的關係是依賴關係

    protected void loadBeanDefinitions(XmlBeanDefinitionReader reader) throws BeansException, IOException {
        Resource[] configResources = getConfigResources();
        if (configResources != null) {
            reader.loadBeanDefinitions(configResources);
        }
        String[] configLocations = getConfigLocations();
        if (configLocations != null) {
            reader.loadBeanDefinitions(configLocations);
        }
    }

  reader.loadBeanDefinitions(configLocations)方法中,將String型別的xml檔案地址轉為了Resource物件,下面就是通過流來讀取