spring解析自定义标签-4

org.springframework.beans.factory.xml.DefaultBeanDefinitionDocumentReader#parseBeanDefinitions

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)) {
               parseDefaultElement(ele, delegate);
            }
            else {
                //解析自定义标签
               delegate.parseCustomElement(ele);
            }
         }
      }
   }
   else {
      delegate.parseCustomElement(root);
   }
}

org.springframework.beans.factory.xml.BeanDefinitionParserDelegate#parseCustomElement(org.w3c.dom.Element, org.springframework.beans.factory.config.BeanDefinition)

public BeanDefinition parseCustomElement(Element ele, @Nullable BeanDefinition containingBd) {
    //根据自定义标签的命名空间来确定namespaceUri
   String namespaceUri = getNamespaceURI(ele);
   if (namespaceUri == null) {
      return null;
   }
   //根据namespaceUri来获取NamespaceHandler,这个标签处理器来解析标签
   NamespaceHandler handler = this.readerContext.getNamespaceHandlerResolver().resolve(namespaceUri);
   if (handler == null) {
      error("Unable to locate Spring NamespaceHandler for XML schema namespace [" + namespaceUri + "]", ele);
      return null;
   }
   //具体的解析过程
   return handler.parse(ele, new ParserContext(this.readerContext, this, containingBd));
}

来看下如何通过namespaceUrl获取到Handler的具体过程

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

public NamespaceHandler resolve(String namespaceUri) {
    //获取所有的mapping
   Map<String, Object> handlerMappings = getHandlerMappings();
   //根据uri获取对应的命名空间处理器
   Object handlerOrClassName = handlerMappings.get(namespaceUri);
   if (handlerOrClassName == null) {
      return null;
   }
   else if (handlerOrClassName instanceof NamespaceHandler) {
      return (NamespaceHandler) handlerOrClassName;
   }
   else {
      String className = (String) handlerOrClassName;
      try {
            //反射生成自定义解析xml处理器对象
         Class<?> handlerClass = ClassUtils.forName(className, this.classLoader);
         if (!NamespaceHandler.class.isAssignableFrom(handlerClass)) {
            throw new FatalBeanException("Class [" + className + "] for namespace [" + namespaceUri +
                  "] does not implement the [" + NamespaceHandler.class.getName() + "] interface");
         }
         NamespaceHandler namespaceHandler = (NamespaceHandler) BeanUtils.instantiateClass(handlerClass);
         //命名空间处理器的钩子函数,进行初始化,也是解析的关键步骤
         namespaceHandler.init();
         //解析完后把命名空间和命名空间处理器放入map中
         handlerMappings.put(namespaceUri, namespaceHandler);
         return namespaceHandler;
      }
      catch (ClassNotFoundException ex) {
         throw new FatalBeanException("Could not find NamespaceHandler class [" + className +
               "] for namespace [" + namespaceUri + "]", ex);
      }
      catch (LinkageError err) {
         throw new FatalBeanException("Unresolvable class definition for NamespaceHandler class [" +
               className + "] for namespace [" + namespaceUri + "]", err);
      }
   }
}

注意这里有个toString的方法,idea debug的时候回调用起来,从而进行读取配置文件

@Override
public String toString() {
   return "NamespaceHandlerResolver using mappings " + getHandlerMappings();
}

先看构造方法:

public DefaultNamespaceHandlerResolver() {
   this(null, DEFAULT_HANDLER_MAPPINGS_LOCATION);
}

public DefaultNamespaceHandlerResolver(@Nullable ClassLoader classLoader, String handlerMappingsLocation) {
   Assert.notNull(handlerMappingsLocation, "Handler mappings location must not be null");
   this.classLoader = (classLoader != null ? classLoader : ClassUtils.getDefaultClassLoader());
   this.handlerMappingsLocation = handlerMappingsLocation;
}

原来解析的时候会去读取类路径下的META-INF/spring.handlers的配置文件,然后把所有属性通过k-v的形式存入properties

public static final String DEFAULT_HANDLER_MAPPINGS_LOCATION = "META-INF/spring.handlers";

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

执行完该方法后会把所有类路径下的文件解析成k-v格式然后存入map中,共后续使用

下面以具体的列子来分析:

<context:component-scan base-package="com.aa"></context:component-scan>

1.找到xsd: spring-context.xsd

2.在类路径下找到 META-INF/spring.handlers

http\://www.springframework.org/schema/context=org.springframework.context.config.ContextNamespaceHandler
http\://www.springframework.org/schema/jee=org.springframework.ejb.config.JeeNamespaceHandler
http\://www.springframework.org/schema/lang=org.springframework.scripting.config.LangNamespaceHandler
http\://www.springframework.org/schema/task=org.springframework.scheduling.config.TaskNamespaceHandler
http\://www.springframework.org/schema/cache=org.springframework.cache.config.CacheNamespaceHandler

3.根据命名空间获取对应的xml解析处理器

4.进行回调,解析,执行init()方法

public class ContextNamespaceHandler extends NamespaceHandlerSupport {
​
   @Override
   public void init() {
      registerBeanDefinitionParser("property-placeholder", new PropertyPlaceholderBeanDefinitionParser());
      registerBeanDefinitionParser("property-override", new PropertyOverrideBeanDefinitionParser());
      registerBeanDefinitionParser("annotation-config", new AnnotationConfigBeanDefinitionParser());
      registerBeanDefinitionParser("component-scan", new ComponentScanBeanDefinitionParser());
      registerBeanDefinitionParser("load-time-weaver", new LoadTimeWeaverBeanDefinitionParser());
      registerBeanDefinitionParser("spring-configured", new SpringConfiguredBeanDefinitionParser());
      registerBeanDefinitionParser("mbean-export", new MBeanExportBeanDefinitionParser());
      registerBeanDefinitionParser("mbean-server", new MBeanServerBeanDefinitionParser());
   }
​
}
5.看看具体的解析过程
   registerBeanDefinitionParser("component-scan", new ComponentScanBeanDefinitionParser());
   
    public BeanDefinition parse(Element element, ParserContext parserContext) {
        //获取包路径
        String basePackage = element.getAttribute(BASE_PACKAGE_ATTRIBUTE);
        basePackage = parserContext.getReaderContext().getEnvironment().resolvePlaceholders(basePackage);
        String[] basePackages = StringUtils.tokenizeToStringArray(basePackage,
                ConfigurableApplicationContext.CONFIG_LOCATION_DELIMITERS);
​
        // Actually scan for bean definitions and register them.
        ClassPathBeanDefinitionScanner scanner = configureScanner(parserContext, element);
        //解析包路径下的所有class文件,判断class是否有@Component的注解,有的话,放入beanDefinitionMap中,将其注入为      //spring bean
        Set<BeanDefinitionHolder> beanDefinitions = scanner.doScan(basePackages);
        registerComponents(parserContext.getReaderContext(), beanDefinitions, element);
​
        return null;
    }
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值