spring整套源码系列之【bean后置处理器解析配置源码】
2024-04-10 18:45:15 0 举报
spring整套源码系列之【bean后置处理器解析配置源码】
作者其他创作
大纲/内容
/处理我们的@propertySource注解
获取到bean定义对象
处理配置类的父类的
普通类或者ConfigurationClass
处理配置类接口的
第一步:首先调用BeanDefinitionRegistryPostProcessor的后置处理器
循环我们传递进来的beanFactoryPostProcessors
//把我们解析出来的组件bean定义注册到我们的IOC容器中的bean定义Map中
this方法里创建了reader,并且这个this就是个BeanDefinitionRegister
//调用没有实现任何优先级接口的BeanDefinitionRegistryPostProcessor
return scanCandidateComponents(basePackage);
第一步:首先调用BeanDefinitionRegistryPostProcessor的后置处理器简化流程
创建我们通过@CompentScan、@Import导入进来的bean name的生成器实例registry.getSingleton(CONFIGURATION_BEAN_NAME_GENERATOR);
执行context.addBeanFactoryPostProcessor(xxx)BeanDefinitionRegistryPostProcessor后置处理器【postProcessBeanDefinitionRegistry(registry);】
很重要的一个方法,只要你用spring都会跑这个方法去,可以说学习spring源码就是学这个方法
for (SourceClass candidate : importCandidates)
执行后置处理器(PriorityOrdered)
ConfigurationClassPostProcessor
这里给配置类创建了动态代理对象,代码挺深的,关于动态代理的,可以先不用抠细节
beanDefinitionMap
是不是候选的组件isCandidateComponent(metadataReader)
//注册一些配置的后置处理器\t\tAnnotationConfigUtils.registerAnnotationConfigProcessors(this.registry);
执行后置处理器(Ordered)
第二步:调用BeanFactoryPostProcessor后置处理器
beanFactory.addBeanPostProcessor(new ImportAwareBeanPostProcessor(beanFactory));
执行没有实现优先级的后置处理器
加了
(2)
这些后置处理器都非常重要!在我们Bean的创建过程中起着至关重要的作用, 属于开Bean元勋.
(1)
再次当成配置类解析,如果不是配置类当成普通类解析完成processConfigurationClass(candidate.asConfigClass(configClass));
我们的配置类中包含很多的注解,需要一个一个解析,比如@ComponentScan扫描包注解
(3)
//需要合并配置\t\t\t\t\texistingClass.mergeImportedBy(configClass);
//处理jsr250相关的组件
一系列的后置处理器跟事件
添加配置类到一个集合中Set<ConfigurationClass> importedBy#.addAll(otherConfigClass.importedBy)
includeFilters:需要扫描excludeFilters 不需要扫描
是
处理 @Import注解
do while循环
//注册我们的配置类 register(annotatedClasses);
//设置我们的beanName
//解析我们的 @ComponentScan 注解
这里解析,解析途中调用
判断了是否抽象类、接口等isCandidateComponent(AnnotatedBeanDefinition beanDefinition)
//定义一个集合用户保存当前准备创建的BeanDefinitionRegistryPostProcessor\t\t\tList<BeanDefinitionRegistryPostProcessor> currentRegistryProcessors = new ArrayList<>();
配置类MainConfig.class)
else
先执行实现了PriorityOrdered接口的后置处理器
这里才会注册成bean定义
防止又是一个配置类所以调用一样的方法
执行后置处理器
循环解析我们的配置类
for循环处理class成bean定义
return
这个才是我们解析配置类的解析器
for循环
如果传入进来的配置类是通过其他配置类的Import导入进来的
执行后置处理器方法postProcessor.postProcessBeanDefinitionRegistry(registry);
代表方法里面
返回
//调用selector的selectImports\t\t\t\t\t\t\tString[] importClassNames = selector.selectImports(currentSourceClass.getMetadata());
简化
includeFilters 是否需要进行包含的
再执行实现了Ordered接口的后置处理器
放入集合
//调用他作为BeanDefinitionRegistryPostProcessor的处理器的后置方法 registryProcessor.postProcessBeanDefinitionRegistry(registry);
全部放入集合中后
new AnnotationConfigApplicationContext(MainConfig.class)入口,通过配置类方式获取applicationContext上下文
循环解析 我们解析出来的AnnotationAttributes
//使用cglib对配置类进行代理,因为@Bean方法到时候要进行创建Bean的实例\t\tenhanceConfigurationClasses(beanFactory);
判断该组件是不是实现了ImportSelector的candidate.isAssignable(ImportSelector.class
//找到候选的CompentsfindCandidateComponents(basePackage);
执行后置处理器方法postProcessor.postProcessBeanFactory(beanFactory);
首先会调用父类GenericApplicationContext的无参构造函数
处理 @ImportResource 注解
beanFactory.clearMetadataCache();
前面spring-ioc加载流程中已经整个流程分析了ioc的加载过程,整个spring的源码整体就是那么一整块,然后里面的关键细节没有去深入研究。前面也说过spring扫描以及创建bean定义都是通过bean工厂的后置处理器来的,这里就分析spring怎么通过bean的后置处理器对我们的配置类处理源码过程
递归处理
通过excludeFilters 进行是否需要排除的
put
//真正的解析我们的配置类\t\t\tparser.parse(candidates);
判断我们导入的组件是不是ImportBeanDefinitionRegistrarcandidate.isAssignable(ImportBeanDefinitionRegistrar.class)
/判断是否有没有解析过
没加
有没有动态代理主要在有没有@Configuration注解的区别
// 调用我们的bean工厂的后置处理器. invokeBeanFactoryPostProcessors(beanFactory);
第三步:清除缓存的合并bean定义,因为后处理程序可能有修改原始元数据,例如替换值中的占位符…
对我们的配置类进行Order排序configCandidates.sort(...)
判断是否加了@Configuration注解
执行bean定义Map中的BeanDefinitionRegistryPostProcessor后置处理器【postProcessBeanDefinitionRegistry(registry);】(PriorityOrdered)
在这个类中,会解析加了@Configuration的配置类,还会解析@ComponentScan、@ComponentScans注解扫描的包,以及解析@Import等注解。
//真正的解析我们的bean定义\t\tprocessConfigBeanDefinitions(registry);
处理 @Bean methods 获取到我们配置类中所有标注了@Bean的方法
执行bean定义Map中的BeanDefinitionRegistryPostProcessor后置处理器【postProcessBeanDefinitionRegistry(registry);】(没有实现优先级接口)
do while循环解析配置类
没有
循环我们的包路径集合
此时我们bean定义Map
创建一个配置类解析器对象parser = new ConfigurationClassParser(...)
递归处理configuration类及其超类层次结构。
//反之SelectImport 导入进来的又是Import, 所以递归解析 Collection<SourceClass> importSourceClasses = asSourceClasses(importClassNames);
代表说明
执行bean定义Map同时实现了BeanFactoryPostProcessor的方法【postProcessBeanFactory(beanFactory);】
bean定义
//IOC容器刷新接口,特别重要的一个方法 refresh();
//真正的进行扫描解析return scanner.doScan(StringUtils.toStringArray(basePackages));
会找到并设置CompentScan对象的includeFilters、excludeFilters 属性跟包路径属性等
在这里典型的BeanDefinitionRegistryPostProcessor就是ConfigurationClassPostProcessor 用于进行bean定义的加载 比如我们的包扫描,@import 等
关注
可以看到是一个bean工厂后置处理器、bean定义注册器后置处理器
执行bean定义Map中的BeanDefinitionRegistryPostProcessor后置处理器【postProcessBeanDefinitionRegistry(registry);】(Ordered)
//调用构造函数this();AnnotationConfigApplicationContext()构造函数
调用完我们add的bean定义注册器后置处理器后
getBeanFactoryPostProcessors()
入口
构造方法里
代表同一个方法里
注册bean定义
这里使用了三个List分别放:PriorityOrdered、Ordered、没有实现任何的优先级接口的
如果配置解析没完成while (sourceClass != null);
会调用bean工厂后置处理器
解析我们的配置类
注册
如果实现了ImportSelector类,会把重写的方法返回的string[](类的全路径限名)全部注册成bean
这里有判断了接口是不能被扫描的,所以mybatis就是重写了这个方法做到@Mapper
所以说如果我们的bean是一个配置类(比如带有@Bean等不管有没有带@Configuration)都会去处理的
打印消息说已经解析过
第二个参数getBeanFactoryPostProcessors()为我们context.addBeanFactoryPostProcessor(xxx);这种形式加入的bean工厂后置处理器,我们这里没有加入所以为空
执行context.addBeanFactoryPostProcessor(xxx)实现了BeanFactoryPostProcessor的方法【postProcessBeanFactory(beanFactory);】
else if
包装成为一个ScannedGenericBeanDefinition
注册了bean工厂后置处理器ConfigurationClassPostProcessor
注册了处理@Autowired 注解的处理器AutowiredAnnotationBeanPostProcessor
//真正的把我们解析出来的配置类注册到容器中\t\t\tthis.reader.loadBeanDefinitions(configClasses);
是否懒加载这些基本的bean定义属性
这个方法也复杂,先不看
/获取IOC 容器中目前所有bean定义的名称registry.getBeanDefinitionNames();然后获取到bean定义对象
把资源路径变成我们需要解析的路径下的所有class路径
//存在没有解析过的 需要循环解析\t\twhile (!candidates.isEmpty());
因为我们配置类中可能还有配置类,所以不只是我们一开始传入的配置类
后面会根据这个集合处理配置类,所以说我们手动添加的配置类优先执行
//处理@AutoWired相关的
创建了读取配置类的对象用来读取配置AnnotatedBeanDefinitionReader(this);
这里是通过一个标记“full”,在postProcessBeanDefinitionRegistry(registry)会将带了注解的标记打上
这里如果没有找到配置类在下面会直接返回false结束方法
0 条评论
下一页