/**
   * Load the template BeanDefinition and call {@link #transform(ConfigurableListableBeanFactory,
   * BeanDefinition, Element, ParserContext)} to apply runtime configuration value to it. <code>
   * builder</code> will be configured to instantiate the bean in the Spring context that we are
   * parsing.
   *
   * <p>During parsing, an instance of {@link
   * TemplateBeanDefinitionParser.TemplateComponentDefinition} is pushed onto <code>ParserContext
   * </code> so that nested tags can access the enclosing template configuration with a call to
   * {@link #findEnclosingTemplateFactory(ParserContext)}. Subclasses can override {@link
   * #newComponentDefinition(String, Object, DefaultListableBeanFactory)} to provide a subclass of
   * {@link TemplateBeanDefinitionParser.TemplateComponentDefinition} to the parser context if
   * necessary.
   */
  @Override
  protected final void doParse(
      Element element, ParserContext parserContext, BeanDefinitionBuilder builder) {

    // if we have multiple nested bean definitions, we only parse the template factory
    // once.  this allows configuration changes made by enclosing bean parsers to be inherited
    // by contained beans, which is quite useful.
    DefaultListableBeanFactory templateFactory = findEnclosingTemplateFactory(parserContext);
    TemplateComponentDefinition tcd = null;
    if (templateFactory == null) {

      // no nesting -- load the template XML configuration from the classpath.
      final BeanFactory parentFactory = (BeanFactory) parserContext.getRegistry();
      templateFactory = new DefaultListableBeanFactory(parentFactory);

      // load template bean definitions
      DefaultResourceLoader loader = new DefaultResourceLoader();
      XmlBeanDefinitionReader reader = new XmlBeanDefinitionReader(templateFactory);
      reader.setResourceLoader(loader);
      reader.setEntityResolver(new ResourceEntityResolver(loader));
      reader.loadBeanDefinitions(templateResource);

      // propagate factory post-processors from the source factory into the template
      // factory.
      BeanDefinition ppChain = new RootBeanDefinition(ChainingBeanFactoryPostProcessor.class);
      ppChain.getPropertyValues().addPropertyValue("targetFactory", templateFactory);
      parserContext.getReaderContext().registerWithGeneratedName(ppChain);

      // push component definition onto the parser stack for the benefit of
      // nested bean definitions.
      tcd =
          newComponentDefinition(
              element.getNodeName(), parserContext.extractSource(element), templateFactory);
      parserContext.pushContainingComponent(tcd);
    }

    try {
      // allow subclasses to apply overrides to the template bean definition.
      BeanDefinition def = templateFactory.getBeanDefinition(templateId);
      transform(templateFactory, def, element, parserContext);

      // setup our factory bean to instantiate the modified bean definition upon request.
      builder.addPropertyValue("beanFactory", templateFactory);
      builder.addPropertyValue("beanName", templateId);
      builder.getRawBeanDefinition().setAttribute("id", def.getAttribute("id"));

    } finally {
      if (tcd != null) parserContext.popContainingComponent();
    }
  }
  /**
   * Loads the bean definitions via an XmlBeanDefinitionReader.
   *
   * @see org.springframework.beans.factory.xml.XmlBeanDefinitionReader
   * @see #initBeanDefinitionReader
   * @see #loadBeanDefinitions
   */
  protected void loadBeanDefinitions(DefaultListableBeanFactory beanFactory) throws 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.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 来加载bean definition.第三步.
   *
   * <p>当然,可能存在其他非xml形式的配置加载,所以这个从refreshablApplicationConetext类中抽象出模板方法,在子类来实现
   *
   * <p>Loads the bean definitions via an XmlBeanDefinitionReader.
   *
   * @see org.springframework.beans.factory.xml.XmlBeanDefinitionReader
   * @see #initBeanDefinitionReader
   * @see #loadBeanDefinitions
   */
  @Override
  protected void loadBeanDefinitions(DefaultListableBeanFactory beanFactory)
      throws BeansException, IOException {

    // DefaultListableBeanFactory 中实现了BeanDefinitionRegistry ,reader会将解析好的bean definition 注册到该对象上
    XmlBeanDefinitionReader beanDefinitionReader = new XmlBeanDefinitionReader(beanFactory);

    // 配置资源使用的环境,一般用的比较少,打包一般只配置对应的环境配置
    beanDefinitionReader.setEnvironment(this.getEnvironment());

    // this 继承了 DefaultResourceLoader类,所以其如果不是classpath的话,最终会调用filesystem的getResourcebypath
    // 实际上,这就是程序式ioc的第一步,定义resourceLoader
    beanDefinitionReader.setResourceLoader(this);

    beanDefinitionReader.setEntityResolver(new ResourceEntityResolver(this));

    // 允许子类提供自定义的reader初始化,然后进行实际的加载bean definition工作
    initBeanDefinitionReader(beanDefinitionReader);

    loadBeanDefinitions(beanDefinitionReader);
  }
  /*初始化方法*/
  public void init() {
    beanDefinitionReader =
        new XmlBeanDefinitionReader((BeanDefinitionRegistry) applicationContext.getBeanFactory());

    beanDefinitionReader.setEntityResolver(new ResourceEntityResolver(applicationContext));
  }