Spring源码分析-IOC(三)容器初始化

IOC的初始化又refresh方法来启动,这个过程包括Resource定位,BeanDefinitionl载入,BeanDefinitionl注册。这个过程一般不包括Bean的依赖注入,在ioc设计中Bean的载入和依赖注入是两个独立的过程,依赖注入一般发生在第一次getBean向容器索要Bean的时候。(单例Bean默认配置了lazyinit属性为ture,实例化会在ioc容器初始化的时候提前完成)

上文说容器的启动大同小异,基本操作封装在一个基类,这个基类就是AbstractApplicationContext。ClassPathXmlApplicationContext的refresh()实际上就是调用了AbstractApplicationContext的refresh()方法。

public void refresh() throws BeansException, IllegalStateException {
synchronized (this.startupShutdownMonitor) {
// 准备刷新容器, 获取容器的当时时间, 同时给容器设置同步标识
prepareRefresh();

        // 启动子类的refreshBeanFactory方法.  
        ConfigurableListableBeanFactory beanFactory = obtainFreshBeanFactory();

        // 为BeanFactory配置容器特性,例如类加载器、事件处理器等.
        prepareBeanFactory(beanFactory);
        try {
                // 设置BeanFactory的后置处理.  
                postProcessBeanFactory(beanFactory);

                // 调用BeanFactory的后处理器, 这些后处理器是在Bean定义中向容器注册的.  
                invokeBeanFactoryPostProcessors(beanFactory);

                // 注册Bean的后处理器, 在Bean创建过程中调用.  
                registerBeanPostProcessors(beanFactory);

                // 初始化上下文中的消息源.  
                initMessageSource();

                // 初始化上下文中的事件机制.  
                initApplicationEventMulticaster();

                // 初始化其它特殊的Bean. 
                onRefresh();

                // 检查并向容器注册监听器Bean.  
                registerListeners();

                // 实例化所有剩余的(non-lazy-init) 单例Bean.
                finishBeanFactoryInitialization(beanFactory);

                // 发布容器事件, 结束refresh过程.  
                finishRefresh();
        }
        catch (BeansException ex) {
                if (logger.isWarnEnabled()) {
                        logger.warn("Exception encountered during context initialization - " +
                                                "cancelling refresh attempt: " + ex);
                }
                // 销毁已经创建的单例Bean, 以避免资源占用. 
                destroyBeans();
                // 取消refresh操作, 重置 'active' 标志.  
                cancelRefresh(ex);
                throw ex;
        }
        finally {
                //重置Spring的核心缓存
                resetCommonCaches();
        }
}

}

Resources定位

obtainFreshBeanFactory()中调用了refreshBeanFactory(),而refreshBeanFactory的实现在AbstractRefreshableApplicationContext

protected final void refreshBeanFactory() throws BeansException {
//如果建立了BeanFactory则关闭销毁BeanFactory
if (hasBeanFactory()) {
destroyBeans();
closeBeanFactory();
}
try {
//创建并设置DefaultListableBeanFactory同时调用loadBeanDefinitions载入loadBeanDefinition
DefaultListableBeanFactory beanFactory = createBeanFactory();
beanFactory.setSerializationId(getId());
customizeBeanFactory(beanFactory);
loadBeanDefinitions(beanFactory);
synchronized (this.beanFactoryMonitor) {
this.beanFactory = beanFactory;
}
}
catch (IOException ex) {
throw new ApplicationContextException(“I/O error parsing bean definition source for “ + getDisplayName(), ex);
}
}
//在上下文中创建DefaultListableBeanFactory
protected DefaultListableBeanFactory createBeanFactory() {
return new DefaultListableBeanFactory(getInternalParentBeanFactory());
}

这里我们看一下loadBeanDefinitions其具体实现在AbstractXmlApplicationContext

protected void loadBeanDefinitions(DefaultListableBeanFactory beanFactory) throws BeansException, IOException {
// Create a new XmlBeanDefinitionReader for the given BeanFactory.
//创建一个beanDefinitionReader,并通过回调设置到BeanFactory中去
XmlBeanDefinitionReader beanDefinitionReader = new XmlBeanDefinitionReader(beanFactory);

    // Configure the bean definition reader with this context's
    // resource loading environment.
    //为XmlBeanDefinitionReader配一个ResourceLoader
    beanDefinitionReader.setEnvironment(this.getEnvironment());
    beanDefinitionReader.setResourceLoader(this);
    //为Bean读取器设置SAX xml解析器
    beanDefinitionReader.setEntityResolver(new ResourceEntityResolver(this));

    // Allow a subclass to provide custom initialization of the reader,
    // then proceed with actually loading the bean definitions.
    initBeanDefinitionReader(beanDefinitionReader);
    //Bean读取器真正实现的地方
    loadBeanDefinitions(beanDefinitionReader);
}
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,每一类资源都对应着一个BeanDefinitionReader,BeanDefinitionReader提供统一的转换规则;然后设置Reader,最后调用loadBeanDefinition,该loadBeanDefinition才是读取器真正实现的地方。而getConfigResources采用模板方法设计模式,具体的实现由之类完成,实际上这里getConfigResources调用的就是ClassPathXmlApplicationContext的getConfigResources方法。

1

从图中可以看出ClassPathXmlApplicationContext继承了DefaultResourceLoader,具备了Resource加载资源的功能。至此完成了Resource定位!

BeanDefinition载入

继续向下看loadBeanDefinitions是如何载入的

public int loadBeanDefinitions(Resource... resources) throws BeanDefinitionStoreException {
    Assert.notNull(resources, "Resource array must not be null");
    int counter = 0;
    //遍历所有Resource集合loadBeanDefinition的信息
    for (Resource resource : resources) {
        counter += loadBeanDefinitions(resource);
    }
    return counter;
}
//调用入口
public int loadBeanDefinitions(Resource resource) throws BeanDefinitionStoreException {
    return loadBeanDefinitions(new EncodedResource(resource));
}
//载入xml形式的BeanDefinition的地方
public int loadBeanDefinitions(EncodedResource encodedResource) throws BeanDefinitionStoreException {
    Assert.notNull(encodedResource, "EncodedResource must not be null");
    if (logger.isInfoEnabled()) {
        logger.info("Loading XML bean definitions from " + encodedResource.getResource());
    }

    Set<EncodedResource> currentResources = this.resourcesCurrentlyBeingLoaded.get();
    if (currentResources == null) {
        currentResources = new HashSet<EncodedResource>(4);
        this.resourcesCurrentlyBeingLoaded.set(currentResources);
    }
    if (!currentResources.add(encodedResource)) {
        throw new BeanDefinitionStoreException(
                "Detected cyclic loading of " + encodedResource + " - check your import definitions!");
    }
    try {
        //得到xml的InputStream
        InputStream inputStream = encodedResource.getResource().getInputStream();
        try {
            InputSource inputSource = new InputSource(inputStream);
            if (encodedResource.getEncoding() != null) {
                inputSource.setEncoding(encodedResource.getEncoding());
            }
            //具体的读入过程
            return doLoadBeanDefinitions(inputSource, encodedResource.getResource());
        }
        finally {
            inputStream.close();
        }
    }
    catch (IOException ex) {
        throw new BeanDefinitionStoreException(
                "IOException parsing XML document from " + encodedResource.getResource(), ex);
    }
    finally {
        currentResources.remove(encodedResource);
        if (currentResources.isEmpty()) {
            this.resourcesCurrentlyBeingLoaded.remove();
        }
    }
}

protected int doLoadBeanDefinitions(InputSource inputSource, Resource resource)
throws BeanDefinitionStoreException {
try {
//取得xml文件的Document,解析过程是由DocumentLoader完成,默认为DefaultDocumentLoader
Document doc = doLoadDocument(inputSource, resource);
//启动对BeanDefinition的详细解析过程,这个解析会使用到spring的BEAN配置规则
return registerBeanDefinitions(doc, resource);
}
catch (BeanDefinitionStoreException ex) {
throw ex;
}
catch (SAXParseException ex) {
throw new XmlBeanDefinitionStoreException(resource.getDescription(),
“Line “ + ex.getLineNumber() + “ in XML document from “ + resource + “ is invalid”, ex);
}
catch (SAXException ex) {
throw new XmlBeanDefinitionStoreException(resource.getDescription(),
“XML document from “ + resource + “ is invalid”, ex);
}
catch (ParserConfigurationException ex) {
throw new BeanDefinitionStoreException(resource.getDescription(),
“Parser configuration exception parsing XML from “ + resource, ex);
}
catch (IOException ex) {
throw new BeanDefinitionStoreException(resource.getDescription(),
“IOException parsing XML document from “ + resource, ex);
}
catch (Throwable ex) {
throw new BeanDefinitionStoreException(resource.getDescription(),
“Unexpected exception parsing XML document from “ + resource, ex);
}
}

得到了xml的document对象,怎么按照Spring的Bean规则将document转换成BeanDefinitionDocument呢?这个过程是由BeanDefinitionDocumentReader完成的,这里的registerBeanDefinitions还对载入Bean的数量进行了统计

public int registerBeanDefinitions(Document doc, Resource resource) throws BeanDefinitionStoreException {
//得到BeanDefinitionDocumentReader对xml进行解析
BeanDefinitionDocumentReader documentReader = createBeanDefinitionDocumentReader();
int countBefore = getRegistry().getBeanDefinitionCount();
//具体解析过程在这个registerBeanDefinitions中完成
documentReader.registerBeanDefinitions(doc, createReaderContext(resource));
return getRegistry().getBeanDefinitionCount() - countBefore;
}

至此就完成了BeanDefinition的载入,BeanDefinition的载入分为两个部分,首先通过调用xml解析器得到的document对象,但是这个对象并没有按照spring的bean规则进行解析。在完成xml解析之后,才是按照Spring的Bean规则进行解析,这个解析过程在DocumentReader中完成的,这里使用的是默认的DefaultBeanDefinitionDocumentReader。

坚持原创技术分享,您的支持将鼓励我继续创作!
  • 本文作者: XiuYu.Ge
  • 本文链接: 57.html
  • 版权声明: 本博客所有文章除特别声明外,均采用 CC BY-NC-SA 3.0 许可协议。转载请注明出处!