整体流程

parseBeanDefinitions.jpeg
如果不是默认的命名空间,比如是:http://www.springframework.org/schema/aop 那么就会进入自定义解析方法。
在阅读代码前,首先了解下自定义标签如何使用? 附录2 - 自定义标签🏷
然后再继续看解析源码:

  1. @Nullable
  2. public BeanDefinition parseCustomElement(Element ele) {
  3. return parseCustomElement(ele, null);
  4. }
  1. @Nullable
  2. public BeanDefinition parseCustomElement(Element ele, @Nullable BeanDefinition containingBd) {
  3. // 参数校验
  4. String namespaceUri = getNamespaceURI(ele);
  5. if (namespaceUri == null) {
  6. return null;
  7. }
  8. // 获取自定义标签解析器
  9. NamespaceHandler handler = this.readerContext.getNamespaceHandlerResolver().resolve(namespaceUri);
  10. if (handler == null) {
  11. error("Unable to locate Spring NamespaceHandler for
  12. XML schema namespace [" + namespaceUri + "]", ele);
  13. return null;
  14. }
  15. return handler.parse(ele, new ParserContext(this.readerContext, this, containingBd));
  16. }

具体流程:

  1. 首先获取标签的命名空间;
  2. 然后获取自定义标签的处理器,通过 DefaultNamespaceHandlerResolver 来解析命令空间获取对应的解析器。
  3. 标签解析;

    获取命名空间

    这一步不用我们过多的处理,调用的是 jdk Node 的方法。org.w3c.dom.Node 提供了对应的方法;

    1. String namespaceUri = getNamespaceURI(ele);
    1. public String getNamespaceURI(Node node) {
    2. return node.getNamespaceURI();
    3. }

    获取自定义标签处理器

    1. NamespaceHandler handler = this.readerContext.getNamespaceHandlerResolver().resolve(namespaceUri);

    3. 解析 XML 文档 - registerBeanDefinitions 可以得知 XmlReaderContext 的由来。
    所以 this.readerContext.getNamespaceHandlerResolver() 这块其实就是获取到了 DefaultNamespaceHandlerResolver
    然后通过 resolve 方法得到对应命名空间的处理器。源码如下:
    org.springframework.beans.factory.xml.DefaultNamespaceHandlerResolver#resolve

    1. @Override
    2. @Nullable
    3. public NamespaceHandler resolve(String namespaceUri) {
    4. // 获取所有的handlers
    5. Map<String, Object> handlerMappings = getHandlerMappings();
    6. // 根据命名空间获取处理器
    7. Object handlerOrClassName = handlerMappings.get(namespaceUri);
    8. if (handlerOrClassName == null) {
    9. return null;
    10. }
    11. // 最开始这个处理器还是字符串,还不是对象
    12. else if (handlerOrClassName instanceof NamespaceHandler) {
    13. return (NamespaceHandler) handlerOrClassName;
    14. }
    15. else {
    16. // 获取处理器的类名称
    17. String className = (String) handlerOrClassName;
    18. try {
    19. // 反射得到Class对象
    20. Class<?> handlerClass = ClassUtils.forName(className, this.classLoader);
    21. if (!NamespaceHandler.class.isAssignableFrom(handlerClass)) {
    22. throw new FatalBeanException("Class [" + className + "] for namespace [" + namespaceUri +
    23. "] does not implement the [" + NamespaceHandler.class.getName() + "] interface");
    24. }
    25. // 实例化处理器对象
    26. NamespaceHandler namespaceHandler = (NamespaceHandler) BeanUtils.instantiateClass(handlerClass);
    27. // 处理器初始化各种标签的解析器到父类的缓存中,
    28. // private final Map<String, BeanDefinitionParser> parsers = new HashMap<>()
    29. namespaceHandler.init();
    30. // 添加到映射中
    31. handlerMappings.put(namespaceUri, namespaceHandler);
    32. return namespaceHandler;
    33. }
    34. catch (ClassNotFoundException ex) {
    35. throw new FatalBeanException("Could not find NamespaceHandler class [" + className +
    36. "] for namespace [" + namespaceUri + "]", ex);
    37. }
    38. catch (LinkageError err) {
    39. throw new FatalBeanException("Unresolvable class definition for NamespaceHandler class [" +
    40. className + "] for namespace [" + namespaceUri + "]", err);
    41. }
    42. }
    43. }
  4. 首先获取所有的自定义标签处理器;

org.springframework.beans.factory.xml.DefaultNamespaceHandlerResolver#resolve

  1. private Map<String, Object> getHandlerMappings() {
  2. Map<String, Object> handlerMappings = this.handlerMappings;
  3. if (handlerMappings == null) {
  4. synchronized (this) {
  5. handlerMappings = this.handlerMappings;
  6. if (handlerMappings == null) {
  7. if (logger.isTraceEnabled()) {
  8. logger.trace("Loading NamespaceHandler mappings from [" + this.handlerMappingsLocation + "]");
  9. }
  10. try {
  11. Properties mappings =
  12. PropertiesLoaderUtils.loadAllProperties(this.handlerMappingsLocation, this.classLoader);
  13. if (logger.isTraceEnabled()) {
  14. logger.trace("Loaded NamespaceHandler mappings: " + mappings);
  15. }
  16. handlerMappings = new ConcurrentHashMap<>(mappings.size());
  17. CollectionUtils.mergePropertiesIntoMap(mappings, handlerMappings);
  18. this.handlerMappings = handlerMappings;
  19. }
  20. catch (IOException ex) {
  21. throw new IllegalStateException(
  22. "Unable to load NamespaceHandler mappings from location [" + this.handlerMappingsLocation + "]", ex);
  23. }
  24. }
  25. }
  26. }
  27. return handlerMappings;
  28. }

用于获取 jar 中这个位置 META-INF/spring.handlers 配置的处理器,比如 aop 包下的这个文件 spring.handlers 如下:
image.png
spring.handlers 文件定义的就是命名空间-对应的处理器。

  1. http\://www.springframework.org/schema/aop=org.springframework.aop.config.AopNamespaceHandler
  1. 得到处理器后,会立刻执行 init 方法初始化对应的 BeanDefinitionParser;
  2. 将得到的处理器添加到缓存中。

    自定义标签解析

    1. return handler.parse(ele, new ParserContext(this.readerContext, this, containingBd));

    得到命名空间对应的处理器后,开始执行解析。

    找到自定义解析器

    这个时候我们的自定义标签解析器已经初始化完毕,该方法调用的父类的方法如下,需要先找到自定义解析器。
    org.springframework.beans.factory.xml.NamespaceHandlerSupport#parse

    1. @Override
    2. @Nullable
    3. public BeanDefinition parse(Element element, ParserContext parserContext) {
    4. BeanDefinitionParser parser = findParserForElement(element, parserContext);
    5. return (parser != null ? parser.parse(element, parserContext) : null);
    6. }

    进入方法 findParserForElement
    org.springframework.beans.factory.xml.NamespaceHandlerSupport#findParserForElement

    1. @Nullable
    2. private BeanDefinitionParser findParserForElement(Element element, ParserContext parserContext) {
    3. String localName = parserContext.getDelegate().getLocalName(element);
    4. BeanDefinitionParser parser = this.parsers.get(localName);
    5. if (parser == null) {
    6. parserContext.getReaderContext().fatal(
    7. "Cannot locate BeanDefinitionParser for element [" + localName + "]", element);
    8. }
    9. return parser;
    10. }
  3. 首先找到 localName ,这个其实就是 中的 keyboard;

  4. 然后根据这个 localName 从注册的解析器中找到对应的解析器返回;

    标签解析

    1. @Override
    2. @Nullable
    3. public BeanDefinition parse(Element element, ParserContext parserContext) {
    4. // 得到自定义解析器
    5. BeanDefinitionParser parser = findParserForElement(element, parserContext);
    6. // 执行解析
    7. return (parser != null ? parser.parse(element, parserContext) : null);
    8. }
    得到解析器后,开始执行解析操作。
    来到了父类的方法
    org.springframework.beans.factory.xml.AbstractBeanDefinitionParser#parse
    1. @Override
    2. @Nullable
    3. public final BeanDefinition parse(Element element, ParserContext parserContext) {
    4. // 得到 AbstractBeanDefinition
    5. AbstractBeanDefinition definition = parseInternal(element, parserContext);
    6. if (definition != null && !parserContext.isNested()) {
    7. try {
    8. String id = resolveId(element, definition, parserContext);
    9. if (!StringUtils.hasText(id)) {
    10. parserContext.getReaderContext().error(
    11. "Id is required for element '" + parserContext.getDelegate().getLocalName(element)
    12. + "' when used as a top-level tag", element);
    13. }
    14. String[] aliases = null;
    15. if (shouldParseNameAsAliases()) {
    16. String name = element.getAttribute(NAME_ATTRIBUTE);
    17. if (StringUtils.hasLength(name)) {
    18. aliases = StringUtils.trimArrayElements(StringUtils.commaDelimitedListToStringArray(name));
    19. }
    20. }
    21. BeanDefinitionHolder holder = new BeanDefinitionHolder(definition, id, aliases);
    22. registerBeanDefinition(holder, parserContext.getRegistry());
    23. if (shouldFireEvents()) {
    24. BeanComponentDefinition componentDefinition = new BeanComponentDefinition(holder);
    25. postProcessComponentDefinition(componentDefinition);
    26. parserContext.registerComponent(componentDefinition);
    27. }
    28. }
    29. catch (BeanDefinitionStoreException ex) {
    30. String msg = ex.getMessage();
    31. parserContext.getReaderContext().error((msg != null ? msg : ex.toString()), element);
    32. return null;
    33. }
    34. }
    35. return definition;
    36. }

这段代码分成了两部分:

  • 第一部分通过 parseInternal 解析得到 AbstractBeanDefinition;
  • 第二部分将 AbstractBeanDefinition 转换成 BeanDefinitionHolder,并注册 bean;

第一部分间接的使用了我们自定义解析器的自定义解析方法,但在使用之前还做了一些准备工作。
org.springframework.beans.factory.xml.AbstractSingleBeanDefinitionParser#parseInternal

  1. @Override
  2. protected final AbstractBeanDefinition parseInternal(Element element, ParserContext parserContext) {
  3. // bean定义构建器,创建一个空的 AbstractBeanDefinition
  4. BeanDefinitionBuilder builder = BeanDefinitionBuilder.genericBeanDefinition();
  5. String parentName = getParentName(element);
  6. if (parentName != null) {
  7. builder.getRawBeanDefinition().setParentName(parentName);
  8. }
  9. // 获取标签对应的 bean Class
  10. // org.springframework.transaction.interceptor.TransactionInterceptor
  11. Class<?> beanClass = getBeanClass(element);
  12. if (beanClass != null) {
  13. builder.getRawBeanDefinition().setBeanClass(beanClass);
  14. } else {
  15. String beanClassName = getBeanClassName(element);
  16. if (beanClassName != null) {
  17. builder.getRawBeanDefinition().setBeanClassName(beanClassName);
  18. }
  19. }
  20. builder.getRawBeanDefinition().setSource(parserContext.extractSource(element));
  21. BeanDefinition containingBd = parserContext.getContainingBeanDefinition();
  22. if (containingBd != null) {
  23. // Inner bean definition must receive same scope as containing bean.
  24. builder.setScope(containingBd.getScope());
  25. }
  26. // 是否懒加载,默认false
  27. if (parserContext.isDefaultLazyInit()) {
  28. // Default-lazy-init applies to custom bean definitions as well.
  29. builder.setLazyInit(true);
  30. }
  31. doParse(element, parserContext, builder);
  32. return builder.getBeanDefinition();
  33. }

这些准备工作包括:创建默认的 GenericBeanDefinition、得到Class、是否使用父类的scope、配置懒加载。按照加载默认标签的方式准备工作都完事了后,调用 doParse 应用用户自定义的解析方法。
(所以 doParse 中只关心自己的逻辑,其他的工作 spring 帮你做好了,熟悉吗?模板方式模式。)