基于XML的IOC容器初始化以及循环依赖问题——Spring中的refresh()方法

基于XML的IOC容器初始化以及循环依赖问题——Spring中的refresh()方法

1,找到入口

我们首先找到测试的入口来一探究竟,相信下面这段代码大家都写过:

@Test
public void test01() {
    // 入口
    ApplicationContext applicationContext = new ClassPathXmlApplicationContext("bean.xml");
    TestService bean = applicationContext.getBean(TestService.class);
    bean.test();
}

我们先来看一下 ClassPathXmlApplicationContext的所处的体系:

在这里插入图片描述

ApplicationContext 允许上下文嵌套,通过保持父上下文可以维持一个上下文体系。对于 Bean 的查找可以在这个上下文体系中发生,首先检查当前上下文,其次是父上下文,逐级向上,这样为不同的 Spring 应用提供了一个共享的 Bean 定义环境。

首先根据上面的代码点进来:

public ClassPathXmlApplicationContext(String configLocation) throws BeansException {
   this(new String[] {configLocation}, true, null);
}

其实际调用的构造函数为:

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

   super(parent);// 位置1
   setConfigLocations(configLocations);
   if (refresh) {
      refresh();
   }
}

实际上,xml应用中正是通过这个构造方法进行的IOC初始化过程。

2,准备工作

通过分析ClassPathXmlApplicationContext的源代码可以知道,在创建ClassPathXmlApplicationContext容器时,构造方法首先做了以下两项工作

2.1. 配置Bean资源加载器

从上面代码的位置1看进去,结合类图看一下以下代码,可以发现其层层调用父类的构造方法,直到AbstractApplicationContext。

// AbstractXmlApplicationContext中
public AbstractXmlApplicationContext(@Nullable ApplicationContext parent) {
   super(parent);
}
// AbstractRefreshableConfigApplicationContext中
public AbstractRefreshableConfigApplicationContext(@Nullable ApplicationContext parent) {
	super(parent);
}
// AbstractRefreshableApplicationContext
public AbstractRefreshableApplicationContext(@Nullable ApplicationContext parent) {
    super(parent);
}
// AbstractApplicationContext
public AbstractApplicationContext(@Nullable ApplicationContext parent) {
    this(); // 位置1
    setParent(parent);
}

接下来我们点进去上面位置1的代码,如下所示

public AbstractApplicationContext() {
   this.resourcePatternResolver = getResourcePatternResolver(); 
}
// 设置资源加载器
protected ResourcePatternResolver getResourcePatternResolver() {
    return new PathMatchingResourcePatternResolver(this);//位置1
}
// AbstractApplicationContext这里其实也是一个资源加载器
public abstract class AbstractApplicationContext extends DefaultResourceLoader ....

这里可以看到,位置1处, AbstractApplicationContext将自己设置为了Bean资源加载器并返回。

因此ClassPathXmlApplicationContext中super(parent);这行代码的目的就是为容器设置好Bean资源加载器(AbstractApplicationContext)。

2.2 设置配置信息

有了加载器,那么肯定就还需要加载器所加载的配置文件信息,setConfigLocations(configLocations);这行代码,目的就是对Bean配置信息进行定位。

// AbstractRefreshableConfigApplicationContext中的方法
public void setConfigLocations(@Nullable String... locations) {
   if (locations != null) {
      Assert.noNullElements(locations, "Config locations must not be null");
      this.configLocations = new String[locations.length];
      for (int i = 0; i < locations.length; i++) {
         this.configLocations[i] = resolvePath(locations[i]).trim();
      }
   }
   else {
      this.configLocations = null;
   }
}

通过以上代码我们也可以看出,我们即可以使用一个字符串来配置多个Spring Bean配置信息,也可以使用字符串数组,即下面两种方式都可以:

ClassPathResource res = new ClassPathResource("a.xml,b.xml");
ClassPathResource res =new ClassPathResource(new String[]{"a.xml","b.xml"});
3,开始启动

SpringIOC 容器对 Bean 配置资源的载入是从 refresh()函数开始的,ClassPathXmlApplicationContext 通过调用其父类 AbstractApplicationContext 的 refresh()函数启动整个 IOC 容器对 Bean 定义的载入过程,现在我们来详细看看 refresh()中的逻辑处理:

@Override
public void refresh() throws BeansException, IllegalStateException {
   synchronized (this.startupShutdownMonitor) {
      StartupStep contextRefresh = this.applicationStartup.start("spring.context.refresh");

      // 调用容器准备刷新的方法,获取容器的当时时间,同时给容器设置同步标识
      prepareRefresh();

      // 载入 位置1
      ConfigurableListableBeanFactory beanFactory = obtainFreshBeanFactory();

      // 为 BeanFactory 配置容器特性,例如类加载器、事件处理器等
      prepareBeanFactory(beanFactory);

      ...
   }
}

我们说的载入过程,其实就是从obtainFreshBeanFactory();(位置1)这个地方开始的

refresh()方法的主要作用是:在创建 IOC 容器前,如果已经有容器存在,则需要把已有的容器销毁和 关闭,以保证在 refresh 之后使用的是新建立起来的 IOC 容器。它类似于对 IOC 容器的重启,在新建立 好的容器中对容器进行初始化,对 Bean 配置资源进行载入。

4,载入

obtainFreshBeanFactory()方法调用子类容器【AbstractApplicationContext】的 refreshBeanFactory()方法,启动容器载入 Bean 配置信息的过程,代码如下:

// AbstractApplicationContext
protected ConfigurableListableBeanFactory obtainFreshBeanFactory() {
   refreshBeanFactory();
   return getBeanFactory();
}
// 抽象方法
protected abstract void refreshBeanFactory() throws BeansException, IllegalStateException;

AbstractApplicationContext 类中只抽象定义了 refreshBeanFactory()方法,容器真正调用的是其子类 AbstractRefreshableApplicationContext 实现的 refreshBeanFactory()方法,方法的源码如下:

@Override
protected final void refreshBeanFactory() throws BeansException {
   if (hasBeanFactory()) { // 位置1
      destroyBeans();
      closeBeanFactory();
   }
   try {
      DefaultListableBeanFactory beanFactory = createBeanFactory();// 位置2
      beanFactory.setSerializationId(getId());
      customizeBeanFactory(beanFactory);
      loadBeanDefinitions(beanFactory);// 位置3
      this.beanFactory = beanFactory;
   }
   catch (IOException ex) { ... }
}

在这个方法中,首先判断BeanFactory是否存在,如果存在则先销毁beans并关闭beanFactory(位置1),接着创建DefaultListableBeanFactory(位置2),并调用loadBeanDefinitions(beanFactory)方法装载bean定义(位置3)。重点是位置3的装载bean定义的调用。

5,配置资源读取器

我们从4步骤中的位置3点进去:

// AbstractRefreshableApplicationContext 抽象方法
protected abstract void loadBeanDefinitions(DefaultListableBeanFactory beanFactory)
			throws BeansException, IOException;
// AbstractXmlApplicationContext具体实现
@Override
protected void loadBeanDefinitions(DefaultListableBeanFactory beanFactory) throws BeansException, IOException {
   // 创建一个XmlBeanDefinitionReader读取Bean配置资源
   XmlBeanDefinitionReader beanDefinitionReader = new XmlBeanDefinitionReader(beanFactory);

   beanDefinitionReader.setEnvironment(this.getEnvironment());
   beanDefinitionReader.setResourceLoader(this);
   beanDefinitionReader.setEntityResolver(new ResourceEntityResolver(this));

   // 位置1
   initBeanDefinitionReader(beanDefinitionReader);
   loadBeanDefinitions(beanDefinitionReader);
}

该步骤的目的主要是使用我们定义的XML资源读取器(XmlBeanDefinitionReader)去加载配置资源。

6,处理文件并加载

从上步骤代码的位置1点进去,最终我们可以看到如下代码:

public int loadBeanDefinitions(String location, @Nullable Set<Resource> actualResources) throws BeanDefinitionStoreException {
   ResourceLoader resourceLoader = getResourceLoader();
   if (resourceLoader == null) {
      throw new BeanDefinitionStoreException("...");
   }
   if (resourceLoader instanceof ResourcePatternResolver) {
      try {
         Resource[] resources = ((ResourcePatternResolver) resourceLoader).getResources(location);// 位置1
         int count = loadBeanDefinitions(resources); // 位置2
         ...
   }
}

在该处我们可以看到程序就做了两件事:

  1. 位置1调用资源加载器的获取资源方法 resourceLoader.getResource(location),获取到要加载的资源

    其实就是 XmlBeanDefinitionReader 通过调用ClassPathXmlApplicationContext的父类DefaultResourceLoader的getResource()方法获取要加载的资源。

  2. 位置2加载bean定义

    在下个步骤中详细解释

总结一下这个流程的目的:寻找要加载资源的位置并加载。

7,读取配置内容

继续上个环节的位置2处的代码:loadBeanDefinitions(resources)。

该处的主要目的是加载Bean定义,通过点进去几层,我们最终来到了XmlBeanDefinitionsReader的这个位置:

protected int doLoadBeanDefinitions(InputSource inputSource, Resource resource)
      throws BeanDefinitionStoreException {

   try {
      Document doc = doLoadDocument(inputSource, resource);// 位置1
      int count = registerBeanDefinitions(doc, resource);// 位置2
      if (logger.isDebugEnabled()) {
         logger.debug("Loaded " + count + " bean definitions from " + resource);
      }
      return count;
   }
   catch (BeanDefinitionStoreException ex) {...}
}

这一步的目的是:将配置文件解析为文档对象注册Bean定义

  • 解析文档对象

    位置1看进去,最终会来到 DefaultDocumentLoaderloadDocument() 方法:

    @Override
    public Document loadDocument(InputSource inputSource, EntityResolver entityResolver,
          ErrorHandler errorHandler, int validationMode, boolean namespaceAware) throws Exception {
    
       DocumentBuilderFactory factory = createDocumentBuilderFactory(validationMode, namespaceAware);
       if (logger.isTraceEnabled()) {
          logger.trace("Using JAXP provider [" + factory.getClass().getName() + "]");
       }
       DocumentBuilder builder = createDocumentBuilder(factory, entityResolver, errorHandler);
       return builder.parse(inputSource);
    }
    

    通过这个操作,Spring就完成了将配置文件转换成为了Document对象的过程。

  • 注册Bean定义

    接下来的步骤将会解释如何将Document对象解析为SpringIOC容器管理的Bean对象,并注册到容器中的。

8,创建 BeanDefinitionDocumentReader 解析资源

XmlBeanDefinitionReader 类中的 doLoadBeanDIfinition()(上步骤的)方法是从特定的XML文件中实际载入Bean配置资源的方法,该方法在载入Bean配置资源之后将其转换为Document对象,接下来调用registerBeanDefinitions() 启动SpringIOC容器对Bean定义的解析过程,registerBeanDefinitions()方法的源码如下:

public int registerBeanDefinitions(Document doc, Resource resource) throws BeanDefinitionStoreException {
    // 创建BeanDefinitionDocumentReader解析doc
   BeanDefinitionDocumentReader documentReader = createBeanDefinitionDocumentReader();
   int countBefore = getRegistry().getBeanDefinitionCount();
   // 具体的解析实现过程 位置1
   documentReader.registerBeanDefinitions(doc, createReaderContext(resource));
   return getRegistry().getBeanDefinitionCount() - countBefore;
}

Bean配置资源的载入解析分为以下两个过程:

  • 首先通过调用xml解析器将Bean配置信息转换得到Document对象,但是这些Document对象并没有按照Spring的Bean规则进行解析

  • 其次,在完成XML解析之后,按照SpringBean的定义规则对Document对象进行解析,其解析过程是在接口 BeanDefinitionDocumentReader 的实现类 DefaultBeanDefinitionDocumentReader 中实现位置1)。

9,解析Document对象

BeanDefinitionDocumentReader 接口通过 registerBeanDefinitions() 方法调用其实现类 DefaultBeanDefinitionDocumentReader 对 Document 对象进行解析,代码如下:

// 解析Document对象
@Override
public void registerBeanDefinitions(Document doc, XmlReaderContext readerContext) {
   this.readerContext = readerContext;
   doRegisterBeanDefinitions(doc.getDocumentElement());
}

protected void doRegisterBeanDefinitions(Element root) {
    //具体的解析过程由 BeanDefinitionParserDelegate 实现, 	
    //BeanDefinitionParserDelegate 中定义了 Spring Bean 定义 XML 文件的各种元素
    BeanDefinitionParserDelegate parent = this.delegate;
    //创建 BeanDefinitionParserDelegate,用于完成真正的解析过程
    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.isDebugEnabled()) { ... }
                return;
            }
        }
    }
	// 在解析Bean定义之前,进行自定义的解析,增强解析过程的可扩展性
    preProcessXml(root); 
    // 从Document的根元素开始解析Bean定义的Document对象  位置1
    parseBeanDefinitions(root, this.delegate);
    // 在解析Bean定义之后,进行自定义的解析,增加解析过程的可扩展性
    postProcessXml(root);
    this.delegate = parent;
}

虽然解析的过程是由DefaultBeanDefinitionDocumentReader 调用,但是实际的解析过程则是由 BeanDefinitionParserDelegate 来完成(位置1)。

10,开始解析

接上步骤中的位置1:由 BeanDefinitionParserDelegate 来完成Document的解析过程,代码如下:

protected void parseBeanDefinitions(Element root, BeanDefinitionParserDelegate delegate) {
   if (delegate.isDefaultNamespace(root)) {
      // 获取Bean定义的Document对象根元素的所有字节点
      NodeList nl = root.getChildNodes();
      for (int i = 0; i < nl.getLength(); i++) {
         Node node = nl.item(i);
         if (node instanceof Element) {
            Element ele = (Element) node;
            if (delegate.isDefaultNamespace(ele)) {
               // //使用 Spring 的 Bean 规则解析元素节点 位置1
               parseDefaultElement(ele, delegate);
            }
            else {
               delegate.parseCustomElement(ele);
            }
         }
      }
   }
   else {
      delegate.parseCustomElement(root);
   }
}

位置1进去,代码如下:

private void parseDefaultElement(Element ele, BeanDefinitionParserDelegate delegate) {
   // 如果元素时<Import> 导入元素,进行导入解析
   if (delegate.nodeNameEquals(ele, IMPORT_ELEMENT)) {
      importBeanDefinitionResource(ele);
   }
   // 如果元素时<Alias> 导入元素,进行别名解析
   else if (delegate.nodeNameEquals(ele, ALIAS_ELEMENT)) {
      processAliasRegistration(ele);
   }
   //元素节点既不是导入元素,也不是别名元素,即普通的<Bean>元素, 	   
   //按照 Spring 的 Bean 规则解析元素
   else if (delegate.nodeNameEquals(ele, BEAN_ELEMENT)) {
      processBeanDefinition(ele, delegate);// 位置1
   }
   else if (delegate.nodeNameEquals(ele, NESTED_BEANS_ELEMENT)) {
      doRegisterBeanDefinitions(ele);
   }
}

可以看到,代码中根据标签类型,对标签内的元素进行解析。下面将以标签为例,一起来看一下是如何载入的。

11,加载Bean

上步骤的位置1点进来,记住这个位置,稍后我们还会回来:

protected void processBeanDefinition(Element ele, BeanDefinitionParserDelegate delegate) {
   	// 第一行 位置1 
    BeanDefinitionHolder bdHolder = delegate.parseBeanDefinitionElement(ele);
    ...
}

我们这里只看该方法的第一行:

public BeanDefinitionHolder parseBeanDefinitionElement(Element ele) {
   return parseBeanDefinitionElement(ele, null);
}

再进来就是解析bean标签的核心方法了,这个方法主要处理bean元素的id,nam和别名属性:

public BeanDefinitionHolder parseBeanDefinitionElement(Element ele, @Nullable BeanDefinition containingBean) {
    // 获取bean元素中的id属性
    String id = ele.getAttribute(ID_ATTRIBUTE);
    // 读取bean元素中的属性值
    String nameAttr = ele.getAttribute(NAME_ATTRIBUTE);
    // 新建集合存储别名,如果配置了别名就尝试获取
    List<String> aliases = new ArrayList<>()if (StringUtils.hasLength(nameAttr)) {
            String[] nameArr = StringUtils.tokenizeToStringArray(nameAttr, MULTI_VALUE_ATTRIBUTE_DELIMITERS);
            aliases.addAll(Arrays.asList(nameArr));
        }
	
    String beanName = id;
    // 如果 bean元素中没有设置id属性时,将别名中第一个值赋值给beanName
    if (!StringUtils.hasText(beanName) && !aliases.isEmpty()) {
        beanName = aliases.remove(0);
        if (logger.isTraceEnabled()) {...}
    }
    
    if (containingBean == null) {
        // 检查bean元素所配置id、name或别名是否重复
        checkNameUniqueness(beanName, aliases, ele);
    }
	// 详细对bean元素中配置的bean定义进行解析的地方 位置1
    AbstractBeanDefinition beanDefinition = parseBeanDefinitionElement(ele, beanName, containingBean);
    if (beanDefinition != null) {
        if (!StringUtils.hasText(beanName)) {
            try {
                if (containingBean != null) {
                    //如果<Bean>元素中没有配置 id、别名或者 name,且没有包含子元素 			 		
                    //<Bean>元素,为解析的 Bean 生成一个唯一 beanName 并注册
                    beanName = BeanDefinitionReaderUtils.generateBeanName(
                        beanDefinition, this.readerContext.getRegistry(), true);
                }
                else {
                    //如果<Bean>元素中没有配置 id、别名或者 name,且包含了子元素 						
                    //<Bean>元素,为解析的 Bean 使用别名向 IOC 容器注册
                    beanName = this.readerContext.generateBeanName(beanDefinition);

                    String beanClassName = beanDefinition.getBeanClassName();
                    if (beanClassName != null &&
                        beanName.startsWith(beanClassName) && beanName.length() > beanClassName.length() &&
                        !this.readerContext.getRegistry().isBeanNameInUse(beanClassName)) {
                        aliases.add(beanClassName);
                    }
                }
                if (logger.isTraceEnabled()) {
                    ...
                }
            }
            catch (Exception ex) {
                error(ex.getMessage(), ele);
                return null;
            }
        }
        String[] aliasesArray = StringUtils.toStringArray(aliases);
        return new BeanDefinitionHolder(beanDefinition, beanName, aliasesArray);
    }

    return null;
}

截止到这里,Spring已经完成了对id,name属性的解析,bean中详细内容的解析就交由 parseBeanDefinitionElement()这个方法来完成位置1),接下来我们一起看一下这个方法的源码:

@Nullable
public AbstractBeanDefinition parseBeanDefinitionElement(
      Element ele, String beanName, @Nullable BeanDefinition containingBean) {
	// 记录要解析的bean
    this.parseState.push(new BeanEntry(beanName));
	// 记录 class 属性的内容 如:com.xx.pojo.Person
    String className = null;
    if (ele.hasAttribute(CLASS_ATTRIBUTE)) {
        className = ele.getAttribute(CLASS_ATTRIBUTE).trim();
    }
    // 如果bean标签中配置了parent属性,那么就记录
    String parent = null;
    if (ele.hasAttribute(PARENT_ATTRIBUTE)) {
        parent = ele.getAttribute(PARENT_ATTRIBUTE);
    }

    try {
        /* 根据bean元素配置的class名称和parent属性值创建BeanDefinition
        为载入Bean定义信息做准备*/
        AbstractBeanDefinition bd = createBeanDefinition(className, parent);
		// 对当前的bean元祖中配置的一些属性进行解析和设置
        // 如配置的单例属性(Singleton)等
        parseBeanDefinitionAttributes(ele, beanName, containingBean, bd);
        // 为bean元素解析的bean设置 description 标签信息
       	bd.setDescription(DomUtils.getChildElementValueByTagName(ele, DESCRIPTION_ELEMENT));
		// 对bean元素的元信息属性解析
        parseMetaElements(ele, bd);
        // 解析lookup-method属性和replaced-method
        parseLookupOverrideSubElements(ele, bd.getMethodOverrides());
        parseReplacedMethodSubElements(ele, bd.getMethodOverrides());
		// 解析构造方法
        parseConstructorArgElements(ele, bd);
        // 解析property标签
        parsePropertyElements(ele, bd);// 位置1
        // 解析bean元素的 qualifier 标签
        parseQualifierElements(ele, bd);
		
        bd.setResource(this.readerContext.getResource());
        bd.setSource(extractSource(ele));

        return bd;
    }
    catch (ClassNotFoundException ex) {
        ...
    }
    finally {
        this.parseState.pop();
    }

    return null;
}

只要对配置文件比较熟悉,通过以上代码的分析,就会明白我们再Spring配置文件中bean元素中配置的属性就是通过该方法解析和设置到Bean中去的。

注意在解析bean元素过程中并没有创建和实例化Bean对象,只是创建了Bean对象的定义类BeanDefiniton,将bean元素中的配置信息设置到BeanDefinition中作为记录,当依赖注入时才使用这些记录信息创建和实例化具体的Bean对象

我们再使用bean标签进行配置时,使用最多的就是property,接下来我们一起看一下property标签是如何配置的(代码位置1)。

12,载入property标签元素

BeanDefinitionParserDelegate 在解析bean时调用parsePropertyElements()方法来完成对property标签的解析(上步骤代码位置1)。源码如下:

public void parsePropertyElements(Element beanEle, BeanDefinition bd) {
    // 获取bean元素中所有子元素
    NodeList nl = beanEle.getChildNodes();
    for (int i = 0; i < nl.getLength(); i++) {
        Node node = nl.item(i);
        // 如果子元素是property元素,则调用解析方法解析
        if (isCandidateElement(node) && nodeNameEquals(node, PROPERTY_ELEMENT)) {
            parsePropertyElement((Element) node, bd);// 位置1
        }
    }
}

这里可以看到,加载流程为:首先获取该bean标签中所有的元素,如果元素是property,则调用解析方法解析该标签:

// 解析 property
public void parsePropertyElement(Element ele, BeanDefinition bd) {
    String propertyName = ele.getAttribute(NAME_ATTRIBUTE);
    if (!StringUtils.hasLength(propertyName)) {
        error("Tag 'property' must have a 'name' attribute", ele);
        return;
    }
    this.parseState.push(new PropertyEntry(propertyName));
    try {
        if (bd.getPropertyValues().contains(propertyName)) {
            error("Multiple 'property' definitions for property '" + propertyName + "'", ele);
            return;
        }
        // 解析获取property的值
        Object val = parsePropertyValue(ele, bd, propertyName);
        // 根据property的名字和值创建property实例
        PropertyValue pv = new PropertyValue(propertyName, val);
        // 解析property标签内的属性
        parseMetaElements(ele, pv);
        pv.setSource(extractSource(ele));
        bd.getPropertyValues().addPropertyValue(pv);
    }
    finally {
        this.parseState.pop();
    }
}

这里就不详细往里看了,时间有限…

4-12步总结:

经过4-12步的介绍,我们有了一个清晰的脉络:

  1. 首先bean.xml文件会首先被我们所配置的资源加载器加载【ClassPathXmlApplicationContext】
  2. 接着由我们配置的资源读取器【XmlBeanDefinitionReader】,加载我们所配置的配置文件
  3. 由【DefaultBeanDefinitionDocumentReader 】将我们配置的资源解析为Document对象
  4. 由【BeanDefinitionParserDelegate 】来完成Document的解析过程
  5. 最终我们将xml中的配置信息转换成了Spring IOC所识别的数据结构——BeanDefinition

通过这几步对配置资源的解析后,IOC容器大致完成了管理bean对象的准备工作,即初始化过程,但是最重要的依赖注入等操作还没有发生,现在在IOC容器中BeanDefinition存储的只是一些静态信息,接下来需要向容器中注册Bean的定义信息才能全部完成IOC容器的初始化过程。

13,让我们回到11步

从上面的流程中我们知道,Spring在11-12步中,完成了对配置文件的加载工作,并将Bean配置信息成功转换为了BeanDefinition,接下来 BeanDefinitionParserDelegate 将分封装了 BeanDefinition 的BeanDefinitionHold对象返回

// DefaultBeanDefinitionDocumentReader中的processBeanDefinition方法
protected void processBeanDefinition(Element ele, BeanDefinitionParserDelegate delegate) {
    // 11步中的位置1
    BeanDefinitionHolder bdHolder = delegate.parseBeanDefinitionElement(ele);
    if (bdHolder != null) {
        bdHolder = delegate.decorateBeanDefinitionIfRequired(ele, bdHolder);
        try {
            // 向容器中注册解析的 Bean 位置1
    		BeanDefinitionReaderUtils.registerBeanDefinition(bdHolder, getReaderContext().getRegistry());
        }
        catch (BeanDefinitionStoreException ex) {
            ...
        }
        // Send registration event.
        getReaderContext().fireComponentRegistered(new BeanComponentDefinition(bdHolder));
    }
}

来看代码的位置1,由 BeanDefinitionReaderUtils 的 registerBeanDefinition() 方法向IOC容器中注册解析的 Bean。

14,注册Bean

上步骤中的位置1点进去,

public static void registerBeanDefinition(
    BeanDefinitionHolder definitionHolder, BeanDefinitionRegistry registry)
    throws BeanDefinitionStoreException {

    // 获取解析的BeanDefinition的名称
    String beanName = definitionHolder.getBeanName();
    // 向容器中注册 位置1
    registry.registerBeanDefinition(beanName, definitionHolder.getBeanDefinition());

    // 如果解析的BeanDefinition有别名,则注册别名
    String[] aliases = definitionHolder.getAliases();
    if (aliases != null) {
        for (String alias : aliases) {
            registry.registerAlias(beanName, alias);
        }
    }
}

当 BeanDefinitionReaderUtils 调用 registerBeanDefinition() 方法时,真正完成注册操作的是 DefaultListableBeanFactory 接下来我们一起看进去(位置1):

// DefaultListableBeanFactory 解析注册Bean
public void registerBeanDefinition(String beanName, BeanDefinition beanDefinition)
      throws BeanDefinitionStoreException {

    Assert.hasText(beanName, "Bean name must not be empty");
    Assert.notNull(beanDefinition, "BeanDefinition must not be null");

    if (beanDefinition instanceof AbstractBeanDefinition) {
        try {
            ((AbstractBeanDefinition) beanDefinition).validate();
        }
        catch (BeanDefinitionValidationException ex) {
            throw new BeanDefinitionStoreException(...);
        }
    }

    BeanDefinition existingDefinition = this.beanDefinitionMap.get(beanName);
    if (existingDefinition != null) {
        if (!isAllowBeanDefinitionOverriding()) {
            throw new BeanDefinitionOverrideException(beanName, beanDefinition, existingDefinition);
        }
        else if (existingDefinition.getRole() < beanDefinition.getRole()) {
            if (logger.isInfoEnabled()) {
                ...
            }
        }
        else if (!beanDefinition.equals(existingDefinition)) {
            if (logger.isDebugEnabled()) {
                ...
            }
        }
        else {
            if (logger.isTraceEnabled()) {
                ...
            }
        }
        this.beanDefinitionMap.put(beanName, beanDefinition);
    }
    else {
        if (hasBeanCreationStarted()) {
            synchronized (this.beanDefinitionMap) {
                this.beanDefinitionMap.put(beanName, beanDefinition);
                List<String> updatedDefinitions = new ArrayList<>(this.beanDefinitionNames.size() + 1);
                updatedDefinitions.addAll(this.beanDefinitionNames);
                updatedDefinitions.add(beanName);
                this.beanDefinitionNames = updatedDefinitions;
                removeManualSingletonName(beanName);
            }
        }
        else {
            // 位置1
            this.beanDefinitionMap.put(beanName, beanDefinition);
            this.beanDefinitionNames.add(beanName);
            removeManualSingletonName(beanName);
        }
        this.frozenBeanDefinitionNames = null;
    }

    if (existingDefinition != null || containsSingleton(beanName)) {
        resetBeanDefinition(beanName);
    }
    else if (isConfigurationFrozen()) {
        clearByTypeCache();
    }
}

这个方法很长,简而言之就是做了一件事: 使用一个ConcurrentHashMap(this.beanDefinitionMap)的集合对象存放IOC容器解析的BeanDefinition(位置1)。

小总结:

至此,Bean配置信息中配置的Bean就被解析完成,且注册到IOC容器中,被容器管理起来,真正完成了IOC容器初始化所做的全部工作。现在IOC容器中已经建立了整个Bean的配置信息,这些BeanDefinition信息已经可以使用,并可以被检索,IOC容器的作用就是对这些注册的Bean定义信息进行维护和处理。这些注册的Bean定义信息是IOC容器控制反转的基础,正式有了这些注册的数据,容器才可以进行依赖注入。

15,Bean初始化之前的准备工作

描述请看代码

@Override
public void refresh() throws BeansException, IllegalStateException {
    synchronized (this.startupShutdownMonitor) {
        StartupStep contextRefresh = this.applicationStartup.start("spring.context.refresh");
        // 准备工作
        prepareRefresh();
		// 将xml解析为 BeanDefinition 获取BeanFactory
        ConfigurableListableBeanFactory beanFactory = obtainFreshBeanFactory();
        /*
        	准备工作:设置BeanFactory的类加载器、支持表达式解析器、
        		添加部分BeanFactoryProcessor等
        */
        prepareBeanFactory(beanFactory);
		
        try {
            // 模板方法:准备工作完成后的后置处理工作
            postProcessBeanFactory(beanFactory);

            StartupStep beanPostProcess = this.applicationStartup.start("spring.context.beans.post-process");
            // 调用Bean工厂后置处理器
            invokeBeanFactoryPostProcessors(beanFactory);
			// 注册Bean的后置处理器
            registerBeanPostProcessors(beanFactory);
            beanPostProcess.end();
			// 初始化MessageSource组件(做国际化功能)
            initMessageSource();
			// 初始化事件派发器
            initApplicationEventMulticaster();
			
            onRefresh();
			// 注册监听器
            registerListeners();
			
            // 初始化单例Bean 位置1
            finishBeanFactoryInitialization(beanFactory);
			
            finishRefresh();
        }

        catch (BeansException ex) {
            if (logger.isWarnEnabled()) {
                ...
            }
            
            destroyBeans();

            cancelRefresh(ex);

            throw ex;
        }

        finally {
            resetCommonCaches();
            contextRefresh.end();
        }
    }
}
16,初始化单实例Bean

我们来一起看一下上步骤中的位置1,在finishBeanFactoryInitialization(beanFactory)方法中,会完成初始化单例Bean的工作,我们来一起看一下源码:

protected void finishBeanFactoryInitialization(ConfigurableListableBeanFactory beanFactory) {
    ...
    // 实例化所有剩余的单例Bean 位置1
    beanFactory.preInstantiateSingletons();
}

这里我们只看最后一行代码:beanFactory.preInstantiateSingletons();

该方法使用DefaultListableBeanFactory的preInstantiateSingletons()方法进行Bean的初始化工作:

@Override
public void preInstantiateSingletons() throws BeansException {
    if (logger.isTraceEnabled()) {
        logger.trace("Pre-instantiating singletons in " + this);
    }

    List<String> beanNames = new ArrayList<>(this.beanDefinitionNames);

    // Trigger initialization of all non-lazy singleton beans...
    for (String beanName : beanNames) {
        RootBeanDefinition bd = getMergedLocalBeanDefinition(beanName);
        if (!bd.isAbstract() && bd.isSingleton() && !bd.isLazyInit()) {
            if (isFactoryBean(beanName)) {
                Object bean = getBean(FACTORY_BEAN_PREFIX + beanName);
                if (bean instanceof FactoryBean) {
                    FactoryBean<?> factory = (FactoryBean<?>) bean;
                    boolean isEagerInit;
                    if (System.getSecurityManager() != null && factory instanceof SmartFactoryBean) {
                        isEagerInit = AccessController.doPrivileged(
                            (PrivilegedAction<Boolean>) ((SmartFactoryBean<?>) factory)::isEagerInit,
                            getAccessControlContext());
                    }
                    else {
                        isEagerInit = (factory instanceof SmartFactoryBean &&
                                       ((SmartFactoryBean<?>) factory).isEagerInit());
                    }
                    if (isEagerInit) {
                        getBean(beanName);
                    }
                }
            }
            else {
                getBean(beanName);//位置1
            }
        }
    ...
}

可以看到在该方法中获取了Bean的定义信息并加载bean:

@Override
public Object getBean(String name) throws BeansException {
    return doGetBean(name, null, null, false);
}
// getBean调用doGetBean
protected <T> T doGetBean(
    String name, @Nullable Class<T> requiredType, @Nullable Object[] args, boolean typeCheckOnly)
    throws BeansException {

    String beanName = transformedBeanName(name);
    Object beanInstance;

    // 1,先获取缓存中保存的单实例Bean,如果能获取到
    // 说明这个Bean之前被创建过
    Object sharedInstance = getSingleton(beanName);
    // 2,缓存中没有拿到
    if (sharedInstance != null && args == null) {
        if (logger.isTraceEnabled()) {
            if (isSingletonCurrentlyInCreation(beanName)) {
                logger.trace("...");
            }
            else {
                logger.trace("...");
            }
        }
        beanInstance = getObjectForBeanInstance(sharedInstance, name, beanName, null);
    }

    else {
        if (isPrototypeCurrentlyInCreation(beanName)) {
            throw new BeanCurrentlyInCreationException(beanName);
        }

        BeanFactory parentBeanFactory = getParentBeanFactory();
        if (parentBeanFactory != null && !containsBeanDefinition(beanName)) {
            String nameToLookup = originalBeanName(name);
            if (parentBeanFactory instanceof AbstractBeanFactory) {
                return ((AbstractBeanFactory) parentBeanFactory).doGetBean(
                    nameToLookup, requiredType, args, typeCheckOnly);
            }
            else if (args != null) {
                return (T) parentBeanFactory.getBean(nameToLookup, args);
            }
            else if (requiredType != null) {
                return parentBeanFactory.getBean(nameToLookup, requiredType);
            }
            else {
                return (T) parentBeanFactory.getBean(nameToLookup);
            }
        }
		// 3,标记当前Bean已经被创建
        if (!typeCheckOnly) {
            markBeanAsCreated(beanName);
        }
		
        StartupStep beanCreation = this.applicationStartup.start("spring.beans.instantiate")
            .tag("beanName", name);
        try {
            if (requiredType != null) {
                beanCreation.tag("beanType", requiredType::toString);
            }
            // 4,获取Bean的定义信息
            RootBeanDefinition mbd = getMergedLocalBeanDefinition(beanName);
            checkMergedBeanDefinition(mbd, beanName, args);

            //,5,获取当前Bean依赖的其他Bean
            // 如果有依赖其他bean,则通过getBean获取
            String[] dependsOn = mbd.getDependsOn();
            if (dependsOn != null) {
                for (String dep : dependsOn) {
                    if (isDependent(beanName, dep)) {
                        throw new ...
                    }
                    registerDependentBean(dep, beanName);
                    try {
                        // 如果有则通过getBean获取
                        getBean(dep);
                    }
                    catch (NoSuchBeanDefinitionException ex) {
                        ...
                    }
                }
            }

            // 6, 启动创建Bean的流程
            if (mbd.isSingleton()) {
                sharedInstance = getSingleton(beanName, () -> {
                    try {
                        return createBean(beanName, mbd, args);
                    }
                    catch (BeansException ex) {
                        destroySingleton(beanName);
                        throw ex;
                    }
                });
                beanInstance = getObjectForBeanInstance(sharedInstance, name, beanName, mbd);
            }

            else if (mbd.isPrototype()) {
                // It's a prototype -> create a new instance.
                Object prototypeInstance = null;
                try {
                    beforePrototypeCreation(beanName);
                    prototypeInstance = createBean(beanName, mbd, args);
                }
                finally {
                    afterPrototypeCreation(beanName);
                }
                beanInstance = getObjectForBeanInstance(prototypeInstance, name, beanName, mbd);
            }

            else {
                String scopeName = mbd.getScope();
                if (!StringUtils.hasLength(scopeName)) {
                    throw new ...
                }
                Scope scope = this.scopes.get(scopeName);
                if (scope == null) {
                    throw new ...
                }
                try {
                    Object scopedInstance = scope.get(beanName, () -> {
                        beforePrototypeCreation(beanName);
                        try {
                            return createBean(beanName, mbd, args);
                        }
                        finally {
                            afterPrototypeCreation(beanName);
                        }
                    });
                    beanInstance = getObjectForBeanInstance(scopedInstance, name, beanName, mbd);
                }
                catch (IllegalStateException ex) {
                    throw new ScopeNotActiveException(beanName, scopeName, ex);
                }
            }
        }
        catch (BeansException ex) {
            ...
        }
        finally {
            beanCreation.end();
        }
    }

    return adaptBeanInstance(name, beanInstance, requiredType);
}

通过上面这个方法我们可以得到的信息是:在进行Bean的初始化过程中,首先会使用 getSingleton(beanName);方法尝试从缓存中获取Bean,代码如下:

@Nullable
protected Object getSingleton(String beanName, boolean allowEarlyReference) {
   Object singletonObject = this.singletonObjects.get(beanName);
   if (singletonObject == null && isSingletonCurrentlyInCreation(beanName)) {
      singletonObject = this.earlySingletonObjects.get(beanName);
      if (singletonObject == null && allowEarlyReference) {
         synchronized (this.singletonObjects) {
            singletonObject = this.singletonObjects.get(beanName);
            if (singletonObject == null) {
               singletonObject = this.earlySingletonObjects.get(beanName);
               if (singletonObject == null) {
                  ObjectFactory<?> singletonFactory = this.singletonFactories.get(beanName);
                  if (singletonFactory != null) {
                     singletonObject = singletonFactory.getObject();
                     this.earlySingletonObjects.put(beanName, singletonObject);
                     this.singletonFactories.remove(beanName);
                  }
               }
            }
         }
      }
   }
   return singletonObject;
}

// 一级缓存
private final Map<String, Object> singletonObjects = new ConcurrentHashMap<>(256);
// 二级缓存
private final Map<String, Object> earlySingletonObjects = new ConcurrentHashMap<>(16);
// 三级缓存
private final Map<String, ObjectFactory<?>> singletonFactories = new HashMap<>(16);

如果没有获取到则会将当前Bean已创建状态,然后执行创建Bean的操作。

17,创建Bean

从createBean(beanName, mbd, args)方法看进来:

@Override
protected Object createBean(String beanName, RootBeanDefinition mbd, @Nullable Object[] args)
      throws BeanCreationException {
	...
	Object beanInstance = doCreateBean(beanName, mbdToUse, args);
    ...
}

我们来只看这一行的doCreateBean()方法:

protected Object doCreateBean(String beanName, RootBeanDefinition mbd, @Nullable Object[] args)
      throws BeanCreationException {
	...
    // 位置1(初始化的第一步)
    instanceWrapper = createBeanInstance(beanName, mbd, args);
   	...
    // 位置2
    addSingletonFactory(beanName, () -> getEarlyBeanReference(beanName, mbd, bean));
    ...
   	// 位置3
    populateBean(beanName, mbd, instanceWrapper);
	// 位置4
    exposedObject = initializeBean(beanName, exposedObject, mbd);
    ...
	...
    return exposedObject;
}

这里只留下几个关键代码进行介绍:

  • 位置1:这是初始化的第一步,就是将Bean创建出来,需要注意的是,此处只是将Bean创建了出来
  • **位置2(重点!!!)**这个地方我们在下个步骤解释
  • 位置3:populateBean(beanName, mbd, instanceWrapper) 完成Bean属性赋值,主要是配置前、后置处理器,并为属性利用setter等进行赋值
  • 位置4:initializeBean(beanName, exposedObject, mbd) 执行bean的初始化
    1. 执行Bean实现的Aware接口的方法
    2. 执行后置处理器初始化之前的方法
    3. 执行初始化方法
    4. 执行后置处理器初始化之后的方法
    5. 注册bean的销毁方法
18,循环依赖

上步骤中的位置2是解决循环依赖的关键,我们来一起看一下这个方法的内容:

protected void addSingletonFactory(String beanName, ObjectFactory<?> singletonFactory) {
    Assert.notNull(singletonFactory, "Singleton factory must not be null");
    synchronized (this.singletonObjects) {
        if (!this.singletonObjects.containsKey(beanName)) {
            // 加到三级缓存中
            this.singletonFactories.put(beanName, singletonFactory);
            this.earlySingletonObjects.remove(beanName);
            this.registeredSingletons.add(beanName);
        }
    }
}

这段代码发生在createBeanInstance之后,也就是说单例对象此时已经被创建出来(调用了构造器)。这个对象已经被生产出来了,虽然还不完美(还没有进行初始化的第二步和第三步),但是已经能被人认出来了(根据对象引用能定位到堆中的对象),所以Spring此时将这个对象提前曝光出来让大家认识,让大家使用。

这样做有什么好处呢?让我们来分析一下“A的某个field或者setter依赖了B的实例对象,同时B的某个field或者setter依赖了A的实例对象”这种循环依赖的情况。A首先完成了初始化的第一步,并且将自己提前曝光到singletonFactories中,此时进行初始化的第二步,发现自己依赖对象B,此时就尝试去get(B),发现B还没有被create,所以走create流程,B在初始化第一步的时候发现自己依赖了对象A,于是尝试get(A),尝试一级缓存singletonObjects(肯定没有,因为A还没初始化完全),尝试二级缓存earlySingletonObjects(也没有),尝试三级缓存singletonFactories,由于A通过ObjectFactory将自己提前曝光了,所以B能够通过ObjectFactory.getObject拿到A对象(虽然A还没有初始化完全,但是总比没有好呀),B拿到A对象后顺利完成了初始化阶段1、2、3,完全初始化之后将自己放入到一级缓存singletonObjects中。此时返回A中,A此时能拿到B的对象顺利完成自己的初始化阶段2、3,最终A也完成了初始化,进去了一级缓存singletonObjects中,而且更加幸运的是,由于B拿到了A的对象引用,所以B现在hold住的A对象完成了初始化

注:该步骤参考博客:https://blog.csdn.net/u010853261/article/details/77940767

19,创建完成

创建完Bean之后将会调用getSingleton(String, ObjectFactory<?>)方法获取单实例Bean,并在该方法中最终调用addSingleton方法将该Bean添加到缓存(singletonObjects)中:

protected void addSingleton(String beanName, Object singletonObject) {
    synchronized (this.singletonObjects) {
        // 添加到一级缓存中
        this.singletonObjects.put(beanName, singletonObject);
        // 从二级缓存中删除
        this.singletonFactories.remove(beanName);
        // 从三级缓存中删除
        this.earlySingletonObjects.remove(beanName);
        this.registeredSingletons.add(beanName);
    }
}

的实例对象”这种循环依赖的情况。A首先完成了初始化的第一步,并且将自己提前曝光到singletonFactories中,此时进行初始化的第二步,发现自己依赖对象B,此时就尝试去get(B),发现B还没有被create,所以走create流程,B在初始化第一步的时候发现自己依赖了对象A,于是尝试get(A),尝试一级缓存singletonObjects(肯定没有,因为A还没初始化完全),尝试二级缓存earlySingletonObjects(也没有),尝试三级缓存singletonFactories,由于A通过ObjectFactory将自己提前曝光了,所以B能够通过ObjectFactory.getObject拿到A对象(虽然A还没有初始化完全,但是总比没有好呀),B拿到A对象后顺利完成了初始化阶段1、2、3,完全初始化之后将自己放入到一级缓存singletonObjects中。此时返回A中,A此时能拿到B的对象顺利完成自己的初始化阶段2、3,最终A也完成了初始化,进去了一级缓存singletonObjects中,而且更加幸运的是,由于B拿到了A的对象引用,所以B现在hold住的A对象完成了初始化**。

注:该步骤参考博客:https://blog.csdn.net/u010853261/article/details/77940767

19,创建完成

创建完Bean之后将会调用getSingleton(String, ObjectFactory<?>)方法获取单实例Bean,并在该方法中最终调用addSingleton方法将该Bean添加到缓存(singletonObjects)中:

protected void addSingleton(String beanName, Object singletonObject) {
    synchronized (this.singletonObjects) {
        // 添加到一级缓存中
        this.singletonObjects.put(beanName, singletonObject);
        // 从二级缓存中删除
        this.singletonFactories.remove(beanName);
        // 从三级缓存中删除
        this.earlySingletonObjects.remove(beanName);
        this.registeredSingletons.add(beanName);
    }
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值