Spring源码分析(一) XmlWebApplicationContext

spring是大家都会用的ioc框架,但是要真的了解spring还是需要好好研究一下才行,为此看了一些spring源码,所以开始写spring源码分析的文章,这个是第一篇,先从ioc容器的启动开始。
我们都知道,spring的ioc容器的最基本的接口就是BeanFactory,而ApplicationContext是包含了BeanFactory的所有信息,所以ioc容器在启动的时候就是从AbstractApplicationContext的refresh方法开始的

public void refresh() throws BeansException, IllegalStateException {
    synchronized (this.startupShutdownMonitor) { // 加锁,避免 #refresh() 和 #close() 方法,自身或者对方并行执行。
        // Prepare this context for refreshing.
        // 准备刷新的上下文
        prepareRefresh();

        // Tell the subclass to refresh the internal bean factory.
        // 初始化 BeanFactory ,并进行 XML 文件读取
        ConfigurableListableBeanFactory beanFactory = obtainFreshBeanFactory();

        // Prepare the bean factory for use in this context.
        // 对 BeanFactory 进行各种功能填充。
        // TODO 包括对 @Autowired 和 @Qualifier 注解的属性注入
        prepareBeanFactory(beanFactory);

        try {
            // Allows post-processing of the bean factory in context subclasses.
            // 子类覆盖该方法,做 BeanFactory 的额外的处理
            postProcessBeanFactory(beanFactory);
            // Invoke factory processors registered as beans in the context.
            // 激活各种 BeanFactory 处理器,例如 BeanFactoryPostProcessor
            invokeBeanFactoryPostProcessors(beanFactory);

            // Register bean processors that intercept bean creation.
            // 注册拦截 Bean 创建的 BeanPostProcessor。这里只是注册,真正的调用在 #getBean(...) 的时,即 Bean 创建的时候。
            // 注意:
            //      1. BeanFactoryPostProcessor 作用于 BeanDefinition
            //      2. BeanPostProcessor 作用于 Bean
            registerBeanPostProcessors(beanFactory);

            // Initialize message source for this context.
            initMessageSource();

            // Initialize event multicaster for this context.
            // 初始化 Application Event Multicaster
            initApplicationEventMulticaster();

            // Initialize other special beans in specific context subclasses.
            // 留给子类,来初始化其他特殊的 Bean 对象们
            onRefresh();

            // Check for listener beans and register them.
            // 注册监听器们
            registerListeners();

            // Instantiate all remaining (non-lazy-init) singletons.
            // 初始化非延迟加载的单例
            finishBeanFactoryInitialization(beanFactory);

            // Last step: publish corresponding event.
            // 完成 refresh 逻辑
            finishRefresh();
        } catch (BeansException ex) {
            if (logger.isWarnEnabled()) {
                logger.warn("Exception encountered during context initialization - " +
                        "cancelling refresh attempt: " + ex);
            }

            // Destroy already created singletons to avoid dangling resources.
            destroyBeans();

            // Reset 'active' flag.
            cancelRefresh(ex);

            // Propagate exception to caller.
            throw ex;
        } finally {
            // Reset common introspection caches in Spring's core, since we
            // might not ever need metadata for singleton beans anymore...
            resetCommonCaches();
        }
    }
}

具体的启动流程就不说了,主要是这里有一个onRefresh方法,我们来看AbstractRefreshableWebApplicationContext这个类,在这个类中覆写了onRefresh方法

protected void onRefresh() {
    this.themeSource = UiApplicationContextUtils.initThemeSource(this);
}

这是什么东西?别急,我们来看看themeSource是什么。

public static ThemeSource initThemeSource(ApplicationContext context) {
    if (context.containsLocalBean(THEME_SOURCE_BEAN_NAME)) {
        ThemeSource themeSource = context.getBean(THEME_SOURCE_BEAN_NAME, ThemeSource.class);
        // Make ThemeSource aware of parent ThemeSource.
        if (context.getParent() instanceof ThemeSource && themeSource instanceof HierarchicalThemeSource) {
            HierarchicalThemeSource hts = (HierarchicalThemeSource) themeSource;
            if (hts.getParentThemeSource() == null) {
                // Only set parent context as parent ThemeSource if no parent ThemeSource
                // registered already.
                hts.setParentThemeSource((ThemeSource) context.getParent());
            }
        }
        if (logger.isDebugEnabled()) {
            logger.debug("Using ThemeSource [" + themeSource + "]");
        }
        return themeSource;
    }
    else {
        // Use default ThemeSource to be able to accept getTheme calls, either
        // delegating to parent context's default or to local ResourceBundleThemeSource.
        HierarchicalThemeSource themeSource = null;
        if (context.getParent() instanceof ThemeSource) {
            themeSource = new DelegatingThemeSource();
            themeSource.setParentThemeSource((ThemeSource) context.getParent());
        }
        else {
            themeSource = new ResourceBundleThemeSource();
        }
        if (logger.isDebugEnabled()) {
            logger.debug("Unable to locate ThemeSource with name '" + THEME_SOURCE_BEAN_NAME +
                    "': using default [" + themeSource + "]");
        }
        return themeSource;
    }
}

还是不太明白?那我们来看看AbstractRefreshableWebApplicationContext的结构

public abstract class AbstractRefreshableWebApplicationContext extends AbstractRefreshableConfigApplicationContext
    implements ConfigurableWebApplicationContext, ThemeSource

原来ThemeSource是一个接口,而AbstractRefreshableWebApplicationContext则实现了这个接口,在onRefresh把自己传进去了,好吧,这块就先看到这里。
我们直接到XmlWebApplicationContext这个类里,我们发现AbstractRefreshableApplicationContext类有一个方法loadBeanDefinitions,而XmlWebApplicationContext覆写了这个方法,我们来看看XmlWebApplicationContext是怎么实现的

protected void loadBeanDefinitions(DefaultListableBeanFactory beanFactory) throws BeansException, IOException {
    // Create a new XmlBeanDefinitionReader for the given BeanFactory.
    XmlBeanDefinitionReader beanDefinitionReader = new XmlBeanDefinitionReader(beanFactory);

    // Configure the bean definition reader with this context's
    // resource loading environment.
    beanDefinitionReader.setEnvironment(getEnvironment());
    beanDefinitionReader.setResourceLoader(this);
    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);
    loadBeanDefinitions(beanDefinitionReader);
}

这里我们要介绍ioc容器里的一个接口BeanDefinitionReader,而XmlBeanDefinitionReader是BeanDefinitionReader的一个实现类,负责对xml的配置文件进行读取,并放到ioc容器中。当读取完配置文件后,通过loadBeanDefinitions方法将bean注册到ioc容器中。

protected void loadBeanDefinitions(XmlBeanDefinitionReader reader) throws IOException {
    String[] configLocations = getConfigLocations();
    if (configLocations != null) {
        for (String configLocation : configLocations) {
            reader.loadBeanDefinitions(configLocation);
        }
    }
}

至此,ioc容器就启动完成。
XmlWebApplicationContext的分析就到这里了。

你可能感兴趣的:(Spring源码分析(一) XmlWebApplicationContext)