class ConfigurationClassParser {
// 解析配置类
public void parse(Set<BeanDefinitionHolder> configCandidates) {
// 遍历所有的配置类
for (BeanDefinitionHolder holder : configCandidates) {
BeanDefinition bd = holder.getBeanDefinition();
// 根据不同的参数,封装成ConfigurationClass配置类对象,调用processConfigurationClass进行解析
if (bd instanceof AnnotatedBeanDefinition) {
parse(((AnnotatedBeanDefinition) bd).getMetadata(), holder.getBeanName()) {
// 详见下面解析方法
processConfigurationClass(new ConfigurationClass(metadata, beanName));
}
continue;
}
if (bd instanceof AbstractBeanDefinition && ((AbstractBeanDefinition) bd).hasBeanClass()) {
parse(((AbstractBeanDefinition) bd).getBeanClass(), holder.getBeanName()) {
// 详见下面解析方法
processConfigurationClass(new ConfigurationClass(clazz, beanName));
}
continue;
}
parse(bd.getBeanClassName(), holder.getBeanName()) {
// 详见下面解析方法
MetadataReader reader = this.metadataReaderFactory.getMetadataReader(className);
processConfigurationClass(new ConfigurationClass(reader, beanName));
}
}
// 上面,所有的ConfigClass都解析完成,现在就要解析延迟导入的类了
this.deferredImportSelectorHandler.process(){
// 获取已经保存了需要延迟导入的类
List<DeferredImportSelectorHolder> deferredImports = this.deferredImportSelectors;
// 将deferredImportSelectors置为空,这个要与ConfigurationClassParser.DeferredImportSelectorHandler.handle对比看
// 因为将deferredImportSelectors置为空,如果调用DeferredImportSelectorHandler.handle才是真正执行导入逻辑
this.deferredImportSelectors = null;
try {
// 在解析的时候,添加到deferredImportSelectors的Import类,还没有处理
// 如果存在现在来处理
if (deferredImports != null) {
// 创建一个延迟导入的分组处理器,用于分组导入
DeferredImportSelectorGroupingHandler handler = new DeferredImportSelectorGroupingHandler();
// 排序
deferredImports.sort(DEFERRED_IMPORT_COMPARATOR);
// 将导入的类保存到configurationClasses中
handler.register(holder) {
// 获取导入的分组
Class<? extends Group> group = deferredImport.getImportSelector().getImportGroup();
// 保存到map中
DeferredImportSelectorGrouping grouping = this.groupings.computeIfAbsent((group != null ? group : deferredImport), key -> new DeferredImportSelectorGrouping(createGroup(group)));
// 将当前导入的类保存到当前分组中
grouping.add(deferredImport);
// 缓存需要解析的配置类信息
this.configurationClasses.put(deferredImport.getConfigurationClass().getMetadata(), deferredImport.getConfigurationClass());
}
// 此时真正处理延迟的Import的类
handler.processGroupImports() {
// 遍历所有的分组
for (DeferredImportSelectorGrouping grouping : this.groupings.values()) {
// 分组导入
grouping.getImports().forEach(entry -> {
// 获取缓存的ConfigClass
ConfigurationClass configurationClass = this.configurationClasses.get(entry.getMetadata());
// 循环处理Import注解
processImports(configurationClass, asSourceClass(configurationClass), asSourceClasses(entry.getImportClassName()), false);
});
}
}
}
} finally {
// 处理完当前延迟的类,需要将deferredImportSelectors重新赋值为默认值
this.deferredImportSelectors = new ArrayList<>();
}
}
}
/**
* 解析配置类
*
* @param configClass 配置类的所有信息
*/
protected void processConfigurationClass(ConfigurationClass configClass) throws IOException {
// 使用条件表达式判断当前配置类是否符合解析条件
// 就是处理@Conditional注解
if (this.conditionEvaluator.shouldSkip(configClass.getMetadata(), ConfigurationPhase.PARSE_CONFIGURATION)) {
return;
}
// 处理过的配置类需要缓存
ConfigurationClass existingClass = this.configurationClasses.get(configClass);
// 如果之前已经处理过该配置类
if (existingClass != null) {
// 判断正在解析的配置类是不是被导入的
// importedBy保存的是当前配置类是被哪个配置类导入的
// 例如A导入B,在B配置类的importedBy中,存入的是A的配置信息
if (configClass.isImported() {
return !this.importedBy.isEmpty();
}){
// 上次解析这个类也是被导入的
if (existingClass.isImported()) {
// 将导入信息合并,原因就是A是被B导入的,现在A又被C导入,所以,A最终是被B,C导入的
existingClass.mergeImportedBy(configClass) {
this.importedBy.addAll(otherConfigClass.importedBy);
}
}
// 这个判断就是为了mergeImportedBy,只做这一件事
// 因为这个类已经被解析过了,其他的不需要再处理
return;
}
// 只要不是被导入的,就没必要保存importedBy信息
// 所以,可以直接将已经解析过的配置删除,重新解析一次
else{
this.configurationClasses.remove(configClass);
this.knownSuperclasses.values().removeIf(configClass::equals);
}
}
// 将配置类封装成SourceClass,SourceClass是描述目标类的信息,内部包含正在解析的类的元数据信息
// 因为最终要获取到当前配置类的所有父类,所以封装成SourceClass会更方便一些
SourceClass sourceClass = asSourceClass(configClass)
do {
// 正式解析配置类的注解或者方法信息,核心
sourceClass = doProcessConfigurationClass(configClass, sourceClass);
}
// 不停地解析,直到返回空
while (sourceClass != null);
// 保存解析后的配置类,内部包含了解析到的所有数据
this.configurationClasses.put(configClass, configClass);
}
/**
* 解析的核心逻辑
*
* @param configClass 正在解析的配置类
* @param sourceClass 配置类本身的元信息对象
*/
protected final SourceClass doProcessConfigurationClass(ConfigurationClass configClass, SourceClass sourceClass) {
// 第一步: 解析配置类中的嵌套的类,内部类
// 处理配置类中包含了Component注解的情况,@Component和@Configuration都包含
if (configClass.getMetadata().isAnnotated(Component.class.getName())) {
// 解析配置类中的嵌套的类,内部类
processMemberClasses(configClass, sourceClass) {
// 获取该配置类的所有成员类
Collection<SourceClass> memberClasses = sourceClass.getMemberClasses() {
// 内部调用jdk内置的提供获取成员类的方法
Class<?>[] declaredClasses = sourceClass.getDeclaredClasses();
for (Class<?> declaredClass : declaredClasses) {
members.add(asSourceClass(declaredClass));
}
// 保存所有的成员类
return members;
}
// 如果存在成员类
if (!memberClasses.isEmpty()) {
// 要判断一下成员类是不是符合配置类的条件
// 如果符合配置类的条件,也需要作为配置类进行解析
List<SourceClass> candidates = new ArrayList<>(memberClasses.size());
for (SourceClass memberClass : memberClasses) {
// 是否符合配置类的条件,上面有相吸解析
if (ConfigurationClassUtils.isConfigurationCandidate(memberClass.getMetadata()) {
// 如果此类是接口,不处理
if (metadata.isInterface()) {
return false;
}
// static {
// candidateIndicators.add(Component.class.getName());
// candidateIndicators.add(ComponentScan.class.getName());
// candidateIndicators.add(Import.class.getName());
// candidateIndicators.add(ImportResource.class.getName());
// }
// 如果是类上存在上面这几个注解,表示也属于配置Bean,也算作是一个配置类
for (String indicator : candidateIndicators) {
if (metadata.isAnnotated(indicator)) {
return true;
}
}
// 上面几种都没,判断当前类中是否存在@Bean标注的方法,如果存在,也表示是一个配置类
return metadata.hasAnnotatedMethods(Bean.class.getName());
}
// 当前成员类的类名不能与当前解析的配置类名称一样
&&!memberClass.getMetadata().getClassName().equals(configClass.getMetadata().getClassName())){
// 表示当前类是一个配置类
candidates.add(memberClass);
}
}
// 对嵌套的配置类进行排序
OrderComparator.sort(candidates);
// 遍历这些嵌套的配置类
for (SourceClass candidate : candidates) {
// 这里是处理循环导入的问题
// 当正在导入的时候,当前配置类存在导入的栈中,导入完成才会被importStack出栈
// 所以所,如果当前类已经在导入栈中,说明它还未导入完
// 这说明什么,内部类是通过导入完成的,类似于@Import的方式来处理的
if (this.importStack.contains(configClass)) {
this.problemReporter.error(new CircularImportProblem(configClass, this.importStack));
continue;
}
// 如果没有被导入,保存到导入栈中
this.importStack.push(configClass);
try {
// 解析当前内部类配置类,递归处理
processConfigurationClass(candidate.asConfigClass(configClass));
} finally {
// 解析完成出栈
this.importStack.pop();
}
}
}
}
}
// 第二步: 处理@PropertySource注解
for (AnnotationAttributes propertySource : AnnotationConfigUtils.attributesForRepeatable(sourceClass.getMetadata(), PropertySources.class, PropertySource.class)) {
// 解析@PropertySources的配置文件属性
if (this.environment instanceof ConfigurableEnvironment) {
// 解析配置文件
processPropertySource(propertySource) {
// 获取文件路径
String[] locations = propertySource.getStringArray("value");
// 创建解析配置类的工厂
DEFAULT_PROPERTY_SOURCE_FACTORY = new DefaultPropertySourceFactory();
PropertySourceFactory factory = (factoryClass == PropertySourceFactory.class ? DEFAULT_PROPERTY_SOURCE_FACTORY : BeanUtils.instantiateClass(factoryClass));
// 获取解析后的路径名,因为路径可以出现占位符
// @PropertySource(value = {"classpath:${user.name}.properties"})
// 对应系统变量中,user.name对应值.properties文件
String resolvedLocation = this.environment.resolveRequiredPlaceholders(location);
// 获取该文件的资源对象
Resource resource = this.resourceLoader.getResource(resolvedLocation);
// 添加
addPropertySource(factory.createPropertySource(name, new EncodedResource(resource, encoding)) {
// 使用工厂factory创建一个ResourcePropertySource对象
return (name != null ? new ResourcePropertySource(name, resource) {
// 使用工具类PropertiesLoaderUtils加载配置文件
super(name,PropertiesLoaderUtils.loadProperties(resource))
} : new ResourcePropertySource(resource));
}){
// 判断当前配置文件是否被加载过
// 一个配置文件对应这一个propertySource对象
if (this.propertySourceNames.isEmpty()) {
// 如果没有被加载,保存到环境的所有的资源列表中
propertySources.addLast(propertySource);
}
// 保存已经解析过的配置文件名称
this.propertySourceNames.add(name);
}
}
}
}
// 第三步: 解析@ComponentScan注解
Set<AnnotationAttributes> componentScans = AnnotationConfigUtils.attributesForRepeatable(sourceClass.getMetadata(), ComponentScans.class, ComponentScan.class);
// 存在componentScans注解,并且如果标注了@Condition注解且满足情况
if (!componentScans.isEmpty() && !this.conditionEvaluator.shouldSkip(sourceClass.getMetadata(), ConfigurationPhase.REGISTER_BEAN)) {
// 遍历所有的注解
for (AnnotationAttributes componentScan : componentScans) {
// 使用componentScanParser去解析这种类,详见ComponentScanParser解析@ComponentScan注解
// this.componentScanParser = new ComponentScanAnnotationParser(environment, resourceLoader, componentScanBeanNameGenerator, registry);
Set<BeanDefinitionHolder> scannedBeanDefinitions = this.componentScanParser.parse(componentScan, sourceClass.getMetadata().getClassName());
// 遍历所有扫描的Bean
for (BeanDefinitionHolder holder : scannedBeanDefinitions) {
// 获取原始的BD,因为可能当前BD设置了需要被代理
BeanDefinition bdCand = holder.getBeanDefinition().getOriginatingBeanDefinition();
// 如果bdCand没有,表示没有被代理,则直接获取BD
if (bdCand == null) {
bdCand = holder.getBeanDefinition();
}
// 如果它是一个配置类,上面有这个方法的解析
if (ConfigurationClassUtils.checkConfigurationClassCandidate(bdCand, this.metadataReaderFactory)) {
// 调用解析配置类ConfigurationClassParser进行配置类解析
// 这里又是递归
ConfigurationClassParser.parse(bdCand.getBeanClassName(), holder.getBeanName());
}
}
}
}
// 第四步: 处理@Import注解
processImports(configClass, sourceClass, getImports(sourceClass) {
// 所有需要导入的类
Set<SourceClass> imports = new LinkedHashSet<>();
// 已经被处理过的类,这个SourceClass可能是类,也可能是注解
Set<SourceClass> visited = new LinkedHashSet<>();
// 收集@Import的类
collectImports(sourceClass, imports, visited) {
// 保存当前正在处理的SourceClass,表示当前SourceClass被处理过
if (visited.add(sourceClass)) {
// 获取SourceClass的所有注解信息
for (SourceClass annotation : sourceClass.getAnnotations()) {
// 获取注解名
String annName = annotation.getMetadata().getClassName();
// 如果注解名不是@Import
if (!annName.equals(Import.class.getName())) {
// 递归收集注解中的嵌套注解信息
collectImports(annotation, imports, visited);
}
}
// 获取@Import注解中导入的类,如果不存在@Import注解,或者没有导入的类,则添加的是一个空集合
// 如果存在@Import注解,添加的则是导入的类
imports.addAll(sourceClass.getAnnotationAttributes(Import.class.getName(), "value"));
}
}
// 保存收集的@Import类
return imports;
},true){ // 不存在@Import注解
if (importCandidates.isEmpty()) {
return;
}
// 处理@Import循环导入问题
if (checkForCircularImports && isChainedImportOnStack(configClass)) {
this.problemReporter.error(new CircularImportProblem(configClass, this.importStack));
this.importStack.pop();
return;
}
// 将当前配置存入栈中,表示当前类正在导入
this.importStack.push(configClass);
// 遍历所有标注@Import的类
for (SourceClass candidate : importCandidates) {
// 第一种情况,如果当前类是实现了ImportSelector接口
if (candidate.isAssignable(ImportSelector.class)) {
// 加载当前类
Class<?> candidateClass = candidate.loadClass();
// 实例化当前类,并且执行生命周期中的Aware接口
ImportSelector selector = ParserStrategyUtils.instantiateClass(candidateClass, ImportSelector.class, this.environment, this.resourceLoader, this.registry);
// 如果ImportSelector是DeferredImportSelector这种类型,表示是延迟导入
if (selector instanceof DeferredImportSelector) {
this.deferredImportSelectorHandler.handle(configClass, (DeferredImportSelector) selector) {
// 使用延迟导入处理器处理
this.deferredImportSelectorHandler.handle(configClass, (DeferredImportSelector) selector) {
// 将当前配置类和importSelector封装到DeferredImportSelectorHolder中
DeferredImportSelectorHolder holder = new DeferredImportSelectorHolder(configClass, importSelector);
// deferredImportSelectors=new ArrayList();
// 正常情况下,deferredImportSelectors赋了默认值,不可能为空,只有到真正处理Import类的时候会将它置空
// 所以,这里都不会进,只会走else逻辑,先保存配置信息,暂时不解析
// 要与DeferredImportSelectorHandler.process对比了看就知道
if (this.deferredImportSelectors == null) {
// 创建一个延迟导入的分组处理器,用于分组导入
DeferredImportSelectorGroupingHandler handler = new DeferredImportSelectorGroupingHandler();
// 将导入的类保存到configurationClasses中,等待处理
handler.register(holder) {
// 获取导入的分组
Class<? extends Group> group = deferredImport.getImportSelector().getImportGroup();
// 保存到map中
DeferredImportSelectorGrouping grouping = this.groupings.computeIfAbsent((group != null ? group : deferredImport), key -> new DeferredImportSelectorGrouping(createGroup(group)));
// 将当前导入的类保存到当前分组中
grouping.add(deferredImport);
// 缓存需要解析的配置类信息
this.configurationClasses.put(deferredImport.getConfigurationClass().getMetadata(), deferredImport.getConfigurationClass());
}
// 真正处理延迟的Import的类
handler.processGroupImports() {
// 遍历所有的分组
for (DeferredImportSelectorGrouping grouping : this.groupings.values()) {
// 分组导入
grouping.getImports().forEach(entry -> {
ConfigurationClass configurationClass = this.configurationClasses.get(entry.getMetadata());
// 循环处理Import注解
processImports(configurationClass, asSourceClass(configurationClass), asSourceClasses(entry.getImportClassName()), false);
});
}
}
} else {
// 先保存需要延迟处理的类
this.deferredImportSelectors.add(holder);
}
}
}
} else {
// 其他类型的ImportSelector,直接回调Selector的selectImports方法,返回需要注册为Bean的类名
String[] importClassNames = selector.selectImports(currentSourceClass.getMetadata());
// 一一将类名封装成SourceClass
Collection<SourceClass> importSourceClasses = asSourceClasses(importClassNames);
// 递归处理@Import注解,可能@import导入的类又导入其他类
processImports(configClass, currentSourceClass, importSourceClasses, false);
}
}
// 如果是第二种情况,实现了ImportBeanDefinitionRegistrar接口
else if (candidate.isAssignable(ImportBeanDefinitionRegistrar.class)) {
// 加载当前类
Class<?> candidateClass = candidate.loadClass();
// 实例化当前类,并且执行生命周期中的Aware接口
ImportBeanDefinitionRegistrar registrar = ParserStrategyUtils.instantiateClass(candidateClass, ImportBeanDefinitionRegistrar.class, this.environment, this.resourceLoader, this.registry);
// 将registrar保存到configClass中
configClass.addImportBeanDefinitionRegistrar(registrar, currentSourceClass.getMetadata()) {
// 将导入的ImportBeanDefinitionRegistrar保存到ConfigClass的importBeanDefinitionRegistrars变量中
// 因为ImportBeanDefinitionRegistrar就是单纯的注入Bean,没有像@Import这样,可能还有其他导入注解的逻辑
this.importBeanDefinitionRegistrars.put(registrar, importingClassMetadata);
}
}
// 其他情况,导入一个普通类
else {
// 把它当做一个导入的@Configuration来处理,压入导入栈中
this.importStack.registerImport(currentSourceClass.getMetadata(), candidate.getMetadata().getClassName());
// 递归处理配置类逻辑
processConfigurationClass(candidate.asConfigClass(configClass));
}
}
// 处理完了导入的类需要出栈
this.importStack.pop();
}
}
// 第五步: 处理@ImportResource
AnnotationAttributes importResource = AnnotationConfigUtils.attributesFor(sourceClass.getMetadata(), ImportResource.class);
// 存在@ImportResource注解
if(importResource !=null){
// 获取导入的配置文件路径
String[] resources = importResource.getStringArray("locations");
// 获取指定的BeanDefinitionReader
Class<? extends BeanDefinitionReader> readerClass = importResource.getClass("reader");
// 遍历所有的xml文件路径
for (String resource : resources) {
// 解析占位符,和PropertySource类似
String resolvedResource = this.environment.resolveRequiredPlaceholders(resource);
// 保存到ConfigClass的importedResources变量中,记录了所有要导入的xml配置文件
configClass.addImportedResource(resolvedResource, readerClass);
}
}
// 第六步: 解析@Bean方法
Set<MethodMetadata> beanMethods = retrieveBeanMethodMetadata(sourceClass){
// 获取当前配置类的元数据
AnnotationMetadata original = sourceClass.getMetadata();
// 找类中所有的@Bean方法
Set<MethodMetadata> beanMethods = original.getAnnotatedMethods(Bean.class.getName());
//包含@Bean的方法有多个,这个时候需要处理一下@Bean方法的顺序
if (beanMethods.size() > 1 && original instanceof StandardAnnotationMetadata) {
// 获取元数据解析工厂
AnnotationMetadata asm = this.metadataReaderFactory.getMetadataReader(original.getClassName()).getAnnotationMetadata();
// 使用asm方式获取@Bean方法
Set<MethodMetadata> asmMethods = asm.getAnnotatedMethods(Bean.class.getName());
// 这样做的目的是asm的方法是按照声明顺序返回的,而直接获取的方法是随机顺序返回的
if (asmMethods.size() >= beanMethods.size()) {
// 最终排序好的BeanMethod
Set<MethodMetadata> selectedMethods = new LinkedHashSet<>(asmMethods.size());
// 遍历ASM找的Bean方法,因为它是按照声明顺序的
for (MethodMetadata asmMethod : asmMethods) {
// 遍历类中所有的BeanMethod,这个是无序的
for (MethodMetadata beanMethod : beanMethods) {
// 如果是同一个方法
if (beanMethod.getMethodName().equals(asmMethod.getMethodName())) {
// 则保存下来,这个使用selectedMethods中的方法就会按照asm中的顺序来保存了
selectedMethods.add(beanMethod);
break;
}
}
}
// 如果两种获取的方法数量是一致的,则将排好序的beanMethods返回
// 如果两个方法个数不一致,那么排序也排的没有用
if (selectedMethods.size() == beanMethods.size()) {
beanMethods = selectedMethods;
}
}
}
// 只有一个方法,就不需要排序,或者已经排序好的
return beanMethods;
}
// 遍历所有的方法
for (MethodMetadata methodMetadata : beanMethods) {
// 将方法封装成BeanMethod对象,保存到ConfigClass中
configClass.addBeanMethod(new BeanMethod(methodMetadata, configClass));
}
// 处理Bean中,实现的接口中的默认方法中含有的@Bean方法
// 注意: 接口中的默认方法存在@Bean,则实现类也会有这个,到时会出现相同BeanMethod
processInterfaces(configClass, sourceClass){
// 遍历当前配置类实现的所有接口
for (SourceClass ifc : sourceClass.getInterfaces()) {
// 解析接口中存在的@Bean注解
Set<MethodMetadata> beanMethods = retrieveBeanMethodMetadata(ifc);
// 遍历所有的方法
for (MethodMetadata methodMetadata : beanMethods) {
// 方法不能是抽象的
if (!methodMetadata.isAbstract()) {
// 将方法封装成BeanMethod对象,保存到ConfigClass中
configClass.addBeanMethod(new BeanMethod(methodMetadata, configClass));
}
}
// 递归解析接口中实现的接口
processInterfaces(configClass, ifc);
}
}
// 最后,解析当前配置类所有的父类
if(sourceClass.getMetadata().hasSuperClass()){
// 获取父类名称
String superclass = sourceClass.getMetadata().getSuperClassName();
// 如果存在父类,并且父类不是java的,同时这个父类没有被处理
if (superclass != null && !superclass.startsWith("java") && !this.knownSuperclasses.containsKey(superclass)) {
// 保存该父类
this.knownSuperclasses.put(superclass, configClass);
// 获取父类进行下一次解析
return sourceClass.getSuperClass();
}
}
// 没有父类 -> 处理完成
return null;
}
Spring中ConfigClass配置类是如何解析的
于 2024-03-11 03:40:34 首次发布
![](https://img-home.csdnimg.cn/images/20240711042549.png)