Spring配置文件解析(一)ClassPathXmlApplicationContext源码分析

1 概述

针对前面的SpringIOC的源码分析,我们看见了在整个Spring容器初始化的时候,配置文件的解析是相当重要的,所以从这篇文章开始,我们将对配置文件的解析进行深入的分析。
这里我们仅仅拿ClassPathXmlApplicationContext类来进行分析,因为FileSystemXmlApplicationContext的配置文件解析的过程和ClassPathXmlApplicationContext是相同的。

2 详细分析

在我们的测试当中使用到了如下的代码。

ClassPathXmlApplicationContext ctx = new ClassPathXmlApplicationContext("spring_test.xml");
Animal animal = (Animal) ctx.getBean("animal");
animal.eat();

这里调用了ClassPathXmlApplicationContext类的构造函数。

public ClassPathXmlApplicationContext(String configLocation) throws BeansException {

        //这里支持自动刷新Spring容器
    this(new String[] {configLocation}, true, null);
}

而在这个构造函数中又调用了下面这个构造函数。

public ClassPathXmlApplicationContext(
        String[] configLocations, boolean refresh, @Nullable ApplicationContext parent)
        throws BeansException {

    super(parent);
    
    //设置配置文件地址
    setConfigLocations(configLocations);
    if (refresh) {
    
        //刷新容器,至此,我们可以猜想配置文件的加载其实是在这个函数里面实现的。
        refresh();
    }
}

那么refresh()函数中又干了什么呢?针对refresh函数我们前面已经分析过,其实这里只需要关注下面这行代码就行了,

public void refresh() throws BeansException, IllegalStateException {
    ... ...
    
    //告述子类刷新内部bean工厂
    ConfigurableListableBeanFactory beanFactory = obtainFreshBeanFactory();
    ... ...
}

刷新bean工厂后返回,然后再对bean工厂进行其余的处理。

protected ConfigurableListableBeanFactory obtainFreshBeanFactory() {

    //这是一个抽象函数,具体实现留给子类
    refreshBeanFactory();
    
    //这里的getBeanFactory也是一个抽象函数
    ConfigurableListableBeanFactory beanFactory = getBeanFactory();
    if (logger.isDebugEnabled()) {
    logger.debug("Bean factory for " + getDisplayName() + ": " + beanFactory);
    }
    return beanFactory;
}

上面的代码,我们可以猜想getBeanFactory函数返回的就是refreshBeanFactory刷新的Bean工厂。下面我们继续来看refreshBeanFactory函数的源码。

protected final void refreshBeanFactory() throws BeansException {

    //有bean工厂
    if (hasBeanFactory()) {
        
    //这里其实就是删除了所有单列bean(其实就是置空了和bean相关的缓存)。
    destroyBeans();
        
    //这里其实就是将bean工厂设置成了null
    closeBeanFactory();
    }
    try {
    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);
    }
}

接下来继续看loadBeanDefinitions(beanFactory);这一步的源码。

protected void loadBeanDefinitions(DefaultListableBeanFactory beanFactory) throws BeansException, IOException {
    XmlBeanDefinitionReader beanDefinitionReader = new XmlBeanDefinitionReader(beanFactory);
    beanDefinitionReader.setEnvironment(this.getEnvironment());
    beanDefinitionReader.setResourceLoader(this);
    beanDefinitionReader.setEntityResolver(new ResourceEntityResolver(this));
    initBeanDefinitionReader(beanDefinitionReader);
    loadBeanDefinitions(beanDefinitionReader);
}

上面的函数其实是生成XmlBeanDefinitionReader对象后调用了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);
    }
}

从这个函数的源码我们可以看出,其实具体的解析配置文件的工作是交给了XmlBeanDefinitionReader。
简单来说在ApplicationContext中所做的操作是初始化了一个BeanFactory和XmlBeanDefinitionReader,针对XmlBeanDefinitionReader这个类的分析,我们接下来会继续,欢迎交流!

    原文作者:Spring Cloud
    原文地址: https://blog.csdn.net/ONROAD0612/article/details/85125178
    本文转自网络文章,转载此文章仅为分享知识,如有侵权,请联系博主进行删除。
点赞