死磕Spring之IoC篇 - 解析自定义标签(XML 文件) (5)

configureScanner(ParserContext parserContext, Element element) 方法,创建 ClassPathBeanDefinitionScanner 扫描器,方法如下:

protected ClassPathBeanDefinitionScanner configureScanner(ParserContext parserContext, Element element) { // <1> 默认使用过滤器(过滤出 @Component 注解或其派生注解的 Class 类) boolean useDefaultFilters = true; if (element.hasAttribute(USE_DEFAULT_FILTERS_ATTRIBUTE)) { useDefaultFilters = Boolean.valueOf(element.getAttribute(USE_DEFAULT_FILTERS_ATTRIBUTE)); } // Delegate bean definition registration to scanner class. // <2> 创建 ClassPathBeanDefinitionScanner 扫描器 `scanner`,用于扫描指定路径下符合条件的 BeanDefinition 们 ClassPathBeanDefinitionScanner scanner = createScanner(parserContext.getReaderContext(), useDefaultFilters); // <3> 设置生成的 BeanDefinition 对象的相关默认属性 scanner.setBeanDefinitionDefaults(parserContext.getDelegate().getBeanDefinitionDefaults()); scanner.setAutowireCandidatePatterns(parserContext.getDelegate().getAutowireCandidatePatterns()); // <4> 根据标签的属性进行相关配置 // <4.1> `resource-pattern` 属性的处理,设置资源文件表达式,默认为 `**/*.class`,即 `classpath*:包路径/**/*.class` if (element.hasAttribute(RESOURCE_PATTERN_ATTRIBUTE)) { scanner.setResourcePattern(element.getAttribute(RESOURCE_PATTERN_ATTRIBUTE)); } try { // <4.2> `name-generator` 属性的处理,设置 Bean 的名称生成器,默认为 AnnotationBeanNameGenerator parseBeanNameGenerator(element, scanner); } catch (Exception ex) { parserContext.getReaderContext().error(ex.getMessage(), parserContext.extractSource(element), ex.getCause()); } try { // <4.3> `scope-resolver`、`scoped-proxy` 属性的处理,设置 Scope 的模式和元信息处理器 parseScope(element, scanner); } catch (Exception ex) { parserContext.getReaderContext().error(ex.getMessage(), parserContext.extractSource(element), ex.getCause()); } // <4.4> `exclude-filter`、`include-filter` 属性的处理,设置 `.class` 文件的过滤器 parseTypeFilters(element, scanner, parserContext); // <5> 返回 `scanner` 扫描器 return scanner; }

过程如下:

默认使用过滤器(过滤出 @Component 注解或其派生注解的 Class 类)

创建 ClassPathBeanDefinitionScanner 扫描器 scanner,用于扫描指定路径下符合条件的 BeanDefinition 们

设置生成的 BeanDefinition 对象的相关默认属性

根据标签的属性进行相关配置

resource-pattern 属性的处理,设置资源文件表达式,默认为 **/*.class,即 classpath*:包路径/**/*.class

name-generator 属性的处理,设置 Bean 的名称生成器,默认为 AnnotationBeanNameGenerator

scope-resolver、scoped-proxy 属性的处理,设置 Scope 的模式和元信息处理器

exclude-filter、include-filter 属性的处理,设置 .class 文件的过滤器

返回 scanner 扫描器

至此,对于 <context:component-scan /> 标签的解析过程已经分析完

spring.schemas 的原理

META-INF/spring.handlers 文件的原理在 DefaultNamespaceHandlerResolver 中已经分析过,那么 Sping 是如何处理 META-INF/spring.schemas 文件的?

先回到 《BeanDefinition 的加载阶段(XML 文件)》 中的 XmlBeanDefinitionReader#doLoadDocument 方法,如下:

protected Document doLoadDocument(InputSource inputSource, Resource resource) throws Exception { // <3> 通过 DefaultDocumentLoader 根据 Resource 获取一个 Document 对象 return this.documentLoader.loadDocument(inputSource, getEntityResolver(), // <1> 获取 `org.xml.sax.EntityResolver` 实体解析器,ResourceEntityResolver this.errorHandler, getValidationModeForResource(resource), isNamespaceAware()); // <2> 获取 XML 文件验证模式,保证 XML 文件的正确性 } 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; }

第 1 步先获取 org.xml.sax.EntityResolver 实体解析器,默认为 ResourceEntityResolver 资源解析器,根据 publicId 和 systemId 获取对应的 DTD 或 XSD 文件,用于对 XML 文件进行验证

ResourceEntityResolver

org.springframework.beans.factory.xml.ResourceEntityResolver,XML 资源实例解析器,获取对应的 DTD 或 XSD 文件

构造函数 public class ResourceEntityResolver extends DelegatingEntityResolver { /** 资源加载器 */ private final ResourceLoader resourceLoader; public ResourceEntityResolver(ResourceLoader resourceLoader) { super(resourceLoader.getClassLoader()); this.resourceLoader = resourceLoader; } } public class DelegatingEntityResolver implements EntityResolver { /** Suffix for DTD files. */ public static final String DTD_SUFFIX = ".dtd"; /** Suffix for schema definition files. */ public static final String XSD_SUFFIX = ".xsd"; private final EntityResolver dtdResolver; private final EntityResolver schemaResolver; public DelegatingEntityResolver(@Nullable ClassLoader classLoader) { this.dtdResolver = new BeansDtdResolver(); this.schemaResolver = new PluggableSchemaResolver(classLoader); } }

注意 schemaResolver 为 XSD 的解析器,默认为 PluggableSchemaResolver 对象

resolveEntity 方法

内容版权声明:除非注明,否则皆为本站原创文章。

转载注明出处:https://www.heiqu.com/zwdfxz.html