目录
Spring bean 扫描流程
引入
上一个分析文章中我们知道从Class到一个Bean中间是需要把Class先创建成BeanDefinition
然后由Spring控制在不同的时机用不用的方法依据BeanDefinition转化为Bean供我们使用
那么Class到BeanDefinition的流程是什么?
先说结论这个过程主要发生在
ClassPathBeanDefinitionScanner : 扫描读取Class文件为Resource对象
扫描:ClassPathBeanDefinitionScanner
org.springframework.context.annotation.ClassPathBeanDefinitionScanner#doScan
这个方法就是扫描包中的文件,把文件加载成Resource对象的并注册成为BeanDefinition的
doScan
分析下细节:
遍历basePackages : basePackage {
查找到所有符合要求的BeanDefinition(findCandidateComponents(basePackage)) : candidates
遍历所有的 BeanDefinitions : beanDefinitions {
解析:Scope.class
获取beanName
执行postProcessBeanDefinition:
1. 设置默认值
setLazyInit
setAutowireMode(defaults.getAutowireMode());
setDependencyCheck(defaults.getDependencyCheck());
setInitMethodName(defaults.getInitMethodName());
setEnforceInitMethod(false);
setDestroyMethodName(defaults.getDestroyMethodName());
setEnforceDestroyMethod(false);
2. setAutowireCandidate
解析 @Lazy、@Primary、@DependsOn、@Role、@Description
if (this.registry是否存在beanName) {
注册BeanDefinition到this.registry
}
}
}
findCandidateComponents(basePackage)
if 没有 编写索引文件 那么进入 scanCandidateComponents(basePackage);
scanCandidateComponents(basePackage) {
路径转化 包名转化为三部分组成的路径
1. classpath*:
2. 包名中的 "." 替换为 "/"
3. /**/*.class
扫描路径中的class文件为 Resource[] resources
遍历 resources :: resource {
判断是否符合条件
1. excludeFilters 符合任意一个则排除
2. includeFilters 符合任意一个则包含
}
}
this.registry
这里的 registry 并不是 AnnotationConfigApplicationContext 虽然 AppContext本身也是Registry
但是这里的 registry 是
org.springframework.context.annotation.ComponentScanAnnotationParser#parse 中 new 出来的
ClassPathBeanDefinitionScanner 中带有的 org.springframework.beans.factory.support.DefaultListableBeanFactory
而在 DefaultListableBeanFactory 维护了一个 Map<String, BeanDefinition> beanDefinitionMap = new ConcurrentHashMap(256);
- 是否存在 : this.beanDefinitionMap.containsKey(beanName);
- 注册:this.beanDefinitionMap.put(beanName, beanDefinition);