spring源码解析流程,一步一步在源码加注释带你了解bean的加载过程

spring

前述:spring源码环境搭建以及源码下载在文章后方有链接,可自行参考搭建,这里只是对加载过程做一个解析,spring全家桶远不止这些东东,感兴趣的小伙伴可以去官网看一下,本文将以源码加注释的方式进行过程解析,带你了解spring中bean到底是如何一步步加载完成

了解重点:bean的生命周期、加载过程

最终目的:学习spring源码短期内不对对你的技术有太大提升,可能只是了解到漂亮的代码是如何写出来,为何别人写代码就不是简单的接口加上无限的if-else,所以加强基础知识的学习、多去思考如何优化逻辑才会有效提高编程效率。spring源码经历了多年的沉淀,没有一年半载很难搞透彻,所以什么手撕源码还是要慎重,大部分源码博客都只是告诉你源码的执行过程,不会告诉你原理和如何去改造,本文也是如此

本文目录:也就是bean加载的大致过程

1.使用ClassPathResource对配置文件进行封装

BeanFactory beanFactory = new XmlBeanFactory(new ClassPathResource("beanFactoryTest.xml"));

1>对路径进行解析,包括\替换为/,’.’,’:'的判断,最终返回可解析的路径

2>通过路径以及类加载器构建ClassPathResource对象

this(path, (ClassLoader) null);

3>使用XmlBeanFactory进行文件的读取工作

public XmlBeanFactory(Resource resource, BeanFactory parentBeanFactory) throws BeansException {
   /** 对父类 DefaultListableBeanFactory进行实例化 */
   super(parentBeanFactory);
   this.reader.loadBeanDefinitions(resource);
}
/**
 * Create a new DefaultListableBeanFactory.
 */
public DefaultListableBeanFactory() {
   super();
}

继续跟踪到AbstractAutowireCapableBeanFactory类下

/**
 * Create a new AbstractAutowireCapableBeanFactory.
 */
public AbstractAutowireCapableBeanFactory() {
   super();
   /**ignoreDependencyInterface方法注解
    * 作用:假如A中有属性B,初始化A时会先对B进行初始化,这是spring的一个重要特性
    * 会A加载时自动忽略给定的依赖接口
    * */
   ignoreDependencyInterface(BeanNameAware.class);
   ignoreDependencyInterface(BeanFactoryAware.class);
   ignoreDependencyInterface(BeanClassLoaderAware.class);
}

4>实例化XmlBeanFactory后,开始真正的工作,接步骤3中图1第二行

this.reader.loadBeanDefinitions(resource);

2.资源加载的开始

注:

//DefaultListableBeanFactory--整个bean加载的核心部分,是spring注册以及加载bean的默认实现,主要用于bean注册后的处理
public class XmlBeanFactory extends DefaultListableBeanFactory {
   //XmlBeanFactory 与父类的区别在于实现了自定义的xml读取器XmlBeanDefinitionReader,使用reader属性对资源文件进行读取和注册
   private final XmlBeanDefinitionReader reader = new XmlBeanDefinitionReader(this);

1>进入资源文件加载的第一步:对文件编码进行处理

@Override
public int loadBeanDefinitions(Resource resource) throws BeanDefinitionStoreException {
   /** 使用EncodedResource对resource进行封装,作用是对资源文件的编码进行处理
    * */
   return loadBeanDefinitions(new EncodedResource(resource));
}

EncodedResource只是对属性进行封装,不做其他处理

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;
}

继续回到资源加载的核心部分

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<EncodedResource> currentResources = this.resourcesCurrentlyBeingLoaded.get();

   if (!currentResources.add(encodedResource)) {
      throw new BeanDefinitionStoreException(
            "Detected cyclic loading of " + encodedResource + " - check your import definitions!");
   }
   /**从resource中获取对应的inputStream并构造inputResource */
   try (InputStream inputStream = encodedResource.getResource().getInputStream()) {
      InputSource inputSource = new InputSource(inputStream);
      if (encodedResource.getEncoding() != null) {
         inputSource.setEncoding(encodedResource.getEncoding());
      }
      /** 以上只是对resource参数进行封装,考虑到其编码问题,下面进入核心处理部分**/
      return doLoadBeanDefinitions(inputSource, encodedResource.getResource());
   }
   catch (IOException ex) {
      throw new BeanDefinitionStoreException(
            "IOException parsing XML document from " + encodedResource.getResource(), ex);
   }
   finally {
      currentResources.remove(encodedResource);
      if (currentResources.isEmpty()) {
         this.resourcesCurrentlyBeingLoaded.remove();
      }
   }
}

步骤分解:

2通过属性来记录已经加载的文件

private final ThreadLocal<Set<EncodedResource>> resourcesCurrentlyBeingLoaded =
      new NamedThreadLocal<Set<EncodedResource>>("XML bean definition resources currently being loaded"){
         @Override
         protected Set<EncodedResource> initialValue() {
            return new HashSet<>(4);
         }
      };

3将其加入到本地已加载属性中

if (!currentResources.add(encodedResource)) {
   throw new BeanDefinitionStoreException(
         "Detected cyclic loading of " + encodedResource + " - check your import definitions!");
}

4获取输入流对resource进行解析

try (InputStream inputStream = encodedResource.getResource().getInputStream()) {
   InputSource inputSource = new InputSource(inputStream);
   if (encodedResource.getEncoding() != null) {
      inputSource.setEncoding(encodedResource.getEncoding());
   }
   /** 以上只是对resource参数进行封装,考虑到其编码问题,下面进入核心处理部分**/
   return doLoadBeanDefinitions(inputSource, encodedResource.getResource());
}

5若解析失败,将其从本地属性中移除

finally {
   currentResources.remove(encodedResource);
   if (currentResources.isEmpty()) {
      this.resourcesCurrentlyBeingLoaded.remove();
   }
}

3 进入bean加载核心处理部分

return doLoadBeanDefinitions(inputSource, encodedResource.getResource());

它做的事情大致如下:主要包括两步

/** 1.获取对XMl文件的验证格式xsd或dtd
	 * 2.加载xml封装为document
	 * 3.根据返回的document封装bean**/
Document doc = doLoadDocument(inputSource, resource);
int count = registerBeanDefinitions(doc, resource);
if (logger.isDebugEnabled()) {
   logger.debug("Loaded " + count + " bean definitions from " + resource);
}
return count;

1>把xml文件封装为document,其中包含验证模式的读取(之前是单独方法进行读取,现改为了在文件加载中验证)

protected Document doLoadDocument(InputSource inputSource, Resource resource) throws Exception {
    /**  这里解析一下getEntityResolver是做什么的,作用是提供给项目一个寻找dtd验证模式的方法
     原始的是根据路径去下载验证文件,为避免网络的影响,在本地存贮一个验证文件    **/
   return this.documentLoader.loadDocument(inputSource, getEntityResolver(), this.errorHandler,
         getValidationModeForResource(resource), isNamespaceAware());
}

​ 模式验证:其实就是一行一行的读取文件,获取其中是否包含某个关键词(doctype)

protected int getValidationModeForResource(Resource resource) {
   int validationModeToUse = getValidationMode();
   /** 如果已经指定验证模式,则使用指定的验证模式,没有指定则使用自动的 **/
   if (validationModeToUse != VALIDATION_AUTO) {
      return validationModeToUse;
   }
   /** 自动检测验证模式功能 **/
   int detectedMode = detectValidationMode(resource);
   if (detectedMode != VALIDATION_AUTO) {
      return detectedMode;
   }
   // Hmm, we didn't get a clear indication... Let's assume XSD,
   // since apparently no DTD declaration has been found up until
   // detection stopped (before finding the document's root tag).
   return VALIDATION_XSD;
}

验证的具体过程:detectValidationMode方法进入

try {
   inputStream = resource.getInputStream();
}
catch (IOException ex) {
   throw new BeanDefinitionStoreException(
         "Unable to determine validation mode for [" + resource + "]: cannot open InputStream. " +
         "Did you attempt to load directly from a SAX InputSource without specifying the " +
         "validationMode on your XmlBeanDefinitionReader instance?", ex);
}

try {
   return this.validationModeDetector.detectValidationMode(inputStream);
}

detectValidationMode进入:只是指定最后的验证模式

public int detectValidationMode(InputStream inputStream) throws IOException {
   // Peek into the file to look for DOCTYPE.
   BufferedReader reader = new BufferedReader(new InputStreamReader(inputStream));
   try {
      boolean isDtdValidated = false;
      String content;
      while ((content = reader.readLine()) != null) {
         content = consumeCommentTokens(content);
         if (this.inComment || !StringUtils.hasText(content)) {
            continue;
         }
         if (hasDoctype(content)) {
            isDtdValidated = true;
            break;
         }
         if (hasOpeningTag(content)) {
            // End of meaningful data...
            break;
         }
      }
      return (isDtdValidated ? VALIDATION_DTD : VALIDATION_XSD);
   }
   catch (CharConversionException ex) {
      // Choked on some character encoding...
      // Leave the decision up to the caller.
      return VALIDATION_AUTO;
   }
   finally {
      reader.close();
   }
}

到此结束:doLoadDocument

下面分析其中的一个类:getEntityResolver(作用:尝试去下载验证文件或者加载本地验证文件)

protected EntityResolver getEntityResolver() {
   if (this.entityResolver == null) {
      // Determine default EntityResolver to use.
      ResourceLoader resourceLoader = getResourceLoader();
      if (resourceLoader != null) {
         this.entityResolver = new ResourceEntityResolver(resourceLoader);
      }
      else {
         this.entityResolver = new DelegatingEntityResolver(getBeanClassLoader());
      }
   }
   return this.entityResolver;
}

以DelegatingEntityResolver为例进入方法:做的什么???

public DelegatingEntityResolver(@Nullable ClassLoader classLoader) {
   this.dtdResolver = new BeansDtdResolver();
   this.schemaResolver = new PluggableSchemaResolver(classLoader);
}

实现类:public class BeansDtdResolver implements EntityResolver;指定了验证文件的两个重要属性

实例化了两个解析器,一个dtd文件解析器,一个模式解析器

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-PwUdt5Ik-1629963237562)(C:\Users\15515\AppData\Roaming\Typora\typora-user-images\image-20210728175913418.png)]

@Override
@Nullable
public InputSource resolveEntity(@Nullable String publicId, @Nullable String systemId) throws IOException {
   if (logger.isTraceEnabled()) {
      logger.trace("Trying to resolve XML entity with public ID [" + publicId +
            "] and system ID [" + systemId + "]");
   }

   if (systemId != null && systemId.endsWith(DTD_EXTENSION)) {
      int lastPathSeparator = systemId.lastIndexOf('/');
      int dtdNameStart = systemId.indexOf(DTD_NAME, lastPathSeparator);
      if (dtdNameStart != -1) {
         String dtdFile = DTD_NAME + DTD_EXTENSION;
         if (logger.isTraceEnabled()) {
            logger.trace("Trying to locate [" + dtdFile + "] in Spring jar on classpath");
         }
         try {
            Resource resource = new ClassPathResource(dtdFile, getClass());
            InputSource source = new InputSource(resource.getInputStream());
            source.setPublicId(publicId);
            source.setSystemId(systemId);
            if (logger.isTraceEnabled()) {
               logger.trace("Found beans DTD [" + systemId + "] in classpath: " + dtdFile);
            }
            return source;
         }
         catch (FileNotFoundException ex) {
            if (logger.isDebugEnabled()) {
               logger.debug("Could not resolve beans DTD [" + systemId + "]: not found in classpath", ex);
            }
         }
      }
   }

   // Fall back to the parser's default behavior.
   return null;
}

2>把文件转换为document后进行bean的注册以及加载(较为重要的部分,是真正的bean加载过程,前边都是准备工作)

1.把文件转化为docuemnt对象
/*把文件转化为document对象后开始bean的注册以及加载
 */
public int registerBeanDefinitions(Document doc, Resource resource) throws BeanDefinitionStoreException {
   /** 使用DefaultBeanDefinitionDocumentReader来实例化BeanDefinitionDocumentReader对象 **/
   BeanDefinitionDocumentReader documentReader = createBeanDefinitionDocumentReader();
   /** 这里去除了之前设置环境变量的一步 **/
   /** 记录之前BeanDefinition加载的个数 **/
   int countBefore = getRegistry().getBeanDefinitionCount();
   /** 加载及注册bean **/
   documentReader.registerBeanDefinitions(doc, createReaderContext(resource));
   /** 记录本次加载的bean个数 **/
   return getRegistry().getBeanDefinitionCount() - countBefore;
}

开始对配置文件属性进行解析,包括很多标签中声明的属性(注:此版本源码与pdf中有所不同,只是改变了写法而已)

 /* doc.getDocumentElement()返回Element root对象
 * 本方法就是提取root作为参数继续BeanDefinition的注册
 */
@Override
public void registerBeanDefinitions(Document doc, XmlReaderContext readerContext) {
   this.readerContext = readerContext;
   /** 真正对文件解析属性注册bean的开始 **/
   doRegisterBeanDefinitions(doc.getDocumentElement());
}

解析方法

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

   if (this.delegate.isDefaultNamespace(root)) {
      //对profile进行处理解析,可了解profile属性的作用以及使用,从根节点依次开始获取属性
      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;
         }
      }
   }
   /** preProcessXml、postProcessXml两个方法是空的,作用是解析bean前预处理、解析后处理,根据面向对象设计原则,一个类要么面向继承设计,要么用final修饰
    * 这里是交给子类来实现的 **/
   preProcessXml(root);
   parseBeanDefinitions(root, this.delegate);
   postProcessXml(root);

   this.delegate = parent;
}

以下是对上面的解析过程parseBeanDefinitions进行拆解分步解析:

2.获取bean的声明方式,是否为默认声明方式,不同的声明方式有不同的解析方式
protected void parseBeanDefinitions(Element root, BeanDefinitionParserDelegate delegate) {
   /** 获取是否为自定义命名空间,默认的和非默认的使用不同的处理方式 因为spring xml中bean的声明方式有两种
    * 1.<bean id="" class=""/> 这一种是spring默认的
    * 2.<tx annotation-driven/>  **/
   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)) {
               //如果默认声明方式
               parseDefaultElement(ele, delegate);
            }
            else {//非默认声明方式
               delegate.parseCustomElement(ele);
            }
         }
      }
   }
   else {
      delegate.parseCustomElement(root);
   }
}

默认标签的解析方式:

3.对import、alias标签进行解析
/** 默认标签的解析 **/
private void parseDefaultElement(Element ele, BeanDefinitionParserDelegate delegate) {
   if (delegate.nodeNameEquals(ele, IMPORT_ELEMENT)) {/** 默认标签的解析 **/
	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);
		}
		/** 以此为例,其他原理基本类似 **/
		else if (delegate.nodeNameEquals(ele, BEAN_ELEMENT)) {
			processBeanDefinition(ele, delegate);
		}
		else if (delegate.nodeNameEquals(ele, NESTED_BEANS_ELEMENT)) {
			// recurse
			doRegisterBeanDefinitions(ele);
		}
	}
      importBeanDefinitionResource(ele);
   }
   else if (delegate.nodeNameEquals(ele, ALIAS_ELEMENT)) {
      processAliasRegistration(ele);
   }
   /** 以此为例,其他原理基本类似 **/
   else if (delegate.nodeNameEquals(ele, BEAN_ELEMENT)) {
      processBeanDefinition(ele, delegate);
   }
   else if (delegate.nodeNameEquals(ele, NESTED_BEANS_ELEMENT)) {
      // recurse
      doRegisterBeanDefinitions(ele);
   }
}

进入倒数第二个if中,以此为例进行分析 processBeanDefinition(ele, delegate);

protected void processBeanDefinition(Element ele, BeanDefinitionParserDelegate delegate) {
   /** 对元素进行解析,解析后的bdHolder对象已经包含了各种属性id、name等 重点进入了解 **/
   BeanDefinitionHolder bdHolder = delegate.parseBeanDefinitionElement(ele);
   if (bdHolder != null) {
      /** 默认标签下的子节点若还存在自定义属性,还需要进一步进行解析 **/
      bdHolder = delegate.decorateBeanDefinitionIfRequired(ele, bdHolder);
      try {
         // Register the final decorated instance.对解析后的bdHolder对象进行注册,属性解析完后就是注册
         BeanDefinitionReaderUtils.registerBeanDefinition(bdHolder, getReaderContext().getRegistry());
      }
      catch (BeanDefinitionStoreException ex) {
         getReaderContext().error("Failed to register bean definition with name '" +
               bdHolder.getBeanName() + "'", ele, ex);
      }
      // Send registration event.
      /** 发出相应事件,告诉监听器该bean已经加载完毕 **/
      getReaderContext().fireComponentRegistered(new BeanComponentDefinition(bdHolder));
   }
}

下面又是对上面几个过程进行解析:

4元素解析以及信息提取,对name属性的解析,若未指定beanName,使用默认规则帮其指定
/**
 * 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) {
   String id = ele.getAttribute(ID_ATTRIBUTE);
   /** 获取name属性,此处可以参考源码中的string转数组再转list写法 **/
   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.isTraceEnabled()) {
         logger.trace("No XML 'id' specified - using '" + beanName +
               "' as bean name and " + aliases + " as aliases");
      }
   }

   if (containingBean == null) {
      checkNameUniqueness(beanName, aliases, ele);
   }
   /** 检测bean没有指定beanName,那么就使用默认规则为bean生成beanName **/
   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.isTraceEnabled()) {
               logger.trace("Neither XML 'id' nor 'name' specified - " +
                     "using generated bean name [" + beanName + "]");
            }
         }
         catch (Exception ex) {
            error(ex.getMessage(), ele);
            return null;
         }
      }
      /** 将获取到的全部信息封装到BeanDefinitionHolder中 **/
      String[] aliasesArray = StringUtils.toStringArray(aliases);
      return new BeanDefinitionHolder(beanDefinition, beanName, aliasesArray);
   }

   return null;
}
5.解析除name外的其他属性
/**
 * 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.
 * 解析除name以外的其他属性
 * 这里可以进入AbstractBeanDefinition类对象中看一下拥有的具体属性
 * GenericBeanDefinition只是对AbstractBeanDefinition的子类实现,大部分属性都保存在父类属性中
 */
@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;
   if (ele.hasAttribute(PARENT_ATTRIBUTE)) {
      parent = ele.getAttribute(PARENT_ATTRIBUTE);
   }

   try {
      /** 创建可以承载属性的AbstractBeanDefinition类型的GenericBeanDefinition **/
      AbstractBeanDefinition bd = createBeanDefinition(className, parent);
      /** 上面获取了一个bean的信息后封装在对象里,以下均为解析各种属性 **/
      parseBeanDefinitionAttributes(ele, beanName, containingBean, bd);
      bd.setDescription(DomUtils.getChildElementValueByTagName(ele, DESCRIPTION_ELEMENT));
      /** 解析子元素meta属性 **/
      parseMetaElements(ele, bd);
      /** 获取器注入,通过声明方法返回某一种属性的bean,具体作用参考54-57 **/
      parseLookupOverrideSubElements(ele, bd.getMethodOverrides());
      /** 可以在运行时用新的方法替换原有的方法 参考57-58 **/
      parseReplacedMethodSubElements(ele, bd.getMethodOverrides());
      /** 解析构造函数 **/
      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;
}

后面也是对各种属性的解析过程,就不再赘述,进入下一步,走了这么远,是不是都快忘记是从哪个方法进入的了?上面只是对原来此处的第一步,下面进入第二步

6.若默认标签下的子节点若还存在自定义属性,还需要进一步进行解析
/**
	 * Process the given bean element, parsing the bean definition
	 * and registering it with the registry.
	 */
	protected void processBeanDefinition(Element ele, BeanDefinitionParserDelegate delegate) {
		/** 第一步:对元素进行解析,解析后的bdHolder对象已经包含了各种属性id、name等 重点进入了解 **/
		BeanDefinitionHolder bdHolder = delegate.parseBeanDefinitionElement(ele);
		if (bdHolder != null) {
			/** 第二步:默认标签下的子节点若还存在自定义属性,还需要进一步进行解析 他的作用其实就是
			 *   <bean id="" class="">
			 *      <mybean:user username="aaa"></> </>   就是bean标签采用了spring默认声明方式,但是他的子标签却采用了自定义声明方式**/
			bdHolder = delegate.decorateBeanDefinitionIfRequired(ele, bdHolder);
			try {
				// Register the final decorated instance.对解析后的bdHolder对象进行注册
				BeanDefinitionReaderUtils.registerBeanDefinition(bdHolder, getReaderContext().getRegistry());
			}
			catch (BeanDefinitionStoreException ex) {
				getReaderContext().error("Failed to register bean definition with name '" +
						bdHolder.getBeanName() + "'", ele, ex);
			}
			// Send registration event.
			/** 发出相应事件,告诉监听器该bean已经加载完毕 **/
			getReaderContext().fireComponentRegistered(new BeanComponentDefinition(bdHolder));
		}
	}

进入第二步方法体:第一处方法中调用了第二处

/**
 * Decorate the given bean definition through a namespace handler, if applicable.
 * @param ele the current element
 * @param originalDef the current bean definition
 * @return the decorated bean definition
 * 第三个属性本处设置为null,一般传入的是父标签元素,目的是为了在子元素没有定义scope范围的情况下,默认使用父元素的范围
 */
public BeanDefinitionHolder decorateBeanDefinitionIfRequired(Element ele, BeanDefinitionHolder originalDef) {
   return decorateBeanDefinitionIfRequired(ele, originalDef, null);
}

/**
 * Decorate the given bean definition through a namespace handler, if applicable.
 * @param ele the current element
 * @param originalDef the current bean definition
 * @param containingBd the containing bean definition (if any)
 * @return the decorated bean definition
 */
public BeanDefinitionHolder decorateBeanDefinitionIfRequired(
      Element ele, BeanDefinitionHolder originalDef, @Nullable BeanDefinition containingBd) {

   BeanDefinitionHolder finalDefinition = originalDef;

   // Decorate based on custom attributes first.
   /** 遍历是否有需要修饰的属性 ,可进入decorateIfRequired方法具体了解修饰的过程**/
   NamedNodeMap attributes = ele.getAttributes();
   for (int i = 0; i < attributes.getLength(); i++) {
      Node node = attributes.item(i);
       //第三步:下面会进入本方法体中了解一下
      finalDefinition = decorateIfRequired(node, finalDefinition, containingBd);
   }

   // Decorate based on custom nested elements.
   /** 遍历所有的子节点,看是否有需要修饰的属性 **/
   NodeList children = ele.getChildNodes();
   for (int i = 0; i < children.getLength(); i++) {
      Node node = children.item(i);
      if (node.getNodeType() == Node.ELEMENT_NODE) {
         finalDefinition = decorateIfRequired(node, finalDefinition, containingBd);
      }
   }
   return finalDefinition;
}

进入上述第三步:

public BeanDefinitionHolder decorateIfRequired(
      Node node, BeanDefinitionHolder originalDef, @Nullable BeanDefinition containingBd) {
   /** 获取自定义标签的命名空间,若非默认则进行装饰 **/
   String namespaceUri = getNamespaceURI(node);
   if (namespaceUri != null && !isDefaultNamespace(namespaceUri)) {
      /** 根据命名空间找到相应的处理器并进行修饰**/
      NamespaceHandler handler = this.readerContext.getNamespaceHandlerResolver().resolve(namespaceUri);
      if (handler != null) {
         BeanDefinitionHolder decorated =
               handler.decorate(node, originalDef, new ParserContext(this.readerContext, this, containingBd));
         if (decorated != null) {
            return decorated;
         }
      }
      else if (namespaceUri.startsWith("http://www.springframework.org/schema/")) {
         error("Unable to locate Spring NamespaceHandler for XML schema namespace [" + namespaceUri + "]", node);
      }
      else {
         // A custom namespace, not to be handled by Spring - maybe "xml:...".
         if (logger.isDebugEnabled()) {
            logger.debug("No Spring NamespaceHandler found for XML schema namespace [" + namespaceUri + "]");
         }
      }
   }
   return originalDef;
}

解析和装饰属性的工作已经完成,下面就是进行bean的注册了,也就是所谓的第三步

7.bean的注册
/**
 * Process the given bean element, parsing the bean definition
 * and registering it with the registry.
 */
protected void processBeanDefinition(Element ele, BeanDefinitionParserDelegate delegate) {
   /** 第一步:对元素进行解析,解析后的bdHolder对象已经包含了各种属性id、name等 重点进入了解 **/
   BeanDefinitionHolder bdHolder = delegate.parseBeanDefinitionElement(ele);
   if (bdHolder != null) {
      /** 第二步:默认标签下的子节点若还存在自定义属性,还需要进一步进行解析 他的作用其实就是
       *   <bean id="" class="">
       *      <mybean:user username="aaa"></> </>   就是bean标签采用了spring默认声明方式,但是他的子标签却采用了自定义声明方式**/
      bdHolder = delegate.decorateBeanDefinitionIfRequired(ele, bdHolder);
      try {
         // 第三步:Register the final decorated instance.对解析后的bdHolder对象进行注册
         BeanDefinitionReaderUtils.registerBeanDefinition(bdHolder, getReaderContext().getRegistry());
      }
      catch (BeanDefinitionStoreException ex) {
         getReaderContext().error("Failed to register bean definition with name '" +
               bdHolder.getBeanName() + "'", ele, ex);
      }
      // Send registration event.
      /** 发出相应事件,告诉监听器该bean已经加载完毕 **/
      getReaderContext().fireComponentRegistered(new BeanComponentDefinition(bdHolder));
   }
}

进入第三步:通过bean name注册和通过别名注册

public static void registerBeanDefinition(
			BeanDefinitionHolder definitionHolder, BeanDefinitionRegistry registry)
			throws BeanDefinitionStoreException {
		// Register bean definition under primary name.
		/** 第一步:使用bean name做唯一标识注册 ,他做的事情其实类似将beanDefination 作为value,bean-name作为key放入map中,但不止这些**/
		String beanName = definitionHolder.getBeanName();
		registry.registerBeanDefinition(beanName, definitionHolder.getBeanDefinition());
		// Register aliases for bean name, if any.
		/** 注册所有的别名,若别名与bean name相同,则不需要处理,删除原有的所有别名
		 * 覆盖处理需要用户进行处置
		 * 循环检查 ,最后进行注册**/
		String[] aliases = definitionHolder.getAliases();
		if (aliases != null) {
			for (String alias : aliases) {
				registry.registerAlias(beanName, alias);
			}
		}
	}

那么第一步还做了什么事情呢?

@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 {
         /** 注册前的最后一次校验,不同于之前的xml校验
          * 主要是对AbstractBeanDefinition中的MethodOverride属性进行校验
          * 检验MethodOverride是否与工厂方法并存或者对应的MethodOverride方法根本就不存在 **/
         ((AbstractBeanDefinition) beanDefinition).validate();
      }
      catch (BeanDefinitionValidationException ex) {
         throw new BeanDefinitionStoreException(beanDefinition.getResourceDescription(), beanName,
               "Validation of bean definition failed", ex);
      }
   }

   BeanDefinition existingDefinition = this.beanDefinitionMap.get(beanName);
   /** 如果对应的beanName已经被注册并且配置不允许被覆盖,则抛出异常 **/
   if (existingDefinition != null) {
      if (!isAllowBeanDefinitionOverriding()) {
         throw new BeanDefinitionOverrideException(beanName, beanDefinition, existingDefinition);
      }
      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 + "]");
         }
      }
      else if (!beanDefinition.equals(existingDefinition)) {
         if (logger.isDebugEnabled()) {
            logger.debug("Overriding bean definition for bean '" + beanName +
                  "' with a different definition: replacing [" + existingDefinition +
                  "] with [" + beanDefinition + "]");
         }
      }
      else {
         if (logger.isTraceEnabled()) {
            logger.trace("Overriding bean definition for bean '" + beanName +
                  "' with an equivalent definition: replacing [" + existingDefinition +
                  "] with [" + beanDefinition + "]");
         }
      }
      /** 加入map缓存并对之前的缓存进行清理 **/
      this.beanDefinitionMap.put(beanName, beanDefinition);
   }
   else {
      if (hasBeanCreationStarted()) {
         // Cannot modify startup-time collection elements anymore (for stable iteration)
         /** beanDefinitionMap作为全局变量,肯定存在并发问题 **/
         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
         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();
   }
}

别名的注册过程,跟beanname的注册过程很类似

@Override
public void registerAlias(String name, String alias) {
   Assert.hasText(name, "'name' must not be empty");
   Assert.hasText(alias, "'alias' must not be empty");
   synchronized (this.aliasMap) {
      /** 如果bean name与别名相同则不再记录,删除别名 **/
      if (alias.equals(name)) {
         this.aliasMap.remove(alias);
         if (logger.isDebugEnabled()) {
            logger.debug("Alias definition '" + alias + "' ignored since it points to same name");
         }
      }
      else {
         String registeredName = this.aliasMap.get(alias);
         if (registeredName != null) {
            if (registeredName.equals(name)) {
               // An existing alias - no need to re-register
               return;
            }
            /** 如果别名不允许被覆盖,则抛出异常 **/
            if (!allowAliasOverriding()) {
               throw new IllegalStateException("Cannot define alias '" + alias + "' for name '" +
                     name + "': It is already registered for name '" + registeredName + "'.");
            }
            if (logger.isDebugEnabled()) {
               logger.debug("Overriding alias '" + alias + "' definition for registered name '" +
                     registeredName + "' with new target name '" + name + "'");
            }
         }
         /** 如果A->B存在,再出现A->B->C则抛出异常 **/
         checkForAliasCircle(name, alias);
         this.aliasMap.put(alias, name);
         if (logger.isTraceEnabled()) {
            logger.trace("Alias definition '" + alias + "' registered for name '" + name + "'");
         }
      }
   }
}

以上就是对bean标签的解析,最后回归到开始的地方如下图,但是当初我们提到过,bean的注册包括对import标签、bean标签、beans标签、alias标签的解析,所以上面只是第一步,在spring bean加载过程2中,我们将进行后续的分解

protected void processBeanDefinition(Element ele, BeanDefinitionParserDelegate delegate) {
   /** 第一步:对元素进行解析,解析后的bdHolder对象已经包含了各种属性id、name等 重点进入了解 **/
   BeanDefinitionHolder bdHolder = delegate.parseBeanDefinitionElement(ele);
   if (bdHolder != null) {
      /** 第二步:默认标签下的子节点若还存在自定义属性,还需要进一步进行解析 他的作用其实就是
       *   <bean id="" class="">
       *      <mybean:user username="aaa"></> </>   就是bean标签采用了spring默认声明方式,但是他的子标签却采用了自定义声明方式**/
      bdHolder = delegate.decorateBeanDefinitionIfRequired(ele, bdHolder);
      try {
         // 第三步:Register the final decorated instance.对解析后的bdHolder对象进行注册
         BeanDefinitionReaderUtils.registerBeanDefinition(bdHolder, getReaderContext().getRegistry());
      }
      catch (BeanDefinitionStoreException ex) {
         getReaderContext().error("Failed to register bean definition with name '" +
               bdHolder.getBeanName() + "'", ele, ex);
      }
      // Send registration event.
      /** 发出相应事件,告诉监听器该bean已经加载完毕,其实就是将监听逻辑注册进监听器,没有进行其他特殊处理 **/
      getReaderContext().fireComponentRegistered(new BeanComponentDefinition(bdHolder));
   }
}
了各种属性id、name等 重点进入了解 **/
   BeanDefinitionHolder bdHolder = delegate.parseBeanDefinitionElement(ele);
   if (bdHolder != null) {
      /** 第二步:默认标签下的子节点若还存在自定义属性,还需要进一步进行解析 他的作用其实就是
       *   <bean id="" class="">
       *      <mybean:user username="aaa"></> </>   就是bean标签采用了spring默认声明方式,但是他的子标签却采用了自定义声明方式**/
      bdHolder = delegate.decorateBeanDefinitionIfRequired(ele, bdHolder);
      try {
         // 第三步:Register the final decorated instance.对解析后的bdHolder对象进行注册
         BeanDefinitionReaderUtils.registerBeanDefinition(bdHolder, getReaderContext().getRegistry());
      }
      catch (BeanDefinitionStoreException ex) {
         getReaderContext().error("Failed to register bean definition with name '" +
               bdHolder.getBeanName() + "'", ele, ex);
      }
      // Send registration event.
      /** 发出相应事件,告诉监听器该bean已经加载完毕,其实就是将监听逻辑注册进监听器,没有进行其他特殊处理 **/
      getReaderContext().fireComponentRegistered(new BeanComponentDefinition(bdHolder));
   }
}
  • 22
    点赞
  • 28
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值