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 文件进行验证
ResourceEntityResolverorg.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 方法