先不废话了,直接干吧。
@ComponentScan注解的作用可以简述为:将项目中所有被@Component
注解标记的类---->组装成BeanDefinition
---->然后以key value
的形式注入到IOC容器中。
@ComponentScan中有多个参数,其中尤为重要的几个参数如下:
排除
注入到IOC容器;示例:
@ComponentScan(value = "com.zhouyu",excludeFilters = {@ComponentScan.Filter(type = FilterType.ASSIGNABLE_TYPE,classes = UserService.class)},includeFilters = {@ComponentScan.Filter(type = FilterType.ASSIGNABLE_TYPE,classes = User.class)})
在讲源码之前呢,我们可以先增强几个知识点的概念。这些知识点在阅读@ComponentScan注解源码中起着关键作用。
1、@ComponentScan只会扫描被 @Component标识的类
。 诸如@Bean、spring.xml文件的< bean/>标签、编程式声明BeanDefinition等,都不会被@ComponentScan扫描;
2、@ComponentScan的excludeFilters
和includeFilters
参数影响着类是否注入IOC容器。excludeFilters中指定了一个带有@Component注解的类,该类也不会注入到容器中;includeFilters中指定了一个不带有@Component注解的类,该类也会注入到容器中;
3、被@ComponentScan扫描注入到IOC容器中的BeanDefinition,其具体实现类是:ScannedGenericBeanDefinition
。
4、@ComponentScan扫描涉及到的相关注解:@Conditional
和@Scope
和@Lazy
、@Primary
、@DependsOn
、@Role
、@Description
。
5、须知Resource
类和MetadataReader
类。
6、@ComponentScan扫描最终生成两个map:Map
与Map
。
@ComponentScan("org.example")
public class AppConfig {/*** 声明:* 如果@Bean没有设置value参数,那么IOC中beanName = "createBookService";* 如果@Bean设置了多个value参数,那么IOC中beanName = array[0]*/@Bean({"bookService","bookService2"})public BookService createBookService(){return new BookService();}
}
源码具体位置:org.springframework.context.annotation.ClassPathBeanDefinitionScanner#doScan
protected Set doScan(String... basePackages) {Assert.notEmpty(basePackages, "At least one base package must be specified");Set beanDefinitions = new LinkedHashSet<>();// 遍历basePackagesfor (String basePackage : basePackages) {// 扫描basePackages下所有的文件,进行include、exclude、@Conditional判断后返回BeanDefinitionSet candidates = findCandidateComponents(basePackage);for (BeanDefinition candidate : candidates) {ScopeMetadata scopeMetadata = this.scopeMetadataResolver.resolveScopeMetadata(candidate); // scope解析:单例与多例candidate.setScope(scopeMetadata.getScopeName());String beanName = this.beanNameGenerator.generateBeanName(candidate, this.registry); // 生成beanName:默认是类名首字母小写,如果@Component中指定了name则使用指定的name/* ScannedGenericBeanDefinition extends GenericBeanDefinition(AbstractBeanDefinition) implements AnnotatedBeanDefinition */// 设置BeanDefinition的默认值if (candidate instanceof AbstractBeanDefinition) {postProcessBeanDefinition((AbstractBeanDefinition) candidate, beanName);}if (candidate instanceof AnnotatedBeanDefinition) {// 解析@Lazy、@Primary、@DependsOn、@Role、@DescriptionAnnotationConfigUtils.processCommonDefinitionAnnotations((AnnotatedBeanDefinition) candidate);}// 检查Spring容器中是否已经存在该beanName(如果存在则抛出异常)if (checkCandidate(beanName, candidate)) {BeanDefinitionHolder definitionHolder = new BeanDefinitionHolder(candidate, beanName);definitionHolder =AnnotationConfigUtils.applyScopedProxyMode(scopeMetadata, definitionHolder, this.registry);beanDefinitions.add(definitionHolder);// 注册: beanDefinitionMap.put(beanName, beanDefinition)registerBeanDefinition(definitionHolder, this.registry);}}}return beanDefinitions;}
下一篇:冒泡排序实现