上篇文章已经简单介绍了AnnotatedBeanDefinitionReader和ClassPathBeanDefinitionScanner的功能,这篇文章将详细的分析这两个对象  在分析这两个类之前再贴一下AnnotationConfigApplicationContext的继承关系  可以看到AnnotationConfigApplicationContext有实现一个AnnotationConfigRegistry接口,这个接口里面有两个方法,先说结论register是有AnnotatedBeanDefinitionReader完成的,scan是由ClassPathBeanDefinitionScanner完成的
 再看源码   这里我们就知道了AnnotatedBeanDefinitionReader和ClassPathBeanDefinitionScanner分别完成了AnnotationConfigApplicationContext两个方法的实现,那它们还有没有其他的作用呢?
1、AnnotatedBeanDefinitionReader
这个类的初始化的时候就完成了一件事就是把几个固定的postProcessor包装成BeanDifinition(BeanDifinition后面会专门写一篇文章进行分析,现在知道这个概念就可以),然后放入到容器内(另外BeanFactory有个子类为DefaultListableBeanFactory,它有个成员变量beanDefinitionMap,这里会把所有的BeanDefinition放入beanDefinitionMap)。另外一个作用就是刚才说到的实现了AnnotationConfigApplicationContext的register方法 
1.1 把几个固定的postProcessor包装成BeanDifinition,并放入容器
这是reader初始化的入口,依次点进去  构造方法 
构造方法重载  这里我们看到他除了初始化了两个成员变量外还执行了一个
AnnotationConfigUtils.registerAnnotationConfigProcessors(this.registry);
这是一个静态方法,我们点进去就能看到它完成了【把几个固定的postProcessor包装成BeanDifinition】这个流程 点进去  构造方法重载  最终包装BeanDifinition并注册到容器的流程就在这里
1.2 提供AnnotationConfigApplicationContext.register()方法的的实现
从下图可以看到AnnotatedBeanDefinitionReader为AnnotationConfigApplicationContext提供了register方法的实现  点进去为循环调用  点进去才是真正的实现
private <T> void doRegisterBean(Class<T> beanClass, @Nullable String name,
@Nullable Class<? extends Annotation>[] qualifiers, @Nullable Supplier<T> supplier,
@Nullable BeanDefinitionCustomizer[] customizers) {
AnnotatedGenericBeanDefinition abd = new AnnotatedGenericBeanDefinition(beanClass);
if (this.conditionEvaluator.shouldSkip(abd.getMetadata())) {
return;
}
abd.setInstanceSupplier(supplier);
ScopeMetadata scopeMetadata = this.scopeMetadataResolver.resolveScopeMetadata(abd);
abd.setScope(scopeMetadata.getScopeName());
String beanName = (name != null ? name : this.beanNameGenerator.generateBeanName(abd, this.registry));
AnnotationConfigUtils.processCommonDefinitionAnnotations(abd);
if (qualifiers != null) {
for (Class<? extends Annotation> qualifier : qualifiers) {
if (Primary.class == qualifier) {
abd.setPrimary(true);
}
else if (Lazy.class == qualifier) {
abd.setLazyInit(true);
}
else {
abd.addQualifier(new AutowireCandidateQualifier(qualifier));
}
}
}
if (customizers != null) {
for (BeanDefinitionCustomizer customizer : customizers) {
customizer.customize(abd);
}
}
BeanDefinitionHolder definitionHolder = new BeanDefinitionHolder(abd, beanName);
definitionHolder = AnnotationConfigUtils.applyScopedProxyMode(scopeMetadata, definitionHolder, this.registry);
BeanDefinitionReaderUtils.registerBeanDefinition(definitionHolder, this.registry);
}
可以看到最后一行有把BeanDifinition存到BeanDifinitionMap中
2、ClassPathBeanDefinitionScanner
ClassPathBeanDefinitionScanner主要完成了扫描,但是具体的扫描有两种实现,第一种是AnnotationConfigApplicationContext.scan方法中有调用ClassPathBeanDefinitionScanner的scan方法(这时使用默认的扫描规则,默认扫描规则是实例化的时候指定的)  方法重载  再次重载  指定默认的规则
第二种是为重新new一个ClassPathBeanDefinitionScanner(也就是不适用AnnotationConfigApplicationContext中的ClassPathBeanDefinitionScanner类型的成员变量),为其指定个性化扫描规则完成扫描,spring中的ConfigurationClassPostProcessor就这么干的,mybatis也是这么干的,这个会放在后面分析 下面是AnnotationConfigApplicationContext.scan的调用过程  方法重载  进入doScan方法  findCandidateComponents方法真正执行扫描  方法重载
private Set<BeanDefinition> scanCandidateComponents(String basePackage) {
Set<BeanDefinition> candidates = new LinkedHashSet<>();
try {
String packageSearchPath = ResourcePatternResolver.CLASSPATH_ALL_URL_PREFIX +
resolveBasePackage(basePackage) + '/' + this.resourcePattern;
Resource[] resources = getResourcePatternResolver().getResources(packageSearchPath);
boolean traceEnabled = logger.isTraceEnabled();
boolean debugEnabled = logger.isDebugEnabled();
for (Resource resource : resources) {
if (traceEnabled) {
logger.trace("Scanning " + resource);
}
if (resource.isReadable()) {
try {
MetadataReader metadataReader = getMetadataReaderFactory().getMetadataReader(resource);
if (isCandidateComponent(metadataReader)) {
ScannedGenericBeanDefinition sbd = new ScannedGenericBeanDefinition(metadataReader);
sbd.setSource(resource);
if (isCandidateComponent(sbd)) {
if (debugEnabled) {
logger.debug("Identified candidate component class: " + resource);
}
candidates.add(sbd);
}
else {
if (debugEnabled) {
logger.debug("Ignored because not a concrete top-level class: " + resource);
}
}
}
else {
if (traceEnabled) {
logger.trace("Ignored because not matching any filter: " + resource);
}
}
}
catch (Throwable ex) {
throw new BeanDefinitionStoreException(
"Failed to read candidate component class: " + resource, ex);
}
}
else {
if (traceEnabled) {
logger.trace("Ignored because not readable: " + resource);
}
}
}
}
catch (IOException ex) {
throw new BeanDefinitionStoreException("I/O failure during classpath scanning", ex);
}
return candidates;
}
这里真正执行了扫描,这里使用的是asm的扫描方式,这里我们只了解把指定包里的类扫描到容器里面就可以,关于asm的扫描后面会专门有一篇文章进行讲解,欢迎关注本系列的课程。 这里的扫描只是AnnotationConfigApplicationContext.scan的执行过程,关于ConfigurationClassPostProcessor的扫描过程,请关注后续的文章。 如果想要第一时间获取本系列的更新,请关注公众号: 
|