Spring IOC源码解析
2021-06-19 14:26:17 55 举报
Spring Ioc解析配置类源码分析
作者其他创作
大纲/内容
添加不包含过滤(当前配置类名)
refresh();
postProcessor.postProcessBeanDefinitionRegistry(registry);
调用到目前为止处理的所有处理器的postProcessBeanFactory回调
@Bean和@Import类型,是在这里才注册bean定义的parse()方法中只是解析
ComponentScanAnnotationParser.parse(...)
②
First,调用实现了 PriorityOrdered接口的BeanDefinitionRegistryPostProcessor类型的处理器(集合)
if (beanFactory instanceof BeanDefinitionRegistry)DefaultListableBeanFactory 实现了当前bean定义注册接口,所以走if 逻辑
registerBeanDefinition(span style=\"font-size: inherit;\
for (SourceClass candidate : importCandidates)
ImportBeanDefinitionRegistrar类型
解析 default方法(接口) 忽略
解析 @ComponentScan注解
Reader的构造器方法,注册默认处理器this.registry 指的是 ACAC对象
遍历 item
parse(Set<BeanDefinitionHolder> configCandidates)
ImportSelector类型
调用上下文中bean工厂后置处理器
registerBean(annotatedClass)
scanner.doScan(StringUtils.toStringArray(basePackages))
解析 @Import注解
未跳过,真正执行 注解配置解析
this();
ConfigurationClassParser parser = new ConfigurationClassParser( ... )
接下来,当前类的空参构造
上述方法获取来源类数据 Collection importCandidates
导入: if (configClass.isImported())
遍历 candidates1、生成beanName2、检验(是否注册过 - 类型、来源、相等性) 3、构建持有器,执行注册
创建扫描器,根据参数 useDefaultFilters决定是否添加默认过滤器(@Component 等)接下来,以配置源属性数据进行赋值
@ComponentScan 的basePackages是字符串数组类型接下来就是解析每个包扫描路径(匹配过滤器)
针对上述方法返回的 bean定义持有器集合,遍历,解析原因:假设上述集合中存在一个@Configuration配置类,代码进行到这里时,仅仅说明当前配置类已经完成了注册,但是不代表它内部的@Bean方法和 import注解也进行了解析
同上注意:当前处理的是 上述Next处理中重写方法中注册的当前类型对象(泛指A对象) 及 A对象中注册的当前类型对象(递归)或 代码中显式注入的实例对象(未实现 Ordered接口)及 其重写方法中注册的当前类型对象(递归)
注册默认过滤器
遍历注册表中所有的bean定义对象,筛选出 的自定义配置类,并加入到候选解析集合如果,候选解析集合不为空,创建解析器
委托调用
public AnnotationConfigApplicationContext(){ this.reader = ? this.scanner = ?}
ConfigurationClassParser
this.reader.loadBeanDefinitions(configClasses)
遍历set集合,根据bean定义类型执行解析这里分析 AnnotatedBeanDefinition类型的,因为步骤②加载配置源时,创建的就是当前类型的bean定义对象
else
ConfigurationClassBeanDefinitionReader.loadBeanDefinitions(Set<ConfigurationClass> configurationModel)
校验
解析注解信息(递归父注解)getImports(sourceClass)
configurationClasses属性实际上是 LinkedHashMap结构,put方法调用的是其父类 HashMap的。ConfigurationClass重写了hashCode和equals方法(依据 getMetadata().getClassName() 配置源类名)如果 existingClass不为空,说明之前已经加载过了 。那么接下来就是判断 existingClass 和待解析配置源configClass的类型了(是否被导入① 或 bean定义查找② )处理优先级:② > ①如果 configClass是②类型,则删除existingClass(无论是否②类型),执行后续解析;如果 existingClass是①类型,合并configClass的导入源(外部类) ,再返回,否则不做任何处理直接返回;当然,如果 existingClass为空,执行解析。
@OverridepostProcessBeanDefinitionRegistry(BeanDefinitionRegistry)
①
如果当前配置类被@Component所注解,则递归地处理(嵌套的)内部类
beanFactory.getBeanNamesForType(span style=\"font-size: inherit;\
重点:ConfigurationClassPostProcessor
循环解析每个配置源
有一点需要说明,真正在扫描配置类时使用的ClassPathBeanDefinitionScanner 都是新创建的,并不会使用在创建applicationContext时内置的scanner。那么这个scanner是怎么使用的呢?(编程式扫描)AnnotationConfigApplicationContext ctx = new ...();ctx.refresh();ctx.scan(\"com.tuling.springtest.ioc.beanFactoryPostProcessor\");ctx.getBean(TulingLog.class);
invokeBeanFactoryPostProcessors(beanFactory);
③
processConfigurationClass(ConfigurationClass configClass)
loadBeanDefinitionsForBeanMethod(beanMethod)
解析 @ImportResource注解 忽略
添加
1、注册bean定义
上述方法的第二个参数是BeanFactoryPostProcessor类型的集合,循环执行如果当前后置处理器是 BeanDefinitionRegistryPostProcessor类型的,调用其注册方法,并添加到 registryProcessors集合如果不是,直接添加到 regularPostProcessors集合
递归处理
@Bean: 遍历 configClass.getBeanMethods()附:注册别名
执行解析
遍历,判断类型
this.reader = new AnnotatedBeanDefinitionReader(this);
register(annotatedClasses)
Set<MethodMetadata> beanMethods = retrieveBeanMethodMetadata(sourceClass)
遍历 ConfigurationClass 注册类本身及其所有@bean方法的bean定义
@Import中的 ImportBeanDefinitionRegistrar类型
loadBeanDefinitionsFromImportedResources(configClass.getImportedResources())
do... 真正干事的
this.reader.register(annotatedClasses);
最后
loadBeanDefinitionsForConfigurationClass( ... )
根据@Conditional 注释判断一个项目是否应该被跳过
检索所有@Bean方法的元数据
AnnotationConfigUtils.registerAnnotationConfigProcessors(this.registry)
processConfigBeanDefinitions(registry)
if (useDefaultFilters) { registerDefaultFilters();}
this.beanFactory = new DefaultListableBeanFactory();
this.conditionEvaluator.shouldSkip(...)
registerBeanDefinitionForImportedConfigurationClass(configClass)
Set<BeanDefinition> candidates = findCandidateComponents(basePackage)
首先,调用父类GenericApplicationContext 空参构造
return null;
解析 @PropertySource注解 忽略
loadBeanDefinitionsFromRegistrars(configClass.getImportBeanDefinitionRegistrars())
包含 ConfigurationClassPostProcessor 在内的多个创世纪的处理器的Bean定义将它们注册到 beanDefinitionMap中,并收集其beanName放入 beanDefinitionNames中
@ImportResource 忽略
ClassPathBeanDefinitionScanner scanner = new ClassPathBeanDefinitionScanner(...)
从 beanFactory中筛选出 BeanDefinitionRegistryPostProcessor类型的 beanName集合注意:虽然beanFactory中记录了多个bean定义(步骤①中 初始化reader 和 注册自定义配置类),但是首次筛选时,符合类型条件的只有 ConfigurationClassPostProcessor
解析 @Bean注解
过滤
创建配置类的Bean定义对象,再以此生成 beanName,最后封装成一个bean定义的持有器
processImports( ... )
processConfigurationClass(candidate.asConfigClass(configClass))
parser.parse(candidates)
解析 超类(return) 忽略
默认会注册三个过滤器,其中重要是 Component类型
解析注册的bean定义是否被 @Configuration 或 @Component 标注了
加载自定义配置至注册表
configClass.addImportBeanDefinitionRegistrar(...)
遍历集合
ConfigurationClass existingClass = this.configurationClasses.get(configClass)
public static void main(String[] args) { // AnnotationConfigApplicationContext new ACAC(MainConfig.class);}
this.includeFilters.add(new AnnotationTypeFilter(Component.class));
this.scanner = new ClassPathBeanDefinitionScanner(this);
2、注册别名 aliasMap
0 条评论
下一页