zoukankan      html  css  js  c++  java
  • spring component-scan filter

    (参考的Spring version : 4.1.6.RELEASE)

    我们通常会使用component-scan来进行bean的加载,但是它里面的实现机制却是一知半解。根据原码来理解一下,可能会更加清晰。

    例如,我们通常会使用如下的配置:

    application.xml:

    <context:component-scan base-package="com.cn.kvn.service,com.cn.kvn.config,com.baidu">
            <context:include-filter type="annotation" expression="com.alibaba.dubbo.config.annotation.Service" />
            <context:exclude-filter type="annotation" expression="org.springframework.stereotype.Controller" />
    </context:component-scan>

     spring-servlet.xml:

    <context:component-scan base-package="com.cn.kvn.controller" use-default-filters="false">
            <context:include-filter type="annotation" expression="org.springframework.stereotype.Controller" />
    </context:component-scan>

    看了下面的解释,你就能大体知道这些配置具体是怎么控制和生效的了。

    • componentScan解析bean的入口为:ComponentScanBeanDefinitionParser#parse(Element element, ParserContext parserContext)
    @Override
        public BeanDefinition parse(Element element, ParserContext parserContext) {
            String basePackage = element.getAttribute(BASE_PACKAGE_ATTRIBUTE);
            basePackage = parserContext.getReaderContext().getEnvironment().resolvePlaceholders(basePackage);
            String[] basePackages = StringUtils.tokenizeToStringArray(basePackage,
                    ConfigurableApplicationContext.CONFIG_LOCATION_DELIMITERS);
    
            // Actually scan for bean definitions and register them.
            ClassPathBeanDefinitionScanner scanner = configureScanner(parserContext, element);
            Set<BeanDefinitionHolder> beanDefinitions = scanner.doScan(basePackages);
            registerComponents(parserContext.getReaderContext(), beanDefinitions, element);
    
            return null;
        }

    base-package属性告诉spring要扫描的包,use-default-filters="false"表示不要使用默认的过滤器

    • configureScanner会去配置scan时的使用的filter,其中use-default-filters属性是来控制是否要使用默认的过滤器的。

    (默认的过滤器会去解析base-package下的含有@Component注解的类作为bean,其中@Repository, @Service, and @Controller都是@Component的子注解,故,默认的过滤器会将它们全部解析成bean)

    原码中的英文注释:(ClassPathScanningCandidateComponentProvider#ClassPathScanningCandidateComponentProvider(boolean useDefaultFilters, Environment environment))

    useDefaultFilters whether to register the default filters for the @Component, @Repository, @Service, and @Controller stereotype annotations
    • 用户自定义的include-filter和exclude-filter会在ComponentScanBeanDefinitionParser#parseTypeFilters(Element element, ClassPathBeanDefinitionScanner scanner, ParserContext parserContext)方法中被解析加载。
    • 在执行Set<BeanDefinitionHolder> beanDefinitions = scanner.doScan(basePackages);的时候,使用过滤器的顺序是,exclude-filter优于include-filter。

    也就是说,如果同时定义了exclude-filter排除了某类(某个)bean,但是include-filter又将其包含了,则该bean不会被加载到spring容器。

    ClassPathScanningCandidateComponentProvider.java
    /**
    * Determine whether the given class does not match any exclude filter * and does match at least one include filter. * @param metadataReader the ASM ClassReader for the class * @return whether the class qualifies as a candidate component */ protected boolean isCandidateComponent(MetadataReader metadataReader) throws IOException { for (TypeFilter tf : this.excludeFilters) { if (tf.match(metadataReader, this.metadataReaderFactory)) { return false; } } for (TypeFilter tf : this.includeFilters) { if (tf.match(metadataReader, this.metadataReaderFactory)) { return isConditionMatch(metadataReader); } } return false; }

    附:过滤规则设置

    context:component-scan节点允许有两个子节点<context:include-filter>和<context:exclude-filter>。filter标签的type和表达式说明如下:

    Filter Type Examples Expression Description include-filter为例
    annotation org.example.SomeAnnotation 符合SomeAnnoation的target class

    <context:include-filter type="annotation" expression="org.aspectj.lang.annotation.Aspect"/>

    表示扫描base-package下的类上加了Aspect注解的类,并注册到spring的bean容器

    assignable org.example.SomeClass 指定class或interface的全名

    <context:include-filter type="assignable" expression="com.test.scan.StuService"/>

    指定扫描StuService类作为bean

    aspectj org.example..*Service+ AspectJ語法  
    regex org.example.Default.* Regelar Expression  
    custom org.example.MyTypeFilter Spring3新增自訂Type,實作org.springframework.core.type.TypeFilter  

    在我们的示例中,将filter的type设置成了正则表达式,regex,注意在正则里面.表示所有字符,而.才表示真正的.字符。我们的正则表示以Dao或者Service结束的类。

    我们也可以使用annotaion来限定,如下:

    	<context:component-scan base-package="cn.outofmemory.spring" use-default-filters="false">
    		<context:include-filter type="annotation" expression="org.springframework.stereotype.Repository"/> 
    		<context:include-filter type="annotation" expression="org.springframework.stereotype.Service"/> 
    	 </context:component-scan>

     这里我们指定的include-filter的type是annotation,expression则是注解类的全名。

    另外context:conponent-scan节点还有<context:exclude-filter>可以用来指定要排除的类,其用法和include-filter一致。

  • 相关阅读:
    2017-2018-1 课表
    所编裴书练习参考解答封面 [购买了书的同志记得一定要邮件联系, 并加我微信, 方便更正错误. 这里更新有时会慢, 或者懒得弄.]
    人工智能图片放大
    猜15个名人
    Excel 当前行高亮
    2014年至今的博文目录(更新至2019年1月7日,2017篇)
    拓扑学中凝聚点的几个等价定义
    江苏省2017年高等数学竞赛本二试题(含解答)
    裴礼文数学分析中的典型问题与方法第4章一元函数积分学练习
    2017年华东师范大学数学竞赛(数学类)试题
  • 原文地址:https://www.cnblogs.com/kevin-yuan/p/5068448.html
Copyright © 2011-2022 走看看