Spring NameSpaceHandler的加载过程

1. 调用链

  1. 调用ContextLoadListenner.initWebApplicationContext()
  2. 调用ContextLoadListenner.createWebApplicationContext():根据web.xml里面的contextClass配置的参数名确定Context类,如果没有就使用默认的WebApplicationContext,并创建这个类的实例wac,调用wac.refresh()
  3. 调用ContextLoadListenner.configureAndRefreshWebApplicationContext(): 根据web.xml配置的contextConfigLocation参数 确定配置文件位置
  4. 调用wac.refresh()
  5. 调用wac.obtainFreshBeanFactory();
  6. 调用wac.refreshBeanFactory()
  7. 调用wac.loadBeanDefinitions(beanFactory):创建XmlBeanDefinitionReader reader
  8. 调用reader.loadBeanDefinitions(configLocation):确定文件存在并创建IO流
public int loadBeanDefinitions(EncodedResource encodedResource) {
   InputStream inputStream = encodedResource.getResource().getInputStream();
   try {
      InputSource inputSource = new InputSource(inputStream);
      if (encodedResource.getEncoding() != null) {
        inputSource.setEncoding(encodedResource.getEncoding());
      }
      return doLoadBeanDefinitions(inputSource, encodedResource.getResource());
   }
}
  1. 调用 reader.doLoadBeanDefinitions():构造docreader 解析xml
protected int doLoadBeanDefinitions(InputSource inputSource, Resource resource)throws BeanDefinitionStoreException {
   Document doc = doLoadDocument(inputSource, resource);
   return registerBeanDefinitions(doc, resource);
}
  1. 调用 reader.registerBeanDefinitions()
public int registerBeanDefinitions(Document doc, Resource resource) throws BeanDefinitionStoreException {
   BeanDefinitionDocumentReader documentReader = createBeanDefinitionDocumentReader();
   int countBefore = getRegistry().getBeanDefinitionCount();
   documentReader.registerBeanDefinitions(doc, createReaderContext(resource));
   return getRegistry().getBeanDefinitionCount() - countBefore;
}
  1. 调用 documentReader.registerBeanDefinition
public void registerBeanDefinitions(Document doc, XmlReaderContext readerContext) {
   this.readerContext = readerContext;
   logger.debug("Loading bean definitions");
   Element root = doc.getDocumentElement();//其实就是beans标签
   doRegisterBeanDefinitions(root);
   }

12 . 简化的代码

protected void doRegisterBeanDefinitions(Element root) {
    preProcessXml(root);
    parseBeanDefinitions(root, this.delegate);//上下两个方法调用都是空实现,没用
    postProcessXml(root);
}
  1. 真的加载逻辑
protected void parseBeanDefinitions(Element root, BeanDefinitionParserDelegate delegate) {
    if (delegate.isDefaultNamespace(root)) {
        NodeList nl = root.getChildNodes();//xml doc 对象
        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);
    }
}
  1. xml标签tag标签解析
public BeanDefinition parseCustomElement(Element ele, BeanDefinition containingBd) {
    String namespaceUri = getNamespaceURI(ele);
    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));
}
  1. 从缓存的数据寻找对应namespace的URI对应的NameSpcaeHandler
public NamespaceHandler resolve(String namespaceUri) {
    Map<String, Object> handlerMappings = getHandlerMappings();
    Object handlerOrClassName = handlerMappings.get(namespaceUri);
    if (handlerOrClassName == null) {
        return null;
    } else if (handlerOrClassName instanceof NamespaceHandler) {
        return (NamespaceHandler) handlerOrClassName;
    }else {
        String className = (String) handlerOrClassName;
        try {
            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);// 创建handler对象
            namespaceHandler.init();//初始化
            handlerMappings.put(namespaceUri, namespaceHandler);
            return namespaceHandler;
        }catch (ClassNotFoundException ex) {
        throw new FatalBeanException("NamespaceHandler class [" + className + "] for namespace [" +namespaceUri + "] not found", ex);
        }catch (LinkageError err) {
        throw new FatalBeanException("Invalid NamespaceHandler class [" + className + "] for namespace [" +	namespaceUri + "]: problem with handler class file or dependent class", err);
        }
    }
}
  1. 这一步骤原理在ClassLoader.getResources(String location)加载所有jar里面的spring.handlers 这个文件里的配置
private Map<String, Object> getHandlerMappings() {
    if (this.handlerMappings == null) {
        synchronized (this) {
            if (this.handlerMappings == null) {
                try {
                    Properties mappings =PropertiesLoaderUtils.loadAllProperties(this.handlerMappingsLocation, this.classLoader);
                    if (logger.isDebugEnabled()) {
                        logger.debug("Loaded NamespaceHandler mappings: " + mappings);
                    }
                    Map<String, Object> handlerMappings = new ConcurrentHashMap<String, Object>(mappings.size());
                    CollectionUtils.mergePropertiesIntoMap(mappings, handlerMappings);
                    this.handlerMappings = handlerMappings;
                }catch (IOException ex) {
                    throw new IllegalStateException("Unable to load NamespaceHandler mappings from location [" + this.handlerMappingsLocation + "]", ex);
                }
            }
        }
    }
    return this.handlerMappings;
}

2. NameSpcaceHandler加载逻辑简化

  1. ContextLoaderListener初始化
  2. 设置配置文件路径
  3. 生成DefaultBeanDefinitionDocumentReader实例 reader
  4. reader 解析配置xml,解析出根据标签的namespace 对应的URL
  5. 利用ClassLoader.getResource()加载全部的/META-INF/spring.handlers的配置
  6. 根据URL 查找 对应的NameSpaceHandler并初始化;

转载于:https://my.oschina.net/Aruforce/blog/3067107

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值