组件
annotation读取主要涉及以下组件
-
AnnotatedBeanDefinitionReader
- 读取并注册指定class(es) -
ClassPathBeanDefinitionScanner
- 扫描注册指定package 下的bean -
AnnotationConfigUtils
- 注册相关BeanFactoryPostProcessor,提供一些common的annotation处理
以及 @Configuration 处理相关的组件
-
ConfigurationClassBeanDefinitionReader
- 解析处理 Configuration Bean -
ConfigurationClassPostProcessor
- 处理 @Configuration -
ComponentScanAnnotationParser
- 处理 @ComponentScan -
ContextNamespaceHandler
&ComponentScanBeanDefinitionParser
- 处理xml配置中的 component-scan
以及一些辅助类
-
BeanNameGenerator
(AnnotationBeanNameGenerator
) -
ScopeMetadataResolver
(AnnotationScopeMetadataResolver
) -
ConditionEvaluator
处理 @Conditional
Annotation & BeanDefinition
为了在BeanDefinition中承载annotation, AnnotatedBeanDefinitionReader
和 ClassPathBeanDefinitionScanner
分别使用了 实现了AnnotatedBeanDefinition
的AnnotatedGenericBeanDefinition
和 ScannedGenericBeanDefinition
。
AnnotatedBeanDefinition
AnnotatedBeanDefinition
通过AnnotationMetadata
来暴露annotation及class信息。
public interface AnnotatedBeanDefinition extends BeanDefinition {
AnnotationMetadata getMetadata();
MethodMetadata getFactoryMethodMetadata();
}
AnnotationMetadata
AnnotationMetadata
继承了 ClassMetadata
和 AnnotatedTypeMetadata
。暴露的接口均以String 的形式表现 annotation 和 class 信息,以便独立于(先于) ClassLoader 读取存储这些metadata。
AnnotatedGenericBeanDefinition
使用了 StandardAnnotationMetadata
通过java reflection 获取 annotation/class 信息。
ScannedGenericBeanDefinition
则使用了 AnnotationMetadataReadingVisitor
通过 ASM 读取 annotation/class 信息。
AnnotatedBeanDefinition读取注册
AnnotatedBeanDefinition读取有两种方式
一是使用 AnnotatedBeanDefinitionReader
,传入bean的Class进行读取注册
一是使用 ClassPathBeanDefinitionScanner
扫描classpath 找出符合条件的class进行注册
这一个步骤等价于XmlBeanDefinitionReader
从XMl中读取注册bean。而具体处理@Configuration @Import 等等的操作会留给 ConfigurationClassPostProcessor
处理。这样也使得xml 读取的bean,如果需要,同样可以使用 @Configuration 等annotation。
AnnotatedBeanDefinitionReader
初始化
AnnotatedBeanDefinitionReader
创建时会用 AnnotationConfigUtils.registerAnnotationConfigProcessors(BeanDefinitionRegistry)
向registry 注册annotation 相关的BeanFactoryPostProcessor
registerBean
AnnotatedBeanDefinitionReader
的读取很简单。由于 Java Config 不涉及像XML Config 中的 constructor-arg, property-value 等等的配置,所以只需要关注一些Bean基本的属性即可。
<T> void doRegisterBean(Class<T> annotatedClass, @Nullable Supplier<T> instanceSupplier, @Nullable String name,
@Nullable Class<? extends Annotation>[] qualifiers, BeanDefinitionCustomizer... definitionCustomizers) {
// 1. 创建 AnnotatedGenericBeanDefinition
AnnotatedGenericBeanDefinition abd = new AnnotatedGenericBeanDefinition(annotatedClass);
// 2. 检查 @Conditional
if (this.conditionEvaluator.shouldSkip(abd.getMetadata())) {
return;
}
...
// 3. 检查设置Scope
ScopeMetadata scopeMetadata = this.scopeMetadataResolver.resolveScopeMetadata(abd);
abd.setScope(scopeMetadata.getScopeName());
// 4. 获取Bean Name
String beanName = (name != null ? name : this.beanNameGenerator.generateBeanName(abd, this.registry));
// 5. 处理 @Lazy, @Primary, @DependesOn, @Role, D@escription
AnnotationConfigUtils.processCommonDefinitionAnnotations(abd);
...
// 6. 向registry 注册
BeanDefinitionHolder definitionHolder = new BeanDefinitionHolder(abd, beanName);
definitionHolder = AnnotationConfigUtils.applyScopedProxyMode(scopeMetadata, definitionHolder, this.registry);
BeanDefinitionReaderUtils.registerBeanDefinition(definitionHolder, this.registry);
}
ClassPathBeanDefinitionScanner
初始化
- 设置filters,主要是添加了
new AnnotationTypeFilter(Component.class)
来过滤有 @Comonent 的class - 设置
ResourcePatternResolver
, 用来读取class 文件 - 设置
MetadataReaderFactory
为CachingMetadataReaderFactory
,对应生成SimpleMetadataReader
类型的MetadataReader
- 读取之前执行时生成的 componentsIndex
public ClassPathBeanDefinitionScanner(BeanDefinitionRegistry registry, boolean useDefaultFilters,
Environment environment, @Nullable ResourceLoader resourceLoader) {
this.registry = registry;
if (useDefaultFilters) {
registerDefaultFilters();
}
setEnvironment(environment);
setResourceLoader(resourceLoader);
}
public void setResourceLoader(@Nullable ResourceLoader resourceLoader) {
this.resourcePatternResolver = ResourcePatternUtils.getResourcePatternResolver(resourceLoader);
this.metadataReaderFactory = new CachingMetadataReaderFactory(resourceLoader);
this.componentsIndex = CandidateComponentsIndexLoader.loadIndex(this.resourcePatternResolver.getClassLoader());
}
scan
doScan(String... basePackages)
- 调用
findCandidateComponents
扫描获得所有能通过filter 的class的BeanDefinition
- 类似
AnnotatedBeanDefinitionReader
一样处理和注册bean
findCandidateComponents(String basePackage)
findCandidateComponents
从 componentsIndex 读取或者直接扫描classpath
public Set<BeanDefinition> findCandidateComponents(String basePackage) {
if (this.componentsIndex != null && indexSupportsIncludeFilters()) {
return addCandidateComponentsFromIndex(this.componentsIndex, basePackage);
}
else {
return scanCandidateComponents(basePackage);
}
}
scanCandidateComponents(String basePackage)
- 使用
ResourcePatternResolver
加载所有在classpath*:{basepakcage}/**/*.class
上的class。 - 遍历class Resource,对每个resource, 生成
SimpleMetadataReader
读取resource -
ScannedGenericBeanDefinition
存储通过 metaReader 获取的 AnnotationMetaData 生成 BeanDefinition
classpath*:
和 classpath:
的区别在于:
classpath*:
会搜索所有classpath 上满足条件的class, classpath:
只会找到满足条件的第一个。``classpath:`如果没有找到的话会break
// ClassPathScanningCandidateComponentProvider
// with try..catch, else {}, logging removed
private Set<BeanDefinition> scanCandidateComponents(String basePackage) {
Set<BeanDefinition> candidates = new LinkedHashSet<>();
String packageSearchPath = ResourcePatternResolver.CLASSPATH_ALL_URL_PREFIX +
resolveBasePackage(basePackage) + '/' + this.resourcePattern;
Resource[] resources = getResourcePatternResolver().getResources(packageSearchPath);
for (Resource resource : resources) {
if (resource.isReadable()) {
MetadataReader metadataReader = getMetadataReaderFactory().getMetadataReader(resource);
if (isCandidateComponent(metadataReader)) {
ScannedGenericBeanDefinition sbd = new ScannedGenericBeanDefinition(metadataReader);
sbd.setResource(resource);
sbd.setSource(resource);
if (isCandidateComponent(sbd)) {
candidates.add(sbd);
}
}
}
}
return candidates;
}
// ScannedGenericBeanDefinition
public ScannedGenericBeanDefinition(MetadataReader metadataReader) {
Assert.notNull(metadataReader, "MetadataReader must not be null");
this.metadata = metadataReader.getAnnotationMetadata();
setBeanClassName(this.metadata.getClassName());
}
SimpleMetadataReader
使用了repackage 的 ASM
- 使用
ClassReader
读入class 文件 - 利用
AnnotationMetadataReadingVisitor
从ClassReader
读取 annotation/class 信息
//SimpleMetadataReader
SimpleMetadataReader(Resource resource, @Nullable ClassLoader classLoader) throws IOException {
InputStream is = new BufferedInputStream(resource.getInputStream());
ClassReader classReader;
try {
classReader = new ClassReader(is);
}
catch (IllegalArgumentException ex) {
throw new NestedIOException("ASM ClassReader failed to parse class file - " +
"probably due to a new Java class file version that isn't supported yet: " + resource, ex);
}
finally {
is.close();
}
AnnotationMetadataReadingVisitor visitor = new AnnotationMetadataReadingVisitor(classLoader);
classReader.accept(visitor, ClassReader.SKIP_DEBUG);
this.annotationMetadata = visitor;
// (since AnnotationMetadataReadingVisitor extends ClassMetadataReadingVisitor)
this.classMetadata = visitor;
this.resource = resource;
}
网友评论