Spring源码解析之context:component-scan标签解析

阅读须知

  • Spring源码版本:4.3.8
  • 文章中使用/* */注释的方法会做深入分析

正文

现在我们使用Spring的时候,基本上很少使用标签配置的方式来声明bean了,都是使用注解的方式来声明bean,下面我们就来分析一下这部分的源码实现。
在使用注解之前,我们要首先配置一下<context:component-scan/>标签,我们就以这个标签的解析作为入口来分析,这里需要读者了解Spring自定义标签解析的流程,不了解的可以看一下笔者之前关于Spring自定义标签解析的的文章,这里给出传送门,锁定ContextNamespaceHandler:

public void init() {
    registerBeanDefinitionParser("property-placeholder", new PropertyPlaceholderBeanDefinitionParser());
    registerBeanDefinitionParser("property-override", new PropertyOverrideBeanDefinitionParser());
    registerBeanDefinitionParser("annotation-config", new AnnotationConfigBeanDefinitionParser());
    /* 注册<context:component-scan/>标签解析器 */
    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());
}

分析ComponentScanBeanDefinitionParser的parse方法:

public BeanDefinition parse(Element element, ParserContext parserContext) {
	// 获取base-package属性
    String basePackage = element.getAttribute(BASE_PACKAGE_ATTRIBUTE);
    // 处理包路径中的特殊符号,如${}
    basePackage = parserContext.getReaderContext().getEnvironment().resolvePlaceholders(basePackage);
    // 分割
    String[] basePackages = StringUtils.tokenizeToStringArray(basePackage,
            ConfigurableApplicationContext.CONFIG_LOCATION_DELIMITERS);
    /* 配置Scanner */
    ClassPathBeanDefinitionScanner scanner = configureScanner(parserContext, element);
    /* 扫描 */
    Set<BeanDefinitionHolder> beanDefinitions = scanner.doScan(basePackages);
    /* 注册一些注解相关的PostProcessor,将BeanDefinition注册完成的事件通知给相关监听器 */
    registerComponents(parserContext.getReaderContext(), beanDefinitions, element);
    return null;
}

ComponentScanBeanDefinitionParser:

protected ClassPathBeanDefinitionScanner configureScanner(ParserContext parserContext, Element element) {
    boolean useDefaultFilters = true;
    // use-default-filters属性,默认为true
    if (element.hasAttribute(USE_DEFAULT_FILTERS_ATTRIBUTE)) {
        useDefaultFilters = Boolean.valueOf(element.getAttribute(USE_DEFAULT_FILTERS_ATTRIBUTE));
    }
    /* 创建Scanner */
    ClassPathBeanDefinitionScanner scanner = createScanner(parserContext.getReaderContext(), useDefaultFilters);
    scanner.setBeanDefinitionDefaults(parserContext.getDelegate().getBeanDefinitionDefaults());
    scanner.setAutowireCandidatePatterns(parserContext.getDelegate().getAutowireCandidatePatterns());
    // resource-pattern属性
    if (element.hasAttribute(RESOURCE_PATTERN_ATTRIBUTE)) {
        scanner.setResourcePattern(element.getAttribute(RESOURCE_PATTERN_ATTRIBUTE));
    }
    try {
        /* 解析name-generator属性 */
        parseBeanNameGenerator(element, scanner);
    }
    catch (Exception ex) {
        parserContext.getReaderContext().error(ex.getMessage(), parserContext.extractSource(element), ex.getCause());
    }
    try {
        /* 解析scope-resolver属性和scoped-proxy属性 */
        parseScope(element, scanner);
    }
    catch (Exception ex) {
        parserContext.getReaderContext().error(ex.getMessage(), parserContext.extractSource(element), ex.getCause());
    }
    /* 解析include-filter子标签和exclude-filter子标签 */
    parseTypeFilters(element, scanner, parserContext);
    return scanner;
}

ComponentScanBeanDefinitionParser:

protected ClassPathBeanDefinitionScanner createScanner(XmlReaderContext readerContext, boolean useDefaultFilters) {
    /* 创建ClassPathBeanDefinitionScanner */
    return new ClassPathBeanDefinitionScanner(readerContext.getRegistry(), useDefaultFilters,
            readerContext.getEnvironment(), readerContext.getResourceLoader());
}

ClassPathBeanDefinitionScanner:

public ClassPathBeanDefinitionScanner(BeanDefinitionRegistry registry, boolean useDefaultFilters,
        Environment environment, ResourceLoader resourceLoader) {
    Assert.notNull(registry, "BeanDefinitionRegistry must not be null");
    this.registry = registry;
    if (useDefaultFilters) {
        /* 注册默认的过滤器 */
        registerDefaultFilters();
    }
    setEnvironment(environment);
    setResourceLoader(resourceLoader);
}

ClassPathScanningCandidateComponentProvider:

protected void registerDefaultFilters() {
    // 添加默认的Component注解的过滤器
    this.includeFilters.add(new AnnotationTypeFilter(Component.class));
    ClassLoader cl = ClassPathScanningCandidateComponentProvider.class.getClassLoader();
    try {
        this.includeFilters.add(new AnnotationTypeFilter(
                ((Class<? extends Annotation>) ClassUtils.forName("javax.annotation.ManagedBean", cl)), false));
        logger.debug("JSR-250 'javax.annotation.ManagedBean' found and supported for component scanning");
    }
    catch (ClassNotFoundException ex) {
    }
    try {
        this.includeFilters.add(new AnnotationTypeFilter(
                ((Class<? extends Annotation>) ClassUtils.forName("javax.inject.Named", cl)), false));
        logger.debug("JSR-330 'javax.inject.Named' annotation found and supported for component scanning");
    }
    catch (ClassNotFoundException ex) {
    }
}

这里我们看到了默认的@Component注解过滤器的添加,而我们常用的@Service、@Controller等注解都使用了@Component注解,所以同样会匹配这个过滤器。

@Target({ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Component // @Service注解也使用了@Component
public @interface Service {
    String value() default "";
}

ClassPathBeanDefinitionScanner:

protected void parseBeanNameGenerator(Element element, ClassPathBeanDefinitionScanner scanner) {
    // 如果配置了name-generator属性则设置为自定义的BeanNameGenerator
    if (element.hasAttribute(NAME_GENERATOR_ATTRIBUTE)) {
        BeanNameGenerator beanNameGenerator = (BeanNameGenerator) instantiateUserDefinedStrategy(
                element.getAttribute(NAME_GENERATOR_ATTRIBUTE), BeanNameGenerator.class,
                scanner.getResourceLoader().getClassLoader());
        scanner.setBeanNameGenerator(beanNameGenerator);
    }
}

ClassPathBeanDefinitionScanner:

protected void parseScope(Element element, ClassPathBeanDefinitionScanner scanner) {
    // scope-resolver属性
    if (element.hasAttribute(SCOPE_RESOLVER_ATTRIBUTE)) {
        // 不能与scoped-proxy同时出现
        if (element.hasAttribute(SCOPED_PROXY_ATTRIBUTE)) {
            throw new IllegalArgumentException(
                    "Cannot define both 'scope-resolver' and 'scoped-proxy' on <component-scan> tag");
        }
        ScopeMetadataResolver scopeMetadataResolver = (ScopeMetadataResolver) instantiateUserDefinedStrategy(
                element.getAttribute(SCOPE_RESOLVER_ATTRIBUTE), ScopeMetadataResolver.class,
                scanner.getResourceLoader().getClassLoader());
        scanner.setScopeMetadataResolver(scopeMetadataResolver);
    }
    // scope-proxy属性
    if (element.hasAttribute(SCOPED_PROXY_ATTRIBUTE)) {
        String mode = element.getAttribute(SCOPED_PROXY_ATTRIBUTE);
        // targetClass、interfaces、no三个属性值的设置
        if ("targetClass".equals(mode)) {
            scanner.setScopedProxyMode(ScopedProxyMode.TARGET_CLASS);
        }
        else if ("interfaces".equals(mode)) {
            scanner.setScopedProxyMode(ScopedProxyMode.INTERFACES);
        }
        else if ("no".equals(mode)) {
            scanner.setScopedProxyMode(ScopedProxyMode.NO);
        }
        else {
            throw new IllegalArgumentException("scoped-proxy only supports 'no', 'interfaces' and 'targetClass'");
        }
    }
}

ClassPathBeanDefinitionScanner:

protected void parseTypeFilters(Element element, ClassPathBeanDefinitionScanner scanner, ParserContext parserContext) {
    ClassLoader classLoader = scanner.getResourceLoader().getClassLoader();
    NodeList nodeList = element.getChildNodes();
    for (int i = 0; i < nodeList.getLength(); i++) {
        Node node = nodeList.item(i);
        if (node.getNodeType() == Node.ELEMENT_NODE) {
            String localName = parserContext.getDelegate().getLocalName(node);
            try {
                // 子标签include-filter
                if (INCLUDE_FILTER_ELEMENT.equals(localName)) {
                    TypeFilter typeFilter = createTypeFilter((Element) node, classLoader, parserContext);
                    scanner.addIncludeFilter(typeFilter);
                }
                // 子标签exclude-filter
                else if (EXCLUDE_FILTER_ELEMENT.equals(localName)) {
                    TypeFilter typeFilter = createTypeFilter((Element) node, classLoader, parserContext);
                    scanner.addExcludeFilter(typeFilter);
                }
            }
            catch (Exception ex) {
                parserContext.getReaderContext().error(
                        ex.getMessage(), parserContext.extractSource(element), ex.getCause());
            }
        }
    }
}

到这配置解析的准备工作就完成了,我们会在后面的文章继续分析注解的扫描流程。

  • 1
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值