上篇文章已经简单介绍了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);
// 根据元数据确定是否需要跳过 实例化BeanDefinition时会有默认的元数据生成
if (this.conditionEvaluator.shouldSkip(abd.getMetadata())) {
return;
}
// 设置supplier supplier不为空,就不再利用反射生成单例,而是由supplier提供
abd.setInstanceSupplier(supplier);
// 设置作用域
ScopeMetadata scopeMetadata = this.scopeMetadataResolver.resolveScopeMetadata(abd);
abd.setScope(scopeMetadata.getScopeName());
// 由beanNameGenerator生成beanName
String beanName = (name != null ? name : this.beanNameGenerator.generateBeanName(abd, this.registry));
// 给BeanDefinition设置默认值
AnnotationConfigUtils.processCommonDefinitionAnnotations(abd);
// class有没有注解
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);
// 真正的王BeanDifinition里面注册
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;
// 从相关路径中扫描出所有的类,里面主要保存了相关class文件的InputStream
Resource[] resources = getResourcePatternResolver().getResources(packageSearchPath);
boolean traceEnabled = logger.isTraceEnabled();
boolean debugEnabled = logger.isDebugEnabled();
for (Resource resource : resources) {
if (traceEnabled) {
logger.trace("Scanning " + resource);
}
// 判断InputStream指向的class是否存在
if (resource.isReadable()) {
try {
// 通过asm进行扫描并把扫描结果包装为MetadataReader
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的扫描过程,请关注后续的文章。
如果想要第一时间获取本系列的更新,请关注公众号: