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)
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一致。
總結
以上是生活随笔為你收集整理的spring component-scan filter的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: Java线程池的工作原理与实现
- 下一篇: 【转载】eclipse常用插件在线安装地