(参考的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一致。

spring component-scan filter的更多相关文章

  1. [Spring Boot] Use Component Scan to scan for Bean

    Component Scan is important concept when we want to create Bean. Currently we know what, for the cla ...

  2. 解决Spring Security自定义filter重复执行问题

    今天做项目的时候,发现每次拦截器日志都会打两遍,很纳闷,怀疑是Filter被执行了两遍.结果debug之后发现还真是!记录一下这个神奇的BUG! 问题描述 项目中使用的是Spring-security ...

  3. Spring框架之Filter应用

    在web.xml中进行配置,对所有的URL请求进行过滤,就像"击鼓传花"一样,链式处理. 配置分为两种A和B. 在web.xml中增加如下内容: <filter> &l ...

  4. not registered via @EnableConfigurationProperties or marked as Spring component

    利用@ConfigurationProperties(prefix = "")来绑定属性时报错: not registered via @EnableConfigurationPr ...

  5. Spring Cloud Zuul Filter 和熔断

    转一篇很不错的关于Spring Cloud Zuul 相关用法的文章,基本包含常用的一些场景,另外附上实际项目中的熔断.打印请求日志和登录验证的实例. 原文地址:https://www.cnblogs ...

  6. spring boot: 通过filter过滤器实现中文的简体繁体字符集转换(spring boot 2.3.1)

    一,为什么要使用filter来实现简繁体转换? 项目中有时会有同时支持简体和繁体两种字符集的要求, 或者搜索引擎有支持繁体输入字符的需求. 针对繁体字符的显示, 我们通常会在数据库和模板.文案配置中默 ...

  7. Spring Boot 使用 Filter

    Filter 是 JavaEE 中 Servlet 规范的一个组件,位于包javax.servlet 中,它可以在 HTTP 请求到达 Servlet 之前,被一个或多个Filter处理. 1. 编写 ...

  8. Spring @ Component 的作用

    1.@controller 控制器(注入服务) 2.@service 服务(注入dao) 3.@repository dao(实现dao访问) 4.@component (把普通pojo实例化到spr ...

  9. spring @Component

    使用 @Component <context:component-scan base-package="dao" />   虽 然我们可以通过@Autowired或@R ...

  10. spring security 4 filter 顺序及作用

    Spring Security 有两个作用:认证和授权 一.Srping security 4 filter 别名及顺序 spring security 4 标准filter别名和顺序,因为经常要用就 ...

随机推荐

  1. mac xcworkspace xcodebuild

    xcodebuild 在介绍xcodebuild之前,需要先弄清楚一些在XCode环境下的一些概念[4]: Workspace:简单来说,Workspace就是一个容器,在该容器中可以存放多个你创建的 ...

  2. iOS开发UI篇—ios应用数据存储方式(归档)

    iOS开发UI篇—ios应用数据存储方式(归档)  一.简单说明 在使用plist进行数据存储和读取,只适用于系统自带的一些常用类型才能用,且必须先获取路径相对麻烦: 偏好设置(将所有的东西都保存在同 ...

  3. bzoj 2875: [Noi2012]随机数生成器

    #include<cstdio> #include<iostream> #include<cstring> #define ll long long using n ...

  4. mod_cluster启用https协议的步骤

    1.生成SSL证书与私钥 Generate Private Key on the Server Running Apache + mod_ssl First, generate a private k ...

  5. css布局之一列布局

    在我们浏览网页中经常看见一列布局其实一列布局就是 一般的一列布局的都是固定宽度的 body{margin:0;padding:0} .main{width:800px;height:300px;bac ...

  6. springmvc学习第二天

    一.pojo Spring mvc 会按请求参数名和pojo属性名进行自动匹配,自动为该对象填充属性值,并且支持级联属性 表单: <form action="springmvc/tes ...

  7. javascript之小积累-.-typeof与instanceof的区别

    1.typeof 是获取一个变量或表达式的类型,返回的值通常是string, number, boolean, object(null, 数组, 对象), function, undefined,可以 ...

  8. python学习:函数的学习

    我们写东东的时候,往往有一些东西要频繁去复用,那么每个功能是10行代码,复用2次就是20行,这样看来我们的程序如果频繁利用某些代码的话,那么会是我们开发的东西越来越臃肿.那么好的方法有没有呢,那就是函 ...

  9. IOS UIWebView引用外部CSS样式(转载)

    首先,将要引用的CSS样式导入到工程文件,然后我们可以自己拼装一个网页并引用这个样式,具体代码实现如下: -(void)viewDidLoad { [super viewDidLoad]; NSStr ...

  10. Java笔记6-数组

    知识大纲一.数组的应用由于数组是用来存储数据的,所以,它的操作总是增.删除.改.查的操作.数组做为一种最基本的数据结构,它在查询上效率是最高的.但是在增加.删除的操作效率是最低的. 因为,数组的长度一 ...