其他模块也有这两种文件,这里不一一展示,从上面的 spring.handlers 这里可以看到 context 命名空间对应的是 ContextNamespaceHandler 处理器,先来看一下:
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()); } }可以看到注册了不同的标签所对应的解析器,其中 component-scan 对应 ComponentScanBeanDefinitionParser 解析器,这里先看一下,后面再具体分析
Spring 如何处理非默认命名空间的元素回顾到 《BeanDefinition 的加载阶段(XML 文件)》 文章中的 XmlBeanDefinitionReader#registerBeanDefinitions 方法,解析 Document 前会先创建 XmlReaderContext 对象(读取 Resource 资源的上下文对象),创建方法如下:
// XmlBeanDefinitionReader.java public XmlReaderContext createReaderContext(Resource resource) { return new XmlReaderContext(resource, this.problemReporter, this.eventListener, this.sourceExtractor, this, getNamespaceHandlerResolver()); } public NamespaceHandlerResolver getNamespaceHandlerResolver() { if (this.namespaceHandlerResolver == null) { this.namespaceHandlerResolver = createDefaultNamespaceHandlerResolver(); } return this.namespaceHandlerResolver; } protected NamespaceHandlerResolver createDefaultNamespaceHandlerResolver() { ClassLoader cl = (getResourceLoader() != null ? getResourceLoader().getClassLoader() : getBeanClassLoader()); return new DefaultNamespaceHandlerResolver(cl); }在 XmlReaderContext 对象中会有一个 DefaultNamespaceHandlerResolver 对象
回顾到 《BeanDefinition 的解析阶段(XML 文件)》 文章中的 DefaultBeanDefinitionDocumentReader#parseBeanDefinitions 方法,如果不是默认的命名空间,则执行自定义解析,调用 BeanDefinitionParserDelegate#parseCustomElement(Element ele) 方法,方法如下
// BeanDefinitionParserDelegate.java @Nullable public BeanDefinition parseCustomElement(Element ele) { return parseCustomElement(ele, null); } @Nullable public BeanDefinition parseCustomElement(Element ele, @Nullable BeanDefinition containingBd) { // <1> 获取 `namespaceUri` String namespaceUri = getNamespaceURI(ele); if (namespaceUri == null) { return null; } // <2> 通过 DefaultNamespaceHandlerResolver 根据 `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; } // <3> 根据 NamespaceHandler 命名空间处理器处理该标签 return handler.parse(ele, new ParserContext(this.readerContext, this, containingBd)); }过程如下:
获取该节点对应的 namespaceUri 命名空间
通过 DefaultNamespaceHandlerResolver 根据 namespaceUri 获取相应的 NamespaceHandler 处理器
根据 NamespaceHandler 命名空间处理器处理该标签
关键就在与 DefaultNamespaceHandlerResolver 是如何找到该命名空间对应的 NamespaceHandler 处理器,我们只是在 spring.handlers 文件中进行关联,它是怎么找到的呢,我们进入 DefaultNamespaceHandlerResolver 看看
DefaultNamespaceHandlerResolverorg.springframework.beans.factory.xml.DefaultNamespaceHandlerResolver,命名空间的默认处理器
构造函数 public class DefaultNamespaceHandlerResolver implements NamespaceHandlerResolver { /** * The location to look for the mapping files. Can be present in multiple JAR files. */ public static final String DEFAULT_HANDLER_MAPPINGS_LOCATION = "META-INF/spring.handlers"; /** Logger available to subclasses. */ protected final Log logger = LogFactory.getLog(getClass()); /** ClassLoader to use for NamespaceHandler classes. */ @Nullable private final ClassLoader classLoader; /** Resource location to search for. */ private final String handlerMappingsLocation; /** Stores the mappings from namespace URI to NamespaceHandler class name / instance. */ @Nullable private volatile Map<String, Object> handlerMappings; public DefaultNamespaceHandlerResolver() { this(null, DEFAULT_HANDLER_MAPPINGS_LOCATION); } public DefaultNamespaceHandlerResolver(@Nullable ClassLoader classLoader) { this(classLoader, 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; } }