Spring容器(IOC)源码解析(一)

一 Spring IOC解读

Spring IOC即控制反转,IOC不是技术而是思想,对象由容器控制而不是自己对象控制。

控制:传统的程序是直接new创建对象,IOC是一个容器来创建管理对象,所以是IOC容器控制对象。

反转:传统的程序直接在对象内主动new依赖的对象,这就是正转;而反转是由容器注入依赖对象,对象只是被动接受,所以是被依赖对象反转。

DI是IOC不同角度的解读,IOC是站在被依赖对象角度说明,类是被控制反转到IOC容器内;DI是站在依赖对象角度说明,类是依赖注入,只需要简单配置,不需要关心依赖对象的具体创建和管理。

二 Spring IOC核心流程

IOC简单理解就是一个容器,进行对象初始化及实例化;其实主要可以分为三部分;第一识别Bean定义,解析XML或者注解;第二创建Bean容器(BeanFactory);第三类的初始化及实例化。

ebe8f531eacb8ce4b59827d001f85537.png

  • 读取配置文件或注释的Bean定义

  • 解析文件或注释,验证是否合法等

  • 获取出Bean的定义信息(beanDefinition)

  • 对BeanDefinition信息做增强处理

  • 创建BeanFactory容器

  • 通过反射对类进行初始化

  • 填充属性

  • 执行aware方法

  • 实例化Bean方法前置处理

  • 实例化Bean方法

  • 实例化Bean方法后置处理

  • Bean创建成功

三 识别Bean的定义

ClassPathXmlApplicationContext.class

// 通过构造方法初始化
  ClassPathXmlApplicationContext classPathXmlApplicationContext = new ClassPathXmlApplicationContext("beanTest.xml");
// 创建一个新的 ClassPathXmlApplicationContext,从给定的 XML 文件加载定义并自动刷新上下文。
  // 调用本类根据父级创建对象,传入父级为null
  public ClassPathXmlApplicationContext(String configLocation) throws BeansException {
    this(new String[] {configLocation}, true, null);
  }
// 使用给定的父级创建一个新的 ClassPathXmlApplicationContext,从给定的 XML 文件加载定义。
  public ClassPathXmlApplicationContext(
      String[] configLocations, boolean refresh, @Nullable ApplicationContext parent)
      throws BeansException {
    // 构造器调用,一直到AbstractApplicationContext.class
    // 创建一个AbstractApplicationContext,合并父级配置到当前
    super(parent);
    // 设置配置文件路径
    setConfigLocations(configLocations);
    // refresh Spring容器
    // bean的创建和实例化都是在refresh()方法中进行的,refresh()函数中包含了几乎所有的ApplicationContext中提供的全部功能。
    if (refresh) {
      refresh();
    }
  }

super(parent),构造器

AbstractApplicationContext.calss

// 使用给定的父上下文创建一个新的 AbstractApplicationContext。
  // 我们创建的时候没有父级容器,所以为空
  public AbstractApplicationContext(@Nullable ApplicationContext parent) {
    // 注1 调用本类方法创建一个没有父级的新 AbstractApplicationContext。
    this();
    // 注2 把父级配置合并到当前配置
    setParent(parent);
  }
// 注1 创建一个没有父级的新 AbstractApplicationContext。
  public AbstractApplicationContext() {
    this.resourcePatternResolver = getResourcePatternResolver();
  }
  // 返回 ResourcePatternResolver 以用于将位置模式解析为 Resource 实例。
  // 默认是PathMatchingResourcePatternResolver ,支持 Ant 风格的位置模式。
  protected ResourcePatternResolver getResourcePatternResolver() {
    return new PathMatchingResourcePatternResolver(this);
  }
  public PathMatchingResourcePatternResolver(ResourceLoader resourceLoader) {
    Assert.notNull(resourceLoader, "ResourceLoader must not be null");
    this.resourceLoader = resourceLoader;
  }
// 注2 设置此应用程序上下文的父级。
  // 如果父环境为非null且其环境是ConfigurableEnvironment的实例,则父环境将与此(子)应用程序上下文环境合并。
  @Override
  public void setParent(@Nullable ApplicationContext parent) {
    this.parent = parent;
    if (parent != null) {
      // 获取父级配置信息
      Environment parentEnvironment = parent.getEnvironment();
      if (parentEnvironment instanceof ConfigurableEnvironment) {
        // 父级配置合并到当前配置中
        getEnvironment().merge((ConfigurableEnvironment) parentEnvironment);
      }
    }
  }

setConfigLocations(configLocations),设置配置路径

AbstractRefreshableConfigApplicationContext.calss

// 设置配置文件路径
  public void setConfigLocations(@Nullable String... locations) {
    if (locations != null) {
      Assert.noNullElements(locations, "Config locations must not be null");
      // 传入配置文件路径初始化到configLocations数组中
      this.configLocations = new String[locations.length];
      for (int i = 0; i < locations.length; i++) {
        // 解析给定的路径,如有占位符 ${...},用相应的环境属性值替换占位符。如spring-${profile}.yml
        this.configLocations[i] = resolvePath(locations[i]).trim();
      }
    }
    else {
      this.configLocations = null;
    }
  }
  // 替换配置文件占位符
  protected String resolvePath(String path) {
    return getEnvironment().resolveRequiredPlaceholders(path);
  }

refresh(),Spring容器初始化,包括了BeanDefinition和Resource的定义、载入和注册三个基本过程

AbstractApplicationContext.calss

// refresh()函数中包含了几乎所有的ApplicationContext中提供的全部功能
  @Override
  public void refresh() throws BeansException, IllegalStateException {
    // 加锁,在创建容器过程中防止出现重复创建和销毁
    synchronized (this.startupShutdownMonitor) {
      // 步骤记录有关在ApplicationStartup期间发生的特定阶段或操作的指标。
      // StartupStep的生命周期如下:
      // 1 该步骤是通过调用application.startup()来创建并被分配一个唯一的id 。
      // 2 然后我们可以在处理过程中使用StartupStep.Tags添加一些附加信息
      // 3 结束需要调用contextRefresh.end()标记
      // 实现可以跟踪“执行时间”或步骤的其他指标。
      // Spring5.3才开始有;主要对创建容器过程做一个记录标记,调用开始标记
      StartupStep contextRefresh = this.applicationStartup.start("spring.context.refresh");


      // 准备刷新容器
      // 准备工作,记录下容器的启动时间、标记“已启动”状态、处理配置文件中的占位符
      prepareRefresh();


      // 通知子类刷新内部bean工厂,初始化BeanFactory并进行XML文件的解析、读取
      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);


        StartupStep beanPostProcess = this.applicationStartup.start("spring.context.beans.post-process");
        // Invoke factory processors registered as beans in the context.
        invokeBeanFactoryPostProcessors(beanFactory);


        // Register bean processors that intercept bean creation.
        registerBeanPostProcessors(beanFactory);
        beanPostProcess.end();


        // 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();
        contextRefresh.end();
      }
    }
  }

prepareRefresh()

// 准备工作,记录下容器的启动时间、标记“已启动”状态、处理配置文件中的占位符
  protected void prepareRefresh() {
    // 记录启动时间,
    // 将 active 属性设置为 true,closed 属性设置为 false,它们都是 AtomicBoolean 类型
    this.startupDate = System.currentTimeMillis();
    // 指示此上下文是否已关闭的标志
    this.closed.set(false);
    // 指示此上下文当前是否处于活动状态的标志
    this.active.set(true);


    if (logger.isDebugEnabled()) {
      if (logger.isTraceEnabled()) {
        logger.trace("Refreshing " + this);
      }
      else {
        logger.debug("Refreshing " + getDisplayName());
      }
    }


    // 替换配置文件占位符,空实现
    initPropertySources();


    // Validate that all properties marked as required are resolvable:
    // see ConfigurablePropertyResolver#setRequiredProperties
    // 校验配置文件属性
    getEnvironment().validateRequiredProperties();


    // Store pre-refresh ApplicationListeners...
    if (this.earlyApplicationListeners == null) {
      this.earlyApplicationListeners = new LinkedHashSet<>(this.applicationListeners);
    }
    else {
      // Reset local application listeners to pre-refresh state.
      this.applicationListeners.clear();
      this.applicationListeners.addAll(this.earlyApplicationListeners);
    }


    // Allow for the collection of early ApplicationEvents,
    // to be published once the multicaster is available...
    this.earlyApplicationEvents = new LinkedHashSet<>();
  }

obtainFreshBeanFactory()

// 通知子类刷新内部bean工厂,初始化BeanFactory并进行XML文件的解析、读取
  // 实现BeanFactory的地方,也就是经过这个方法,ApplicationContext就已经拥有了BeanFactory的全部功能
  protected ConfigurableListableBeanFactory obtainFreshBeanFactory() {
    // 关闭旧的 BeanFactory (如果有),创建新的 BeanFactory,加载 Bean 定义、注册 Bean
    refreshBeanFactory();
    // 返回刚创建的 BeanFactory
    return getBeanFactory();
  }

refreshBeanFactory() - AbstractRefreshableApplicationContext.class

// 关闭现有bean工厂,新建一个新的bean工厂
  @Override
  protected final void refreshBeanFactory() throws BeansException {
    // 如果已有bean工厂,则关闭
    if (hasBeanFactory()) {
      destroyBeans();
      closeBeanFactory();
    }
    try {
      // 注1 初始化一个 DefaultListableBeanFactory,下图解释为何初始化这个类
      DefaultListableBeanFactory beanFactory = createBeanFactory();
      // 指定用于序列化目的的 id,如果需要,允许将此 BeanFactory 从此 id 反序列化回 BeanFactory 对象。
      beanFactory.setSerializationId(getId());
      // 注2 设置是否可以循环引用和bean名称重复覆盖
      customizeBeanFactory(beanFactory);
      // 加载bean定义信息,这一步实际上就从XML配置文件里的bean信息给读取到了Factory里了。
      // 详细说明另起如下文
      loadBeanDefinitions(beanFactory);
      this.beanFactory = beanFactory;
    }
    catch (IOException ex) {
      throw new ApplicationContextException("I/O error parsing bean definition source for " + getDisplayName(), ex);
    }
  }
  // 注1 通过当前已有的beanFactory创建对象
  protected DefaultListableBeanFactory createBeanFactory() {
    return new DefaultListableBeanFactory(getInternalParentBeanFactory());
  }
  // getParent()获取的就是我们初始进来super(parent)设置进去的父级,我们没有为空
  protected BeanFactory getInternalParentBeanFactory() {
    return (getParent() instanceof ConfigurableApplicationContext ?
        ((ConfigurableApplicationContext) getParent()).getBeanFactory() : getParent());
  }
  // 注2 设置是否可以循环引用和bean名称重复覆盖
  protected void customizeBeanFactory(DefaultListableBeanFactory beanFactory) {
    // 默认值为false。值为空所以不设置
    if (this.allowBeanDefinitionOverriding != null) {
      // 设置是否允许通过注册具有相同名称的不同定义来覆盖 bean 定义,自动替换前者。 如果没有,将抛出异常。 这也适用于覆盖别名。
      beanFactory.setAllowBeanDefinitionOverriding(this.allowBeanDefinitionOverriding);
    }
    // 默认值为false。值为空所以不设置
    if (this.allowCircularReferences != null) {
      // 设置是否允许 bean 之间的循环引用。
      // 关闭此选项以在遇到循环引用时抛出异常。
      // 注意:通常建议不要依赖 bean 之间的循环引用。 重构您的应用程序逻辑,让所涉及的两个 bean 委托给封装其公共逻辑的第三个 bean。
      beanFactory.setAllowCircularReferences(this.allowCircularReferences);
    }
  }

通过下图可以看出DefaultListableBeanFactory类实现或继承了BeanFactory所有的类,所以可以认为他是BeanFactory是最全的一个类

ApplicationContext是继承自BeanFactory,但他并不是BeanFactory实现类,而是内部实例化了DefaultListableBeanFactory并对其进行了扩展,所有的BeanFactory操作都是通过他完成的。所以DefaultListableBeanFactory对ApplicationContext非常重要。

0b764ef93d69b4a2af52056e49fac2ca.png

loadBeanDefinitions(beanFactory)- AbstractXmlApplicationContext.class

// 通过 XmlBeanDefinitionReader 加载 bean 定义。
  @Override
  protected void loadBeanDefinitions(DefaultListableBeanFactory beanFactory) throws BeansException, IOException {
    // Create a new XmlBeanDefinitionReader for the given BeanFactory.
    // 为给定的 bean 工厂创建新的 XmlBeanDefinitionReader。
    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.
    // 允许子类提供reader的自定义初始化,空实现,还可以关闭xml验证
    initBeanDefinitionReader(beanDefinitionReader);
    // 核心。使用给定的 XmlBeanDefinitionReader 加载 bean 定义。
    loadBeanDefinitions(beanDefinitionReader);
  }

loadBeanDefinitions(beanDefinitionReader)

// 使用给定的 XmlBeanDefinitionReader 加载 bean 定义。
  protected void loadBeanDefinitions(XmlBeanDefinitionReader reader) throws BeansException, IOException {
    // 返回一个 Resource 对象数组,引用上下文应该使用的 XML bean 定义文件。
    Resource[] configResources = getConfigResources();
    if (configResources != null) {
      // 从指定的资源加载 bean 定义
      reader.loadBeanDefinitions(configResources);
    }
    // 返回一个资源位置数组,指的是构建此上下文时应使用的 XML bean 定义文件。
    // 还可以包括位置模式,这将通过 ResourcePatternResolver 解决。
    // 默认实现返回null 。子类可以覆盖它以提供一组资源位置来加载 bean 定义。
    String[] configLocations = getConfigLocations();
    if (configLocations != null) {
      // 从指定的资源位置加载 bean 定义
      // 这个方法是指定路径,通过方法调用最后会转换成reader.loadBeanDefinitions(configResources);(同上)
      reader.loadBeanDefinitions(configLocations);
    }
  } 
  // 从指定的资源加载 bean 定义。
  @Override
  public int loadBeanDefinitions(Resource... resources) throws BeanDefinitionStoreException {
    Assert.notNull(resources, "Resource array must not be null");
    int count = 0;
    for (Resource resource : resources) {
      // 从指定的资源加载 bean 定义
      count += loadBeanDefinitions(resource);
    }
    return count;
  }

loadBeanDefinitions(resource) - XmlBeanDefinitionReader.class

// 从指定的 XML 加载 bean
  @Override
  public int loadBeanDefinitions(Resource resource) throws BeanDefinitionStoreException {
    // 注1 从指定的 XML 文件加载 bean 定义。
    return loadBeanDefinitions(new EncodedResource(resource));
  }
  // EncodedResource.calss 为给定的Resource创建一个新的EncodedResource ,不指定显式编码或Charset 。
  public EncodedResource(Resource resource) {
    this(resource, null, null);
  }
  // EncodedResource.calss
  private EncodedResource(Resource resource, @Nullable String encoding, @Nullable Charset charset) {
    super();
    Assert.notNull(resource, "Resource must not be null");
    this.resource = resource;
    this.encoding = encoding;
    this.charset = charset;
  }
  // 注1 从指定的 XML 文件加载 bean 定义。
  public int loadBeanDefinitions(EncodedResource encodedResource) throws BeanDefinitionStoreException {
    Assert.notNull(encodedResource, "EncodedResource must not be null");
    if (logger.isTraceEnabled()) {
      logger.trace("Loading XML bean definitions from " + encodedResource);
    }
    // 获取一个新的配置文件对象set集合
    // 就是校验文件是否被重复加载
    Set<EncodedResource> currentResources = this.resourcesCurrentlyBeingLoaded.get();
    // 把当前配置添加到集合中
    if (!currentResources.add(encodedResource)) {
      throw new BeanDefinitionStoreException(
          "Detected cyclic loading of " + encodedResource + " - check your import definitions!");
    }
    // 获取当前文件输入流
    try (InputStream inputStream = encodedResource.getResource().getInputStream()) {
      // 创建可读取XML文件的对象
      InputSource inputSource = new InputSource(inputStream);
      // 获取文件编码方式并设置
      if (encodedResource.getEncoding() != null) {
        inputSource.setEncoding(encodedResource.getEncoding());
      }
      // 注2 真正的从指定的 XML 文件加载 bean 定义。
      return doLoadBeanDefinitions(inputSource, encodedResource.getResource());
    }
    catch (IOException ex) {
      throw new BeanDefinitionStoreException(
          "IOException parsing XML document from " + encodedResource.getResource(), ex);
    }
    finally {
      // 执行完成从当前线程的set对象删除当前配置文件对象数据,
      // 因为是for操作多个配置文件,需要解析完成后就删除
      currentResources.remove(encodedResource);
      if (currentResources.isEmpty()) {
        this.resourcesCurrentlyBeingLoaded.remove();
      }
    }
  }
  // 注2 真正的从指定的 XML 文件加载 bean 定义。
  protected int doLoadBeanDefinitions(InputSource inputSource, Resource resource)
      throws BeanDefinitionStoreException {


    try {
      // 注3 使用配置的 DocumentLoader 实际加载指定的文档。       
      // 获取xml的配置信息并封装为Document对象
      Document doc = doLoadDocument(inputSource, resource);
      // 注4 注册包含在给定 DOM 文档中的 bean 定义。 由loadBeanDefinitions调用。
      // 创建解析器类的新实例并在其上调用registerBeanDefinitions 。
      int count = registerBeanDefinitions(doc, resource);
      if (logger.isDebugEnabled()) {
        logger.debug("Loaded " + count + " bean definitions from " + resource);
      }
      return count;
    }
    catch (BeanDefinitionStoreException ex) {
      throw ex;
    }
    catch (SAXParseException ex) {
      throw new XmlBeanDefinitionStoreException(resource.getDescription(),
          "Line " + ex.getLineNumber() + " in XML document from " + resource + " is invalid", ex);
    }
    catch (SAXException ex) {
      throw new XmlBeanDefinitionStoreException(resource.getDescription(),
          "XML document from " + resource + " is invalid", ex);
    }
    catch (ParserConfigurationException ex) {
      throw new BeanDefinitionStoreException(resource.getDescription(),
          "Parser configuration exception parsing XML from " + resource, ex);
    }
    catch (IOException ex) {
      throw new BeanDefinitionStoreException(resource.getDescription(),
          "IOException parsing XML document from " + resource, ex);
    }
    catch (Throwable ex) {
      throw new BeanDefinitionStoreException(resource.getDescription(),
          "Unexpected exception parsing XML document from " + resource, ex);
    }
  }
  // 注3  Document接口代表整个 HTML 或 XML 文档。从概念上讲,它是文档树的根,并提供对文档数据的主要访问。
  // 由于元素、文本节点、注释、处理指令等不能存在于Document的上下文之外,因此Document接口还包含创建这些对象所需的工厂方法。创建的Node对象具有ownerDocument属性,该属性将它们与创建它们的上下文中的Document相关联
  protected Document doLoadDocument(InputSource inputSource, Resource resource) throws Exception {
    return this.documentLoader.loadDocument(inputSource, getEntityResolver(), this.errorHandler,
        getValidationModeForResource(resource), isNamespaceAware());
  }
  // 注4 
  public int registerBeanDefinitions(Document doc, Resource resource) throws BeanDefinitionStoreException {
    // 创建BeanDefinitionDocumentReader以用于从 XML 文档实际读取 bean 定义。
    // 默认实现实例化指定的“documentReaderClass”
    // 用于解析包含 Spring bean 定义的 XML 文档的 SPI。XmlBeanDefinitionReader用于实际解析 DOM 文档。
    // 根据要解析的文档实例化:在registerBeanDefinitions方法的执行期间,实现可以在实例变量中保存状态——例如,为文档中的所有 bean 定义定义的全局设置
    BeanDefinitionDocumentReader documentReader = createBeanDefinitionDocumentReader();
    // 容器中现有 bean 数量
    int countBefore = getRegistry().getBeanDefinitionCount();
    // 从给定的 DOM 文档中读取 bean 定义,并将它们注册到给定阅读器上下文中的注册表中。
    documentReader.registerBeanDefinitions(doc, createReaderContext(resource));
    // 本次创建了多少 bean
    return getRegistry().getBeanDefinitionCount() - countBefore;
  }
  // 创建XmlReaderContext以传递给文档阅读器
  public XmlReaderContext createReaderContext(Resource resource) {
    return new XmlReaderContext(resource, this.problemReporter, this.eventListener,
        this.sourceExtractor, this, getNamespaceHandlerResolver());
  }

 documentReader.registerBeanDefinitions(doc,createReaderContext(resource))  -  DefaultBeanDefinitionDocumentReader.class

@Override
  public void registerBeanDefinitions(Document doc, XmlReaderContext readerContext) {
    this.readerContext = readerContext;
    // 在给定的根<beans/>元素中注册每个 bean 定义
    // 解析配置文件 <beans> 根标签下的 bean 定义
    doRegisterBeanDefinitions(doc.getDocumentElement());
  }
  // 现在已经获取到配置文件的beans标签,下来会解析标签加载bean
  @SuppressWarnings("deprecation")  // for Environment.acceptsProfiles(String...)
  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 是一个重要的类,它负责解析 Bean 定义,
    // 这里为什么要定义一个 parent? 是递归问题,
    // 因为 <beans /> 内部是可以定义 <beans /> 的,所以这个方法的 root 其实不一定就是 xml 的根节点,也可以是嵌套在里面的 <beans /> 节点,从源码分析的角度,我们当做根节点就好了
    BeanDefinitionParserDelegate parent = this.delegate;
    // 初始化方法
    this.delegate = createDelegate(getReaderContext(), root, parent);


    // 确定给定节点是否指示默认命名空间
    if (this.delegate.isDefaultNamespace(root)) {
      // 这块说的是根节点 <beans ... profile="dev" /> 中的 profile 是否是当前环境需要的,
      // 如果当前环境配置的 profile 不包含此 profile,那就直接 return 了,不对此 <beans /> 解析       
      String profileSpec = root.getAttribute(PROFILE_ATTRIBUTE);
      if (StringUtils.hasText(profileSpec)) {
        String[] specifiedProfiles = StringUtils.tokenizeToStringArray(
            profileSpec, BeanDefinitionParserDelegate.MULTI_VALUE_ATTRIBUTE_DELIMITERS);
        // We cannot use Profiles.of(...) since profile expressions are not supported
        // in XML config. See SPR-12458 for details.
        if (!getReaderContext().getEnvironment().acceptsProfiles(specifiedProfiles)) {
          if (logger.isDebugEnabled()) {
            logger.debug("Skipped XML bean definition file due to specified profiles [" + profileSpec +
                "] not matching: " + getReaderContext().getResource());
          }
          return;
        }
      }
    }


    // 在我们开始处理 bean 定义之前,通过首先处理任何自定义元素类型来允许 XML 可扩展。此方法是 XML 的任何其他自定义预处理的自然扩展点。
    // 默认实现为空。 例如,子类可以覆盖此方法以将自定义元素转换为标准 Spring bean 定义。 实现者可以通过相应的访问器访问解析器的 bean 定义阅读器和底层 XML 资源。
    // 源码没有具体实现,主要考虑用户自主性及扩展性(钩子)
    preProcessXml(root);
    // 注1 核心 解析文档中根级别的元素:“import”、“alias”、“bean”。
    parseBeanDefinitions(root, this.delegate);
    // 也是bean定义后的钩子,同上
    postProcessXml(root);


    this.delegate = parent;
  }
  // 注1 解析文档中根级别的元素:“import”、“alias”、“bean”。
  // 主要就是判断2个分支,一个是parseDefaultElement,代表的是当前namespace;
  // http://www.springframework.org/schema/beans  <import />、<alias />、<bean />、<beans />
  // 另一个delegate.parseCustomElement代表的是其他namespace定义解析 <mvc />、<task />、<context />、<aop />;需要引入额外的xsd
  // 其实解析标签大同小异,主要拿 <bean> 标签说明
  protected void parseBeanDefinitions(Element root, BeanDefinitionParserDelegate delegate) {
    if (delegate.isDefaultNamespace(root)) {
      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)) {
            // 注2 解析当前命名空间默认标签
            parseDefaultElement(ele, delegate);
          }
          else {
             // 解析自定义元素(在默认命名空间之外)。
            delegate.parseCustomElement(ele);
          }
        }
      }
    }
    else {
      // 解析自定义元素(在默认命名空间之外)。
      delegate.parseCustomElement(root);
    }
  }
  
  // 注2 解析当前命名空间默认标签
  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);
    }
    // 注3 解析 bean 标签
    else if (delegate.nodeNameEquals(ele, BEAN_ELEMENT)) {
      processBeanDefinition(ele, delegate);
    }
    // 解析 beans 标签
    else if (delegate.nodeNameEquals(ele, NESTED_BEANS_ELEMENT)) {
      // recurse 递归
      doRegisterBeanDefinitions(ele);
    }
  }
  
  // 注3 解析 bean 标签并注册到beanFactory
  protected void processBeanDefinition(Element ele, BeanDefinitionParserDelegate delegate) {
    // 将 <bean /> 节点中的信息提取出来,然后封装到一个 BeanDefinitionHolder 中
    // 解析完如下图
    BeanDefinitionHolder bdHolder = delegate.parseBeanDefinitionElement(ele);
    if (bdHolder != null) {
      // 如果有自定义属性的话,进行相应的解析
      bdHolder = delegate.decorateBeanDefinitionIfRequired(ele, bdHolder);
      try {
        // Register the final decorated instance.
        // 注册Bean
        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));
    }
  }

a3e52f9f93c9bcfb53ca8649ebda9944.png

delegate.parseBeanDefinitionElement(ele) - BeanDefinitionParserDelegate.class

// 解析提供的<bean>元素
  // 将 <bean /> 节点中的信息提取出来,然后封装到一个 BeanDefinitionHolder 中
  @Nullable
  public BeanDefinitionHolder parseBeanDefinitionElement(Element ele) {
    return parseBeanDefinitionElement(ele, null);
  }
  
  @Nullable
  public BeanDefinitionHolder parseBeanDefinitionElement(Element ele, @Nullable BeanDefinition containingBean) {
    String id = ele.getAttribute(ID_ATTRIBUTE);
    String nameAttr = ele.getAttribute(NAME_ATTRIBUTE);


    List<String> aliases = new ArrayList<>();
    // 将 name 属性的定义按照 ”逗号、分号、空格“ 切分,形成一个别名列表数组,  ",; "
    // 如果不定义的话,就是空的了


    if (StringUtils.hasLength(nameAttr)) {
      String[] nameArr = StringUtils.tokenizeToStringArray(nameAttr, MULTI_VALUE_ATTRIBUTE_DELIMITERS);
      aliases.addAll(Arrays.asList(nameArr));
    }


    String beanName = id;
    // 如果没有指定id, 那么用别名列表的第一个名字作为beanName
    if (!StringUtils.hasText(beanName) && !aliases.isEmpty()) {
      beanName = aliases.remove(0);
      if (logger.isTraceEnabled()) {
        logger.trace("No XML 'id' specified - using '" + beanName +
            "' as bean name and " + aliases + " as aliases");
      }
    }


    // 因为是null所以不存在
    if (containingBean == null) {
      // 验证指定的 bean 名称和别名尚未在 bean 元素嵌套的当前级别中使用
      checkNameUniqueness(beanName, aliases, ele);
    }


    // 注1 根据 <bean ...>...</bean> 中的配置创建 BeanDefinition,然后把配置中的信息都设置到实例中
    AbstractBeanDefinition beanDefinition = parseBeanDefinitionElement(ele, beanName, containingBean);
    
    // 到这里,整个 <bean /> 标签就算解析结束了,一个 BeanDefinition 就形成了
    if (beanDefinition != null) {
      // 如果都没有设置 id 和 name,那么此时的 beanName 就会为 null,进入下面这块代码产生
      if (!StringUtils.hasText(beanName)) {
        try {
          if (containingBean != null) {
            beanName = BeanDefinitionReaderUtils.generateBeanName(
                beanDefinition, this.readerContext.getRegistry(), true);
          }
          else {
            // 如果我们不定义 id 和 name,那么我们引言里的那个例子:
            //   1. beanName 为:com.demo.test.MyTestBean#0
            //   2. beanClassName 为:com.demo.test.MyTestBean
            beanName = this.readerContext.generateBeanName(beanDefinition);
            // Register an alias for the plain bean class name, if still possible,
            // if the generator returned the class name plus a suffix.
            // This is expected for Spring 1.2/2.0 backwards compatibility.
            // 设置别名为 beanClassName
            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()) {
            logger.trace("Neither XML 'id' nor 'name' specified - " +
                "using generated bean name [" + beanName + "]");
          }
        }
        catch (Exception ex) {
          error(ex.getMessage(), ele);
          return null;
        }
      }
      String[] aliasesArray = StringUtils.toStringArray(aliases);
      // 返回 BeanDefinitionHolder
      return new BeanDefinitionHolder(beanDefinition, beanName, aliasesArray);
    }


    return null;
  }
  
  // 注1 根据 <bean ...>...</bean> 中的配置创建 BeanDefinition,然后把配置中的信息都设置到实例中
  @Nullable
  public AbstractBeanDefinition parseBeanDefinitionElement(
      Element ele, String beanName, @Nullable BeanDefinition containingBean) {


    this.parseState.push(new BeanEntry(beanName));


    String className = null;
    // 判断是否有 class 属性 取出
    if (ele.hasAttribute(CLASS_ATTRIBUTE)) {
      className = ele.getAttribute(CLASS_ATTRIBUTE).trim();
    }
    String parent = null;
    // 判断是否有 parent 属性 取出
    if (ele.hasAttribute(PARENT_ATTRIBUTE)) {
      parent = ele.getAttribute(PARENT_ATTRIBUTE);
    }


    try {
      // 创建 BeanDefinition ;new GenericBeanDefinition设置属性返回
      AbstractBeanDefinition bd = createBeanDefinition(className, parent);
      
      // 设置 BeanDefinition 的一堆属性,这些属性定义在 AbstractBeanDefinition 中
      // 获取标签上的属性,有则设置
      parseBeanDefinitionAttributes(ele, beanName, containingBean, bd);
      bd.setDescription(DomUtils.getChildElementValueByTagName(ele, DESCRIPTION_ELEMENT));


       /**
       * 下面的一堆是解析 <bean>......</bean> 内部的子元素,
       * 解析出来以后的信息都放到 bd 的属性中
       */


      // 解析 <meta />
      parseMetaElements(ele, bd);
      // 解析 <lookup-method />
      parseLookupOverrideSubElements(ele, bd.getMethodOverrides());
      // 解析 <replaced-method />
      parseReplacedMethodSubElements(ele, bd.getMethodOverrides());


      // 解析 <constructor-arg />
      parseConstructorArgElements(ele, bd);
      // 解析 <property />
      parsePropertyElements(ele, bd);
      // 解析 <qualifier />
      parseQualifierElements(ele, bd);


      bd.setResource(this.readerContext.getResource());
      bd.setSource(extractSource(ele));


      return bd;
    }
    catch (ClassNotFoundException ex) {
      error("Bean class [" + className + "] not found", ele, ex);
    }
    catch (NoClassDefFoundError err) {
      error("Class that bean class [" + className + "] depends on not found", ele, err);
    }
    catch (Throwable ex) {
      error("Unexpected failure during bean definition parsing", ele, ex);
    }
    finally {
      this.parseState.pop();
    }


    return null;
  }

到此相当于整个<bean />才解析 BeanDefinitionHolder  对象中,只是一个 bean 标签,接下来我们再回到之前解析 bean 标签的入口,现在相当于第一步执行完成 

这个 BeanDefinitionHolder 实例里面也就是一个 BeanDefinition 的实例和它的 beanName、aliases 这三个信息,我们的关注点始终在 BeanDefinition 上

 -  DefaultBeanDefinitionDocumentReader.class

protected void processBeanDefinition(Element ele, BeanDefinitionParserDelegate delegate) {
    // 将 <bean /> 节点中的信息提取出来,然后封装到一个 BeanDefinitionHolder 中
    // 解析完如下图
    BeanDefinitionHolder bdHolder = delegate.parseBeanDefinitionElement(ele);
    if (bdHolder != null) {
      // 如果有自定义属性的话,进行相应的解析
      bdHolder = delegate.decorateBeanDefinitionIfRequired(ele, bdHolder);
      try {
        // Register the final decorated instance.
        // 注册Bean
        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));
    }
  }

BeanDefinitionReaderUtils.registerBeanDefinition(bdHolder, getReaderContext().getRegistry()); - BeanDefinitionReaderUtils.class

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


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


    // Register aliases for bean name, if any.
    // 如果有别名,也要根据别名注册一遍,不然根据别名就找不到 Bean 了
    String[] aliases = definitionHolder.getAliases();
    if (aliases != null) {
      for (String alias : aliases) {
        registry.registerAlias(beanName, alias);
      }
    }
  }

registry.registerBeanDefinition(beanName, definitionHolder.getBeanDefinition()); - DefaultListableBeanFactory.class

// 根据 bean 名称注册
  @Override
  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.getResourceDescription(), beanName,
            "Validation of bean definition failed", ex);
      }
    }
    
    // 获取当前是否有同名 bean
    BeanDefinition existingDefinition = this.beanDefinitionMap.get(beanName);
    if (existingDefinition != null) {
      // 判断是否容许同名覆盖,不容许抛出异常
      if (!isAllowBeanDefinitionOverriding()) {
        throw new BeanDefinitionOverrideException(beanName, beanDefinition, existingDefinition);
      }
      // 用框架定义的 Bean 覆盖用户自定义的 Bean
      else if (existingDefinition.getRole() < beanDefinition.getRole()) {
        // e.g. was ROLE_APPLICATION, now overriding with ROLE_SUPPORT or ROLE_INFRASTRUCTURE
        if (logger.isInfoEnabled()) {
          logger.info("Overriding user-defined bean definition for bean '" + beanName +
              "' with a framework-generated bean definition: replacing [" +
              existingDefinition + "] with [" + beanDefinition + "]");
        }
      }
      // 用新的 Bean 覆盖旧的 Bean
      else if (!beanDefinition.equals(existingDefinition)) {
        if (logger.isDebugEnabled()) {
          logger.debug("Overriding bean definition for bean '" + beanName +
              "' with a different definition: replacing [" + existingDefinition +
              "] with [" + beanDefinition + "]");
        }
      }
      // 用同等的 Bean 覆盖旧的 Bean,这里指的是 equals 方法返回 true 的 Bean
      else {
        if (logger.isTraceEnabled()) {
          logger.trace("Overriding bean definition for bean '" + beanName +
              "' with an equivalent definition: replacing [" + existingDefinition +
              "] with [" + beanDefinition + "]");
        }
      }
      // 覆盖
      this.beanDefinitionMap.put(beanName, beanDefinition);
    }
    else {
      // 判断是否已经有其他的 Bean 开始初始化了.
      // 注意,"注册Bean" 这个动作结束,Bean 依然还没有初始化
      // 在 Spring 容器启动的最后,会 预初始化 所有的 singleton beans
      if (hasBeanCreationStarted()) {
        // Cannot modify startup-time collection elements anymore (for stable iteration)
        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 {
        // Still in startup registration phase
        // 将 BeanDefinition 放到这个 map 中,这个 map 保存了所有的 BeanDefinition
        this.beanDefinitionMap.put(beanName, beanDefinition);
        // 这是个 ArrayList,所以会按照 bean 配置的顺序保存每一个注册的 Bean 的名字
        this.beanDefinitionNames.add(beanName);
        // 这是个 LinkedHashSet,代表的是手动注册的 singleton bean,
         // 注意这里是 remove 方法,到这里的 Bean 当然不是手动注册的
         // 手动指的是通过调用以下方法注册的 bean :
         // registerSingleton(String beanName, Object singletonObject)
         // Spring 会在后面"手动"注册一些 Bean,如 "environment"、"systemProperties" 等 bean
        removeManualSingletonName(beanName);
      }
      // 在预初始化的时候会用到
      this.frozenBeanDefinitionNames = null;
    }


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

到这里已经初始化了 Bean 容器,<bean /> 配置也相应的转换为了一个个 BeanDefinition,然后注册了各个 BeanDefinition 到注册中心,并且发送了注册事件。

其实bean到最后都存放在一个map中,如下k为beanName,v为BeanDefinition对象。

private final Map<String, BeanDefinition> beanDefinitionMap = new ConcurrentHashMap<>(256);

 UML类图

 1 Spring IOC入口

3afd27f6fd670f64525cbfea1995b738.png

2 配置文件校验,加载,解析为DOM树

412bd2eeffa8a11eb21543c62bed3db3.png

3 DOM树<bean />解析成BeanDefinition,存放到beanDefinitionMap

955276a9ad8a4bd520b0b6418c1814c3.png

五 总结

1ed7ae6aad9bb9486073b78f96f1ed12.png

我们到目前为止才把粉色的模块说完,主要就是读取配置文件,校验配置文件,解析配置文件为DOM树,读取DOM数解析成BeanDefinition对象,存放到map。

  • 2
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值