首先给出 IOC 容器初始化的时序图

这里以 ClassPathXmlApplicationContext 为例子,加载 xml 文件中的对象。

大致流程分为 3 个步骤,定位,加载,注册

定位:定位 xml 所在位置

加载:将 xml 中的元素转化成 Resource 对象,加载对应的节点元素

注册:将 Resource 对象转化成 Document 对象,然后注册到 BeanDifinittion,保存到容器 beanDefinitionMap 中

image-20200903172942096

实际分析过程

  1. 首先我们在加载一个 xml 配置文件的时候,会使用以下方式,所以我们以 ClassPathXmlApplicationContext 这个容器作为示例

    1
    2
    3
    public static void main(String[] args) {
    ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext("classpath:spring.xml");
    }

    可以看出,我们是通过构造方法来加载配置文件的,那我们通过构造方法查看具体执行流程

    1
    2
    3
    4
    5
    6
    7
    8
    9
    public ClassPathXmlApplicationContext(String[] configLocations, boolean refresh, ApplicationContext parent)
    throws BeansException {

    super(parent);
    setConfigLocations(configLocations);
    if (refresh) {
    refresh();
    }
    }

    最终执行的构造方法为上述方法,然后我们追踪 refresh()方法

  2. refresh 方法如下:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    61
    62
    63
    public void refresh() throws BeansException, IllegalStateException {
    synchronized (this.startupShutdownMonitor) {
    // Prepare this context for refreshing.
    prepareRefresh();

    // Tell the subclass to refresh the internal bean factory.
    ConfigurableListableBeanFactory beanFactory = obtainFreshBeanFactory();

    // Prepare the bean factory for use in this context.
    prepareBeanFactory(beanFactory);

    try {
    // Allows post-processing of the bean factory in context subclasses.
    postProcessBeanFactory(beanFactory);

    // Invoke factory processors registered as beans in the context.
    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) {
    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();
    }
    }
    }

    refresh 方法完成了 spring 容器初始化的操作。

  3. 我们先定位 IOC 容器部分,也就是执行 obtainFreshBeanFactory 方法过程

    1
    2
    3
    4
    5
    6
    7
    8
    protected ConfigurableListableBeanFactory obtainFreshBeanFactory() {
    refreshBeanFactory();
    ConfigurableListableBeanFactory beanFactory = getBeanFactory();
    if (logger.isDebugEnabled()) {
    logger.debug("Bean factory for " + getDisplayName() + ": " + beanFactory);
    }
    return beanFactory;
    }
  4. 继续跟踪 refreshBeanFactory()方法

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    protected final void refreshBeanFactory() throws BeansException {
    if (hasBeanFactory()) {
    destroyBeans();
    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);
    }
    }

    refreshBeanFactory 方法中首先判断容器是否存在,存在则销毁,然后创建一个新的 DefaultListableBeanFactory 对象来保存容器。

  5. 继续跟踪 loadBeanDefinitions 方法,加载 bean 定义规则

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    	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(this.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);
    }

    创建了一个 XmlBeanDefinitionReader 读取器

    beanDefinitionReader.setResourceLoader(this);指定了资源加载器为当前对象(父类 AbstractApplicationContext 继承了 DefaultResourceLoader,所以子类拥有资源加载的功能)

  6. 跟踪 loadBeanDefinitions 方法

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    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);
    }
    }



    public int loadBeanDefinitions(String location, Set<Resource> actualResources) throws BeanDefinitionStoreException {
    ResourceLoader resourceLoader = getResourceLoader();
    if (resourceLoader == null) {
    throw new BeanDefinitionStoreException(
    "Cannot import bean definitions from location [" + location + "]: no ResourceLoader available");
    }

    if (resourceLoader instanceof ResourcePatternResolver) {
    // Resource pattern matching available.
    try {
    Resource[] resources = ((ResourcePatternResolver) resourceLoader).getResources(location);
    int loadCount = loadBeanDefinitions(resources);
    if (actualResources != null) {
    for (Resource resource : resources) {
    actualResources.add(resource);
    }
    }
    if (logger.isDebugEnabled()) {
    logger.debug("Loaded " + loadCount + " bean definitions from location pattern [" + location + "]");
    }
    return loadCount;
    }
    catch (IOException ex) {
    throw new BeanDefinitionStoreException(
    "Could not resolve bean definition resource pattern [" + location + "]", ex);
    }
    }
    else {
    // Can only load single resources by absolute URL.
    Resource resource = resourceLoader.getResource(location);
    int loadCount = loadBeanDefinitions(resource);
    if (actualResources != null) {
    actualResources.add(resource);
    }
    if (logger.isDebugEnabled()) {
    logger.debug("Loaded " + loadCount + " bean definitions from location [" + location + "]");
    }
    return loadCount;
    }
    }

    可以看到通过上面定义的 resourceLoader 将资源文件转化成 Resource 对象

  7. 继续往下追踪 loadBeanDefinitions,最后调用 doLoadBeanDefinitions 方法

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    protected int doLoadBeanDefinitions(InputSource inputSource, Resource resource)
    throws BeanDefinitionStoreException {
    try {
    Document doc = doLoadDocument(inputSource, resource);
    return registerBeanDefinitions(doc, resource);
    }
    catch (BeanDefinitionStoreException ex) {
    throw ex;
    }

    }

    将资源文件转化成 Document 对象,然后开始在注册 beanDefinition

  8. 追踪 registerBeanDefinitions 方法

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    public int registerBeanDefinitions(Document doc, Resource resource) throws BeanDefinitionStoreException {
    BeanDefinitionDocumentReader documentReader = createBeanDefinitionDocumentReader();
    int countBefore = getRegistry().getBeanDefinitionCount();
    documentReader.registerBeanDefinitions(doc, createReaderContext(resource));
    return getRegistry().getBeanDefinitionCount() - countBefore;
    }

    protected void doRegisterBeanDefinitions(Element root) {
    // Any nested <beans> elements will cause recursion in this method. In
    // order to propagate and preserve <beans> default-* attributes correctly,
    // keep track of the current (parent) delegate, which may be null. Create
    // the new (child) delegate with a reference to the parent for fallback purposes,
    // then ultimately reset this.delegate back to its original (parent) reference.
    // this behavior emulates a stack of delegates without actually necessitating one.
    BeanDefinitionParserDelegate parent = this.delegate;
    this.delegate = createDelegate(getReaderContext(), root, parent);

    if (this.delegate.isDefaultNamespace(root)) {
    String profileSpec = root.getAttribute(PROFILE_ATTRIBUTE);
    if (StringUtils.hasText(profileSpec)) {
    String[] specifiedProfiles = StringUtils.tokenizeToStringArray(
    profileSpec, BeanDefinitionParserDelegate.MULTI_VALUE_ATTRIBUTE_DELIMITERS);
    if (!getReaderContext().getEnvironment().acceptsProfiles(specifiedProfiles)) {
    if (logger.isInfoEnabled()) {
    logger.info("Skipped XML bean definition file due to specified profiles [" + profileSpec +
    "] not matching: " + getReaderContext().getResource());
    }
    return;
    }
    }
    }

    preProcessXml(root);
    parseBeanDefinitions(root, this.delegate);
    postProcessXml(root);

    this.delegate = parent;
    }
  9. 追踪 parseBeanDefinitions 方法,继续往下,调用 processBeanDefinition 方法

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    protected void processBeanDefinition(Element ele, BeanDefinitionParserDelegate delegate) {
    BeanDefinitionHolder bdHolder = delegate.parseBeanDefinitionElement(ele);
    if (bdHolder != null) {
    bdHolder = delegate.decorateBeanDefinitionIfRequired(ele, bdHolder);
    try {
    // Register the final decorated instance.
    BeanDefinitionReaderUtils.registerBeanDefinition(bdHolder, getReaderContext().getRegistry());
    }
    catch (BeanDefinitionStoreException ex) {
    getReaderContext().error("Failed to register bean definition with name '" +
    bdHolder.getBeanName() + "'", ele, ex);
    }
    // Send registration event.
    getReaderContext().fireComponentRegistered(new BeanComponentDefinition(bdHolder));
    }
    }

    我们可以发现委托 BeanDefinitionParserDelegate 将 Element 元素转化成了 BeanDifinitionHolder 对象,然后通过 BeanDefinitionReaderUtils.registerBeanDefinition 将 bean 放入到容器 DefaultListableBeanFactory 对象的 beanDefinitionMap 中

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    public static void registerBeanDefinition(
    BeanDefinitionHolder definitionHolder, BeanDefinitionRegistry registry)
    throws BeanDefinitionStoreException {

    // Register bean definition under primary name.
    String beanName = definitionHolder.getBeanName();
    registry.registerBeanDefinition(beanName, definitionHolder.getBeanDefinition());

    // Register aliases for bean name, if any.
    String[] aliases = definitionHolder.getAliases();
    if (aliases != null) {
    for (String alias : aliases) {
    registry.registerAlias(beanName, alias);
    }
    }
    }