先不废话了,直接干吧。
@ComponentScan注解的作用可以简述为:将项目中所有被@Component
注解直接或者间接标记的类---->组装成BeanDefinition
---->然后以key=beanName, value=BeanDefinition
的形式存储,为后续生成bean对象做准备。
提示:被@Component注解标记的类分为两种情况,这两种情况的类都会被Spring成功扫描。
1、该类直接被@Component注解标记
@Component
public class UserService {}
2、该类间接被@Component注解标记(@Configuration组成注解包含@Component注解)
@Configuration
public class ProConfig {}
--
@Target({ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Component
public @interface Configuration {
@AliasFor(
annotation = Component.class
)
String value() default "";
boolean proxyBeanMethods() default true;
}
上面是说的通过扫描得到BeanDefinition对象,我们还可以通过直接定义BeanDefinition,或解析spring.xml文件的
@ComponentScan中有多个参数,其中尤为重要的几个参数如下:
排除
扫描;示例:
@ComponentScan(value = "com.zhouyu",
excludeFilters = {@ComponentScan.Filter(type = FilterType.ASSIGNABLE_TYPE,classes = UserService.class)},
includeFilters = {@ComponentScan.Filter(type = FilterType.ASSIGNABLE_TYPE,classes = User.class)})
在讲源码之前呢,我们可以先增强几个知识点的概念。这些知识点在阅读Spring扫描源码中起着关键作用。
1、@ComponentScan只会扫描被 @Component标识的类
。 诸如@Bean、spring.xml文件的< bean/>标签、编程式声明BeanDefinition等,都不会被@ComponentScan扫描;
2、@ComponentScan的excludeFilters
和includeFilters
参数影响着类是否成功被扫描。excludeFilters中指定了一个带有@Component注解的类,该类也不会被扫描;includeFilters中指定了一个不带有@Component注解的类,该类也会被扫描;
3、被@ComponentScan扫描注入到IOC容器中的BeanDefinition,其具体实现类是:ScannedGenericBeanDefinition
。
4、@ComponentScan扫描涉及到的相关注解:@Conditional
和@Scope
和@Lookup
和@Lazy
、@Primary
、@DependsOn
、@Role
、@Description
。
5、须知Resource
类和MetadataReader
类。
6、@ComponentScan扫描最终生成两个map:Map
与Map
。
@ComponentScan("org.example")
public class AppConfig {
/**
* 声明:
* 如果@Bean没有设置value参数,那么beanName = "createBookService";
* 如果@Bean设置了多个value参数,那么beanName = array[0]
*/
@Bean({"bookService","bookService2"})
public BookService createBookService(){
return new BookService();
}
}
7、其他:
ASM技术
:为什么要使用ASM技术,Spring启动的时候需要去扫描,如果指定的包路径比较宽泛,那么扫描的类是非常多的,那如果在Spring启动时就把这些类全部加载进JVM了,这样不太好,所以使用了ASM技术;源码具体位置:org.springframework.context.annotation.ClassPathBeanDefinitionScanner#doScan
protected Set<BeanDefinitionHolder> doScan(String... basePackages) {
Assert.notEmpty(basePackages, "At least one base package must be specified");
Set<BeanDefinitionHolder> beanDefinitions = new LinkedHashSet<>();
// 遍历basePackages
for (String basePackage : basePackages) {
// 扫描basePackages下所有的文件,进行include、exclude、@Conditional判断后返回BeanDefinition
Set<BeanDefinition> 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、@Description
AnnotationConfigUtils.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;
}