Spring Ioc源码分析(一)

211 阅读13分钟

Spring IoC的容器体系

IoC容器是Spring的核⼼模块,是抽象了对象管理、依赖关系管理的框架解决⽅案。Spring 提供了很多的容器,其中 BeanFactory 是顶层容器(根容器),不能被实例化,它定义了所有 IoC 容器 必须遵从的⼀套原则,具体的容器实现可以增加额外的功能,⽐如我们常⽤到的ApplicationContext,其下更具体的实现如 ClassPathXmlApplicationContext 包含了解析 xml 等⼀系列的内容,AnnotationConfifigApplicationContext 则是包含了注解解析等⼀系列的内容。Spring IoC 容器继承体系⾮常聪明,需要使⽤哪个层次⽤哪个层次即可,不必使⽤功能⼤⽽全的。

BeanFactory 顶级接⼝⽅法栈如下

image.png

BeanFactory 容器继承体系如下

image.png

通过其接⼝设计,我们可以看到我们⼀贯使⽤的 ApplicationContext 除了继承BeanFactory的⼦接⼝,还继承了ResourceLoader、MessageSource等接⼝,因此其提供的功能也就更丰富了。

下⾯我们以 ClasspathXmlApplicationContext 为例,深⼊源码说明 IoC 容器的初始化流程。

BeanFactory创建流程

获取BeanFactory⼦流程

image.png

image.png

入口:org.springframework.context.support.AbstractApplicationContext#refresh

/**
 * 该方法完成IOC容器创建以及初始化工作
 * 该方法中最重要的是第二步和第十一步
 *
 */
@Override
public void refresh() throws BeansException, IllegalStateException {
   synchronized (this.startupShutdownMonitor) {
      // Prepare this context for refreshing.
      // STEP 1: 刷新预处理
      //准备工作包括设置启动时间,是否激活标识位,初始化属性源(property,source)配置
      prepareRefresh();

      // Tell the subclass to refresh the internal bean factory.
      //用DefaultListableBeanFactory的子类得到的是DefaultListableBeanFactory
      //可以理解为初始化bean工厂

      // STEP 2:
      //        a) 创建IoC容器(DefaultListableBeanFactory)
      //    b) 加载解析XML文件(最终存储到Document对象中)
      //    c) 读取Document对象,并完成BeanDefinition的加载和注册工作
      ConfigurableListableBeanFactory beanFactory = obtainFreshBeanFactory();

      // Prepare the bean factory for use in this context.
      //最重要的方法,准备bean工厂
      // STEP 3: 对IoC容器进行一些预处理(设置一些公共属性)
      prepareBeanFactory(beanFactory);

      try {
         // Allows post-processing of the bean factory in context subclasses.
         //这个方法在当前版本的spring是没有任何代码的,可能spring期待在后面的版本中进行扩展
         //空壳方法
         postProcessBeanFactory(beanFactory);

         // Invoke factory processors registered as beans in the context.
         //比较重要的方法
         //在spring的环境中去执行已经被注册的factory processors
         //设置执行自定义的ProcessorFactory和spring内部自己定义的(ConfigutationClassPoetProcessor)
         //ConfigurationClassPostProcessor就是spring内部自己维护的BeanFactoryPostProcessor
         //下面的方法主要执行ConfigurationClassPostProcessor中的方法
         // STEP 5: 调用BeanFactoryPostProcessor后置处理器对BeanDefinition处理

         /**
          * BeanFactoryPostProcessor是spring的扩展点之一
          * 实现该接口,可以在spring的bean创建之前修改bean的定义属性
          *  spring允许BeanFactoryPostProcessor在容器实例化任何其他bean之前读取它配置的元数据
          *  并可以根据需要进行修改,例如可以把bean的scope从singleton改为prototype,也可以把property的值给修改
          *  可以同时配置多个BeanFactoryPostProcessor,并且通过设置'order'属性来控制各个BeanFactoryPostProcessor
          *  BeanFactoryPostProcessor是在spring容器加载了bean的定义文件之后,在bean实例化之前执行的
          *  可以写一个例子来测试以下这个功能
          */
         invokeBeanFactoryPostProcessors(beanFactory);

         // Register bean processors that intercept bean creation.
         //上一行的代码已经将一些后置处理器放到bdMap中了,包括自定义的BeanPostProcessor
         // 注册BeanPostProcessor,即后置处理器,一共是7个
         //把bdMap中的所有后置处理器拿出来,
         // 再直接new另外一些后置处理器,一起放到工厂的list中
         // STEP 6: 注册BeanPostProcessor后置处理器
         registerBeanPostProcessors(beanFactory);

         // Initialize message source for this context.
         //不重要,国际化的处理
         // STEP 7: 初始化一些消息源(比如处理国际化的i18n等消息源)
         initMessageSource();

         // Initialize event multicaster for this context.
         //事件处理,用的比较少,不重要
         // STEP 8: 初始化应用事件广播器
         initApplicationEventMulticaster();

         // Initialize other special beans in specific context subclasses.
         //这是一个空壳方法,里面没有代码
         // STEP 9: 初始化一些特殊的bean
         onRefresh();

         // Check for listener beans and register them.
         //对一些监听器的注册,先放一放
         // STEP 10: 注册一些监听器
         registerListeners();

         // Instantiate all remaining (non-lazy-init) singletons.
         //重点,重点
         //完成bean的实例化
         // STEP 11: 实例化剩余的单例bean(非懒加载方式)
         // 注意事项:Bean的IoC、DI和AOP都是发生在此步骤
         finishBeanFactoryInitialization(beanFactory);

         // Last step: publish corresponding event.
         // STEP 12: 完成刷新时,需要发布对应的事件
         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();
      }
   }
}

image.png

image.png

接着查看org.springframework.context.support.AbstractRefreshableApplicationContext#refreshBeanFactory方法。

/**
 * This implementation performs an actual refresh of this context's underlying
 * bean factory, shutting down the previous bean factory (if any) and
 * initializing a fresh bean factory for the next phase of the context's lifecycle.
 * 真正调用该方法
 * 销毁以前的容器
 * 创建新的`IoC容器`
 * 加载`BeanDefinition`对象注册到IoC容器中
 */
@Override
protected final void refreshBeanFactory() throws BeansException {
   //如果之前有IOC容器,则销毁
   if (hasBeanFactory()) {
      destroyBeans();
      closeBeanFactory();
   }
   try {
      //创建IOC容器,也就是DefaultListableBeanFactory
      DefaultListableBeanFactory beanFactory = createBeanFactory();
      beanFactory.setSerializationId(getId());
      //设置工厂属性:是否允许BeanDefinition覆盖和是否允许循环依赖
      customizeBeanFactory(beanFactory);
      //加载BeanDefinition对象,并注册到IOC容器中(重点)
      //真正调用AbstractXmlApplicationContext类中的loadBeanDefinitions方法
      //重点这一步
      loadBeanDefinitions(beanFactory);
      synchronized (this.beanFactoryMonitor) {
         this.beanFactory = beanFactory;
      }
   }
   catch (IOException ex) {
      throw new ApplicationContextException("I/O error parsing bean definition source for " + getDisplayName(), ex);
   }
}

BeanFactory的创建在第二步:obtainFreshBeanFactory方法中

image.png

image.png

BeanFactory的创建的时序图如下:

image.png

BeanDefifinition加载解析及注册⼦流程

入口跟上面创建BeanFactory一样,也是在:obtainFreshBeanFactory方法中

image.png

image.png

/**
 * This implementation performs an actual refresh of this context's underlying
 * bean factory, shutting down the previous bean factory (if any) and
 * initializing a fresh bean factory for the next phase of the context's lifecycle.
 * 真正调用该方法
 * 销毁以前的容器
 * 创建新的`IoC容器`
 * 加载`BeanDefinition`对象注册到IoC容器中
 */
@Override
protected final void refreshBeanFactory() throws BeansException {
   //如果之前有IOC容器,则销毁
   if (hasBeanFactory()) {
      destroyBeans();
      closeBeanFactory();
   }
   try {
      //创建IOC容器,也就是DefaultListableBeanFactory
      DefaultListableBeanFactory beanFactory = createBeanFactory();
      beanFactory.setSerializationId(getId());
      //设置工厂属性:是否允许BeanDefinition覆盖和是否允许循环依赖
      customizeBeanFactory(beanFactory);
      //加载BeanDefinition对象,并注册到IOC容器中(重点)
      //真正调用AbstractXmlApplicationContext类中的loadBeanDefinitions方法
      //重点这一步
      loadBeanDefinitions(beanFactory);
      synchronized (this.beanFactoryMonitor) {
         this.beanFactory = beanFactory;
      }
   }
   catch (IOException ex) {
      throw new ApplicationContextException("I/O error parsing bean definition source for " + getDisplayName(), ex);
   }
}

重点看:loadBeanDefinitions(beanFactory)方法

image.png

咱们先看基于xml方式的AbstractXmlApplicationContext类

/**
 * 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 {
   // Create a new XmlBeanDefinitionReader for the given BeanFactory.
   //创建一个BeanDefinition阅读器,通过阅读XML文件,真正完成BeanDefinition的加载和注册
   //其实就是一种委托模式
   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);
   //重点
   //委托给BeanDefinition阅读器去加载BeanDefinition
   loadBeanDefinitions(beanDefinitionReader);
}
protected void loadBeanDefinitions(XmlBeanDefinitionReader reader) throws BeansException, IOException {
   // 获取资源的定位
   // 这里getConfigResources是一个空实现,真正实现是调用子类的获取资源定位的方法
   // 比如:ClassPathXmlApplicationContext中进行了实现
   //        而FileSystemXmlApplicationContext没有使用该方法
   Resource[] configResources = getConfigResources();
   if (configResources != null) {
      // XML Bean读取器调用其父类AbstractBeanDefinitionReader中的loadBeanDefinitions读取定位的资源
      //重点
      reader.loadBeanDefinitions(configResources);
   }
   // 如果子类中获取的资源定位为空,则获取FileSystemXmlApplicationContext构造方法中setConfigLocations方法设置的资源
   String[] configLocations = getConfigLocations();
   if (configLocations != null) {
      // XML Bean读取器调用其父类AbstractBeanDefinitionReader读取定位的资源
      //重点
      reader.loadBeanDefinitions(configLocations);
   }
}

接着:org.springframework.beans.factory.support.AbstractBeanDefinitionReader#loadBeanDefinitions方法

//真正调用该方法
@Override
public int loadBeanDefinitions(String... locations) throws BeanDefinitionStoreException {
   Assert.notNull(locations, "Location array must not be null");
   int counter = 0;
   //如果是多个配置文件,循环读取加载,并统计总共加载了多少个BeanDefinition
   for (String location : locations) {
      counter += loadBeanDefinitions(location);
   }
   return counter;
}
@Override
public int loadBeanDefinitions(String location) throws BeanDefinitionStoreException {
   //重点
   return loadBeanDefinitions(location, null);
}
public int loadBeanDefinitions(String location, @Nullable Set<Resource> actualResources) throws BeanDefinitionStoreException {
   //获取在IOC容器初始化过程中设置的资源加载器
   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);
         //重点:委派调用其子类XmlBeanDefinitionReader的方法,实现加载功能
         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;
   }
}
public int loadBeanDefinitions(Resource... resources) throws BeanDefinitionStoreException {
   Assert.notNull(resources, "Resource array must not be null");
   int counter = 0;
   for (Resource resource : resources) {
      //重点:
      //真正调用子类XmlBeanDefinitionReader中的loadBeanDefinitions方法
      counter += loadBeanDefinitions(resource);
   }
   return counter;
}

image.png

接着:org.springframework.beans.factory.xml.XmlBeanDefinitionReader#loadBeanDefinitions方法

public int loadBeanDefinitions(Resource resource) throws BeanDefinitionStoreException {
   //将读入的XML资源进行特殊编码处理
   //接着继续调用该类中的下面的loadBeanDefinitions方法
   return loadBeanDefinitions(new EncodedResource(resource));
}
public int loadBeanDefinitions(EncodedResource encodedResource) throws BeanDefinitionStoreException {
   Assert.notNull(encodedResource, "EncodedResource must not be null");
   if (logger.isInfoEnabled()) {
      logger.info("Loading XML bean definitions from " + encodedResource);
   }

   Set<EncodedResource> currentResources = this.resourcesCurrentlyBeingLoaded.get();
   if (currentResources == null) {
      currentResources = new HashSet<>(4);
      this.resourcesCurrentlyBeingLoaded.set(currentResources);
   }
   if (!currentResources.add(encodedResource)) {
      throw new BeanDefinitionStoreException(
            "Detected cyclic loading of " + encodedResource + " - check your import definitions!");
   }
   try {
      //将资源文件转为InputStream的IO流
      InputStream inputStream = encodedResource.getResource().getInputStream();
      try {
         //从InputStream中得到XML的解析源
         InputSource inputSource = new InputSource(inputStream);
         if (encodedResource.getEncoding() != null) {
            inputSource.setEncoding(encodedResource.getEncoding());
         }
         //重点:这里是具体的读取过程
         return doLoadBeanDefinitions(inputSource, encodedResource.getResource());
      }
      finally {
         inputStream.close();
      }
   }
   catch (IOException ex) {
      throw new BeanDefinitionStoreException(
            "IOException parsing XML document from " + encodedResource.getResource(), ex);
   }
   finally {
      currentResources.remove(encodedResource);
      if (currentResources.isEmpty()) {
         this.resourcesCurrentlyBeingLoaded.remove();
      }
   }
}
**
 * Actually load bean definitions from the specified XML file.
 * @param inputSource the SAX InputSource to read from
 * @param resource the resource descriptor for the XML file
 * @return the number of bean definitions found
 * @throws BeanDefinitionStoreException in case of loading or parsing errors
 * @see #doLoadDocument
 * @see #registerBeanDefinitions
 * 真正调用该方法
 * 还是在本类即XmlBeanDefinitionReader类中的方法
 */
protected int doLoadBeanDefinitions(InputSource inputSource, Resource resource)
      throws BeanDefinitionStoreException {
   try {
      //通过dom4j加载解析XML文件,最终形成Document对象
      Document doc = doLoadDocument(inputSource, resource);
      //通过对Document对象的操作,完成BeanDefinition的加载和注册工作
      return registerBeanDefinitions(doc, resource);
   }
   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);
   }
}

image.png

org.springframework.beans.factory.xml.XmlBeanDefinitionReader#doLoadBeanDefinitions方法

以上一共分为两个步骤:

  • 使用dom4j将applicationContext.xml配置文件解析成Document对象
  • 将Document对象解析,并封装成BeanDefinition对象,最后存入到上面创建出来的DefaultListableBeanFactory(可以理解成Ioc容器)中的beanDefinitionMap中。

image.png

第一步

使用dom4j将applicationContext.xml配置文件解析成Document对象

image.png

/**
 * Actually load the specified document using the configured DocumentLoader.
 * @param inputSource the SAX InputSource to read from
 * @param resource the resource descriptor for the XML file
 * @return the DOM Document
 * @throws Exception when thrown from the DocumentLoader
 * @see #setDocumentLoader
 * @see DocumentLoader#loadDocument
 * 通过dom4j加载解析XML文件,最终形成Document对象
 */
protected Document doLoadDocument(InputSource inputSource, Resource resource) throws Exception {
   return this.documentLoader.loadDocument(inputSource, getEntityResolver(), this.errorHandler,
         getValidationModeForResource(resource), isNamespaceAware());
}

后面具体的解析就不具体看了。

第二步

将Document对象解析,并封装成BeanDefinition对象,最后存入到上面创建出来的DefaultListableBeanFactory(可以理解成Ioc容器)中的beanDefinitionMap中。

image.png

/**
 * 重点
 * 还是调用该类即XmlBeanDefinitionReader类中的registerBeanDefinitions方法
 *
 */
public int registerBeanDefinitions(Document doc, Resource resource) throws BeanDefinitionStoreException {
   //创建BeanDefinitionDocumentReader用来解析Document对象
   BeanDefinitionDocumentReader documentReader = createBeanDefinitionDocumentReader();
   //获取容器中已经注册的Bean数量
   int countBefore = getRegistry().getBeanDefinitionCount();
   //解析过程入口,BeanDefinitionDocumentReader只是一个接口
   //具体的实现过程在DefaultBeanDefinitionDocumentReader完成
   //重点
   documentReader.registerBeanDefinitions(doc, createReaderContext(resource));
   //统计新注册的Bean数量
   return getRegistry().getBeanDefinitionCount() - countBefore;
}

接着:org.springframework.beans.factory.xml.DefaultBeanDefinitionDocumentReader#registerBeanDefinitions方法


/**
 * 来解析Document对象
 */
@Override
public void registerBeanDefinitions(Document doc, XmlReaderContext readerContext) {
   this.readerContext = readerContext;
   logger.debug("Loading bean definitions");
   //首先获取根节点
   // 获得Document的根元素<beans>标签
   Element root = doc.getDocumentElement();
   //重点
   doRegisterBeanDefinitions(root);
}
/**
 * Register each bean definition within the given root {@code <beans/>} element.
 * 重点
 * 还是调用该类中的doRegisterBeanDefinitions方法
 * 1.这里使用了委托模式,将具体的BeanDefinition解析工作交给了BeanDefinitionParserDelegate去完成
 * 2.在解析Bean定义之前,进行自定义的解析,增强解析过程的可扩展性
 * 3.委托给BeanDefinitionParserDelegate,从Document的根元素开始进行BeanDefinition的解析
 *
 */
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.

   // 这里使用了委托模式,将具体的BeanDefinition解析工作交给了BeanDefinitionParserDelegate去完成
   BeanDefinitionParserDelegate parent = this.delegate;
   this.delegate = createDelegate(getReaderContext(), root, parent);

   //判断命名空间是否是http://www.springframework.org/schema/beans
   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;
         }
      }
   }

   // 在解析Bean定义之前,进行自定义的解析,增强解析过程的可扩展性
   preProcessXml(root);
   // 委托给BeanDefinitionParserDelegate,从Document的根元素开始进行BeanDefinition的解析
   //重点
   parseBeanDefinitions(root, this.delegate);
   // 在解析Bean定义之后,进行自定义的解析,增加解析过程的可扩展性
   postProcessXml(root);

   this.delegate = parent;
}
/**
 * Parse the elements at the root level in the document:
 * "import", "alias", "bean".
 * @param root the DOM root element of the document
 * 还是调用该类的方法parseBeanDefinitions方法
 *  该方法为AOP的入口
 *
 */
protected void parseBeanDefinitions(Element root, BeanDefinitionParserDelegate delegate) {
   //加载的Documen对象是否使用了Spring默认的XML命名空间(beans命名空间)
   //即beans标签中的xmlns中的http://www.springframework.org/schema/beans
   if (delegate.isDefaultNamespace(root)) {
      //获取Document对象根元素的所有子节点(bean标签,Import标签,alias标签和其他自定义标签context,aop等)
      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;
            //bean标签,import标签,alias标签,则默认使用解析规则
            //注意只要是不带冒号的标签都是属于默认命名空间的,比如<config:aop>就不是
            if (delegate.isDefaultNamespace(ele)) {
               parseDefaultElement(ele, delegate);
            }
            //像context标签,aop标签,tx标签,则使用用户自定义的解析规则解析元素
            else {
               delegate.parseCustomElement(ele);
            }
         }
      }
   }
   else {
      // 如果不是默认的命名空间,则使用用户自定义的解析规则解析元素节点
      delegate.parseCustomElement(root);
   }
}
//重点,还是调用该类中的方法
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>标签 重点
   else if (delegate.nodeNameEquals(ele, BEAN_ELEMENT)) {
      processBeanDefinition(ele, delegate);
   }
   //解析内置<bean>标签
   else if (delegate.nodeNameEquals(ele, NESTED_BEANS_ELEMENT)) {
      // recurse
      //递归调用
      doRegisterBeanDefinitions(ele);
   }
}
/**
 * Process the given bean element, parsing the bean definition
 * and registering it with the registry.
 * 还是调用该类中的方法
 */
protected void processBeanDefinition(Element ele, BeanDefinitionParserDelegate delegate) {
   //解析<bean>标签,获取BeanDefnition 重点
   BeanDefinitionHolder bdHolder = delegate.parseBeanDefinitionElement(ele);
   if (bdHolder != null) {
      //如果需要,则装饰BeanDefinition对象
      bdHolder = delegate.decorateBeanDefinitionIfRequired(ele, bdHolder);
      try {
         // Register the final decorated instance.
         //重点
         //注册最终的BeanDefinition到BeanDefinitionRegistry(即DefaultListableBeanFactory)
         //因为DefaultListableBeanFactory实现了BeanDefinitionRegistry
         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));
   }
}

以上分为两个步骤:

  • 首先将Document解析出来封装成BeanDefinition,并放在BeanDefinitionHolder中。
  • 将BeanDefinition对象存入到DefaultListableBeanFactory对象中的beanDefinitionMap中。

1.将Document解析出来封装成BeanDefinition,并放在BeanDefinitionHolder中。

image.png

接着:org.springframework.beans.factory.xml.BeanDefinitionParserDelegate#parseBeanDefinitionElement方法

/**
 * Parses the supplied {@code <bean>} element. May return {@code null}
 * if there were errors during parse. Errors are reported to the
 * {@link org.springframework.beans.factory.parsing.ProblemReporter}.
 * 真正调用该方法:重点
 */
@Nullable
public BeanDefinitionHolder parseBeanDefinitionElement(Element ele) {
   return parseBeanDefinitionElement(ele, null);
}
/**
 * Parses the supplied {@code <bean>} element. May return {@code null}
 * if there were errors during parse. Errors are reported to the
 * {@link org.springframework.beans.factory.parsing.ProblemReporter}.
 * 真正调用该方法:重点
 */
@Nullable
public BeanDefinitionHolder parseBeanDefinitionElement(Element ele, @Nullable BeanDefinition containingBean) {
   //获取<bean>标签中的属性id的值
   String id = ele.getAttribute(ID_ATTRIBUTE);
   //获取<bean>标签中的属性name的值
   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;
   if (!StringUtils.hasText(beanName) && !aliases.isEmpty()) {
      beanName = aliases.remove(0);
      if (logger.isDebugEnabled()) {
         logger.debug("No XML 'id' specified - using '" + beanName +
               "' as bean name and " + aliases + " as aliases");
      }
   }

   if (containingBean == null) {
      //检查bean的id或者name是否唯一
      checkNameUniqueness(beanName, aliases, ele);
   }

   //解析<bean>标签,获得BeanDefinition对象:重点
   AbstractBeanDefinition beanDefinition = parseBeanDefinitionElement(ele, beanName, containingBean);
   if (beanDefinition != null) {
      if (!StringUtils.hasText(beanName)) {
         try {
            if (containingBean != null) {
               beanName = BeanDefinitionReaderUtils.generateBeanName(
                     beanDefinition, this.readerContext.getRegistry(), true);
            }
            else {
               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.
               String beanClassName = beanDefinition.getBeanClassName();
               if (beanClassName != null &&
                     beanName.startsWith(beanClassName) && beanName.length() > beanClassName.length() &&
                     !this.readerContext.getRegistry().isBeanNameInUse(beanClassName)) {
                  aliases.add(beanClassName);
               }
            }
            if (logger.isDebugEnabled()) {
               logger.debug("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);
      //将BeanDefinition封装到BeanDefinitionHolder数据结构中
      return new BeanDefinitionHolder(beanDefinition, beanName, aliasesArray);
   }

   return null;
}
**
 * Parse the bean definition itself, without regard to name or aliases. May return
 * {@code null} if problems occurred during the parsing of the bean definition.
 * 真正调用该方法:重点
 * 获得BeanDefinition对象
 */
@Nullable
public AbstractBeanDefinition parseBeanDefinitionElement(
      Element ele, String beanName, @Nullable BeanDefinition containingBean) {

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

   String className = null;
   if (ele.hasAttribute(CLASS_ATTRIBUTE)) {
      className = ele.getAttribute(CLASS_ATTRIBUTE).trim();
   }
   String parent = null;
   //获取bean标签的parent属性
   if (ele.hasAttribute(PARENT_ATTRIBUTE)) {
      parent = ele.getAttribute(PARENT_ATTRIBUTE);
   }

   try {
      //重点:创建BeanDefinition对象GenericBeanDefinition
      AbstractBeanDefinition bd = createBeanDefinition(className, parent);

      //将下列解析到的bean标签中的属性信息到设置到创建出来的BeanDefinition对象中,即全部封装到BeanDefinition对象

      //解析<bean>标签的属性
      parseBeanDefinitionAttributes(ele, beanName, containingBean, bd);
      //解析<bean>标签的子标签
      //解析<description>标签
      bd.setDescription(DomUtils.getChildElementValueByTagName(ele, DESCRIPTION_ELEMENT));

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

      //解析<contructor-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;
}
/**
 * Create a bean definition for the given class name and parent name.
 * @param className the name of the bean class
 * @param parentName the name of the bean's parent bean
 * @return the newly created bean definition
 * @throws ClassNotFoundException if bean class resolution was attempted but failed
 * 重点:创建BeanDefinition对象
 */
protected AbstractBeanDefinition createBeanDefinition(@Nullable String className, @Nullable String parentName)
      throws ClassNotFoundException {

   return BeanDefinitionReaderUtils.createBeanDefinition(
         parentName, className, this.readerContext.getBeanClassLoader());
}

接着:org.springframework.beans.factory.support.BeanDefinitionReaderUtils#createBeanDefinition方法

public static AbstractBeanDefinition createBeanDefinition(
      @Nullable String parentName, @Nullable String className, @Nullable ClassLoader classLoader) throws ClassNotFoundException {

   //创建BeanDefinition对象----终于到头了
   GenericBeanDefinition bd = new GenericBeanDefinition();
   bd.setParentName(parentName);
   if (className != null) {
      if (classLoader != null) {
         bd.setBeanClass(ClassUtils.forName(className, classLoader));
      }
      else {
         bd.setBeanClassName(className);
      }
   }
   return bd;
}

2.将BeanDefinition对象存入到DefaultListableBeanFactory对象中的beanDefinitionMap中。

image.png

接着:org.springframework.beans.factory.support.BeanDefinitionReaderUtils#registerBeanDefinition方法

/**
 * Register the given bean definition with the given bean factory.
 * @param definitionHolder the bean definition including name and aliases
 * @param registry the bean factory to register with
 * @throws BeanDefinitionStoreException if registration failed
 * 真正调用该方法
 * 很重要,把bd放到bdMap中
 */
public static void registerBeanDefinition(
      BeanDefinitionHolder definitionHolder, BeanDefinitionRegistry registry)
      throws BeanDefinitionStoreException {

   // Register bean definition under primary name.
   String beanName = definitionHolder.getBeanName();
   //把BeanDefinitionHolder中的key和value进行拆开传进去
   //通过该方法把bd注册进bdMap中去
   //真正调用DefaultListableBeanFactory中的registerBeanDefinition完成BeanDefinition注册
   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);
      }
   }
}

image.png

最后:org.springframework.beans.factory.support.DefaultListableBeanFactory#registerBeanDefinition方法

//该方法将BeanDefinition注册到bdMap中
@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);
      }
   }

   BeanDefinition existingDefinition = this.beanDefinitionMap.get(beanName);
   if (existingDefinition != null) {
      if (!isAllowBeanDefinitionOverriding()) {
         throw new BeanDefinitionStoreException(beanDefinition.getResourceDescription(), beanName,
               "Cannot register bean definition [" + beanDefinition + "] for bean '" + beanName +
               "': There is already [" + existingDefinition + "] bound.");
      }
      else if (existingDefinition.getRole() < beanDefinition.getRole()) {
         // e.g. was ROLE_APPLICATION, now overriding with ROLE_SUPPORT or ROLE_INFRASTRUCTURE
         if (logger.isWarnEnabled()) {
            logger.warn("Overriding user-defined bean definition for bean '" + beanName +
                  "' with a framework-generated bean definition: replacing [" +
                  existingDefinition + "] with [" + beanDefinition + "]");
         }
      }
      else if (!beanDefinition.equals(existingDefinition)) {
         if (logger.isInfoEnabled()) {
            logger.info("Overriding bean definition for bean '" + beanName +
                  "' with a different definition: replacing [" + existingDefinition +
                  "] with [" + beanDefinition + "]");
         }
      }
      else {
         if (logger.isDebugEnabled()) {
            logger.debug("Overriding bean definition for bean '" + beanName +
                  "' with an equivalent definition: replacing [" + existingDefinition +
                  "] with [" + beanDefinition + "]");
         }
      }
      this.beanDefinitionMap.put(beanName, beanDefinition);
   }
   else {
      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;
            if (this.manualSingletonNames.contains(beanName)) {
               Set<String> updatedSingletons = new LinkedHashSet<>(this.manualSingletonNames);
               updatedSingletons.remove(beanName);
               this.manualSingletonNames = updatedSingletons;
            }
         }
      }
      else {
         // Still in startup registration phase
         //重点
         //DefaultListableBeanFactory把BeanDefinitionHolder中的bd和beanName放入到map集合中
         this.beanDefinitionMap.put(beanName, beanDefinition);
         this.beanDefinitionNames.add(beanName);
         this.manualSingletonNames.remove(beanName);
      }
      this.frozenBeanDefinitionNames = null;
   }

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

总结

将applicationContext.xml配置文件中的内容使用dom4j解析成Document对象,接着将Document对象解析,并封装成BeanDefinition对象,最后将BeanDefinition对象存入到DefaultListableBeanFactory对象中的Map<String, BeanDefinition> beanDefinitionMap中,key为bean的id,即beanName,value为对应的BeanDifinition对象,即类的定义信息,例如beanName,是否单例,是否懒加载,属性信息,初始化方法等等。