Spring IOC 扫描注册BeanDefinition
2024-04-13 16:23:46 0 举报
登录查看完整内容
Spring IOC 扫描注册BeanDefinition是一种核心机制,用于自动发现和注册Spring应用程序上下文中的Bean。该机制通过扫描特定的包及其子包,查找Spring Bean并自动将其注册到Spring应用程序上下文中。扫描过程基于给定的文件类型和修饰语(如@Component、@Service、@Repository等)进行。扫描到的BeanDefinition将包含Bean的全限定类名、构造函数参数、属性和初始化方法等信息,为Spring IOC容器提供详细的Bean元数据。这种自动化的Bean发现和注册机制大大简化了Spring应用程序的配置和开发过程。
作者其他创作
大纲/内容
font color=\"#ffffff\
$B
ConfigurationPhase#PARSE_CONFIGURATION
@Import注解是spring中很重要的一个注解,Springboot大量应用这个注解@Import三种类,一种是Import普通类,一种是Import ImportSelector,还有一种是Import ImportBeanDefinitionRegistrar
再次判断这个类是否符合条件(不是内部类并且是一个具体类)具体类:不是接口也不是抽象类,如果是抽象类则需要带有@Lookup注解
ConfigurationClassBeanDefinitionReader.java
扫描classPath下标注了@Service、@Component、@Respository、@Controller
实现了延时ImportSelector先实例化,再缓存到集合在自动装配时处理this.deferredImportSelectors.add()在解析完配置类(parse方法之后延时调用)后this.deferredImportSelectorHandler.process()延时处理
configClass.isImported()是否从@Import导入的
递归处理;直到处理Import类型为普通配置类
#isCandidateComponent(metadataReader)根据所有的过滤器判断这个类是否符合条件includeFilters(例如必须标注@Component注解或其派生注解)在isCandidateComponent方法内部会真正执行匹配规则注册配置类已经添加到excludeFilters所以自身会被排除,不会进入到这个if
此方法可以理解为执行ConfigurationClassPostProcessor的postProcessBeanDefinitionRegistry()方法用于进行bean定义的加载 比如我们的包扫描,@Component @import @Bean等等。。。。。。。。。调用此方法就完成了扫描@Component的Bean的操作Spring热插播的体现,像ConfigurationClassPostProcessor就相当于一个组件,Spring很多事情就是交给组件去管理
普通ImportSelector先实例化selector.selectImports()调用方法返回当前类所有Import类字符串数组asSourceClasses反射为Class数组(递归处理(被import的类也有可能被@Import注解修饰))
String[] postProcessorNames =beanFactory.getBeanNamesForType(font color=\"#ffeb3b\
Loop
解析 @ComponentScan 注解
#processConfigurationClass(font color=\"#ff9800\
getBeanFactoryPostProcessors()我们自己调用addBeanFactoryPostProcessor的自定义BeanFactoryPostProcessor * spring允许我们手动添加BeanFactoryPostProcessor * 即:annotationConfigApplicationContext.addBeanFactoryPostProcessor(XXX);
遍历扫描返回candidates候选的BeanDefinition
DeferredimportSelectorGroupinggetImports()
创建扫描器会初始化将@Component添加到includeFilters
selector instanceof DeferredImportSelector是否实现DeferredImportSelector
deferredImports.sort(DEFERRED_IMPORT_COMPARATOR)排序处理
判断当前BeanDefinition是否已经注册过this.beanDefinitionMap.get(beanName) != null
Process()
如果符合条件,则创建一个ScannedGenericBeanDefinition对象ScannedGenericBeanDefinition sbd = new ScannedGenericBeanDefinition(metadataReader);
统一执行BeanDefinitionRegistryPostProcessor父类BeanFactoryPostProcessor#postProcessBeanFactory
创建配置类解析器:解析@ComponentScan、@Import、@Bean、@ImportResource
DeferredImportSelector.getImportGroup()
遍历basePackages包路径
ImportBeanDefinitionRegistrar
创建扫描器:1、会将@Component添加到includeFilters
configClass.getBeanMethods()遍历配置类下所有添加@Bean注解方法;这些方法在`$B`处解析
ConfigurationClassParser.java
调用ComponentScanAnnotationParser #parse解析配置类返回扫描出来的Bean定义集合Set<BeanDefinitionHolder> scannedBeanDefinitions
调用实现了 PriorityOrdered 的BeanDefinitionRegistryPostProcessor接口#invokeBeanDefinitionRegistryPostProcessors
2
@Bean和@Import的BeanDefinition在此注册configurationClasses集合在`$A`处进行put
开始执行扫描class文件操作
ConfigurationPhase#REGISTER_BEAN
获得了带有@Bean的方法后,不是马上转换成BeanDefinition,而是先用一个set接收
#parse创建包路径扫描器scanner = new ClassPathBeanDefinitionScanner()
#B
#scanCandidateComponents(String basePackage)获取包下面所有的.class文件Resource[] resources = getResourcePatternResolver().getResources(classpath*:com/xx/**/*.class);
调用实现了BeanDefinitionRegistryPostProcessor接口的Bean工厂后置处理器
否
内容:refresh.invokeBeanFactoryPostProcess主要作用解析配置类;1. 会在此解析@Configuration将添加了@Component的class扫描成beanDefinition2.bean工厂的后置处理器调用(实例化并调用前面注册的ConfigurationClassPostProcessor Bean工厂后置处理器)
默认情况下: * 此时beanFactory的beanDefinitionMap中有6个BeanDefinition,5个基础BeanDefinition+AppConfig的BeanDefinition * 而这6个中只有一个BeanFactoryPostProcessor:ConfigurationClassPostProcessor * 这里会执行ConfigurationClassPostProcessor进行@Component的扫描,扫描得到BeanDefinition,并注册到beanFactory中 * 注意:扫描的过程中可能又会扫描出其他的BeanFactoryPostProcessor,那么这些BeanFactoryPostProcessor也是在这一步执行
postProcessor就一个:ConfigurationClassPostProcessor
font color=\"#388e3c\
AutoConfigurationGroup implements Group
$A
else if
@Bean:beanMethodsloadBeanDefinitionsForBeanMethod(beanMethod);注册BeanDefinition
解析@ImportResource注解
ConfigurationClassPostProcessor#postProcessBeanDefinitionRegistry这里真正开始解析带@Configuration注解的配置类和解析带@ComponentScan注解扫描包,解析@Component、@Import、@Bean
扫描包
@ImportResourcesloadBeanDefinitionsFromImportedResources(configClass.getImportedResources())注册BeanDefinition
@import:importedByregisterBeanDefinitionForImportedConfigurationClass(configClass)注册BeanDefinition
在执行完上面的扫描之后,一般BeanDefinition肯定是增加了的如果发现BeanDefinition增加了,则有可能增加了配置类;如果存在配置类(不在当前配置类扫描包下),则判断是否解析过,如果没有解析
获取当前配置类下所有@Bean方法retrieveBeanMethodMetadata(sourceClass)
Import普通配置类(ConfigClass)
从我们的配置类上解析@ComponentScans的对象集合属性@ComponentScan注解除了最常用的basePackage之外,还有includeFilters,excludeFilters等
设置BeanDefinition默认值和一系列解析(Scope、lazy、DependsOn等)
#processImports(getImports(sourceClass))
#E
#D
调用asConfigClass(ConfigurationClass importedBy)组装一个新的ConfigurationClass;使用importBy属性标记是从哪个配置类@Import进来的;最终通过this.reader.loadBeanDefinitions(configClasses)实现注册
#C
调用实现了BeanFactoryPostProcessor接口的Bean工厂后置处理器
div style=\
groups
font color=\"#f44336\
循环从所有BeanDefinition拿到配置类并且标记CONFIGURATION_CLASS_ATTRIBUTE属性,标记过的BeanDefinition表示已经解析过:1:full完整配置类 @Configuration 会创建Cglib代理2:lite精简版配置类:@Component、@ComponentScan、@ImportResource、@Bean
SpringBoot自动装配AutoconfigurationImportSelector implements DeferredimportSelector
getImports(sourceClass)是递归获得当前配置类@import注解导入的类,返回的是一个set集合importCandidates
解析@Bean注解
return null?
refresh()
createGroup(group).DefaultDeferredImportSelectorGroup
String[] candidateNames = registry.getBeanDefinitionNames()BeanDefinition bd = this.beanDefinitionMap.get(beanName)取出所有BeanDefinition遍历判断判断是否为配置类(标注@Configuration)span style=\"font-size:inherit;\
#process()
#F
#this.reader.loadBeanDefinitions(configurationClasses);
candidates.add()继续遍历解析
#processImports
1
ClassPathBeanDefinitionScanner.java#doScan(String... basePackages)开始扫描解析
this.reader.loadBeanDefinitions(configClasses);
排序
解析@CpmPonentScan注解信息:1、解析ScopedProxyMode属性, 该属性可以将Bean创建成jdk代理或cglib代理2、处理CompentScan对象的includeFilters 和 excludeFilters 包含的属性3、CompentScan是否添加了lazyInit属性(延迟加载所有类)4、把 配置类(declaringClass就是注册类)自身当作排除规则,真正执行匹配的时候,addExcludeFilter(typeFilter)
ComponentScanAnnotationParser.java
解析@Import注解
自动装配未完待续...
ClassPathScanningCandidateComponentProvider.java
@import:ImportBeanDefinitionRegistrarloadBeanDefinitionsFromRegistrars(configClass.getImportBeanDefinitionRegistrars())注册BeanDefinition
ImportSelector
调用实现了Ordered接口的BeanFactoryPostProcessor
AbstractApplicationContext.java#invokeBeanFactoryPostProcessors(beanFactory)
遍历resources扫描出来的资源文件
#invokeBeanFactoryPostProcessors
判断当前配置类是否添加了@ComponentScan注解,或者被@Condition条件跳过,就不再进行解析
调用addBeanFactoryPostProcessor的自定义BeanFactoryPostProcessor#postProcessBeanFactory
configurationClasses遍历所有的配置类
do
font color=\"#7b1fa2\
用于导入 Spring 的 xml 配置文件,让该配置文件中定义的 bean 对象加载到Spring容器中
调用自定义实现Ordered接口和实现了BeanDefinitionRegistryPostProcessor#invokeBeanDefinitionRegistryPostProcessors
遍历componentScans
#G
PostProcessorRegistrationDelegate.java
遍历scannedBeanDefinitions循环处理我们包扫描出来的beanDefinition
符合条件,则添加至`candidates`集合candidates.add(sbd)并返回
ConfigurationClassParser #parse(candidates)
调用其他BeanFactoryPostProcessor
递归调用
调用实现了PriorityOrdered接口的BeanFactoryPostProcessor
ConfigurationClassParser.java内部类DeferredImportSelectorHandler.java
对于实现ImportBeanDefinitionRegistrar的导入:1、单独进行实例化:他不会通过getBean()实例化,也就是说ImportBeanDefinitionRegistrar不是个Bean2、然后加入(ConfigurationClass.java)font color=\"#7b1fa2\
通过getAutoConfigurationEntry()方法获取所有自动装配的类循环处理所有自动配置类
解析@Conditional注解,是否需要跳过解析
解析配置类
!candidates.isEmpty()
根据包名找到符合条件的BeanDefinition集合(扫描com.xx=>classpath*:com/xx/**/*.class类信息)#findCandidateComponents(basePackage)
注册Bean定义此处才把@Bean的方法和@Import 注册到BeanDefinitionMap中
调用自定义其他BeanDefinitionRegistryPostProcessor#invokeBeanDefinitionRegistryPostProcessors
递归调用ConfigurationClassParser font color=\"#1b5e20\
处理我们延时的DeferredImportSelectors ;springboot就是通过这步进行加载spring.factories文件中的自定装配的对象DeferredImportSelectorHandler #process()
ConfigurationClassPostProcessor.java#processConfigBeanDefinitions(BeanDefinitionRegistry registry)
遍历importCandidates
处理我们的@propertySource注解解析加载properties文件,并将属性添加到Spring上下文中
ConfigurationClassPostProcess.postProcessBeanFactory方法在此调用;主要是对@Configuration做代理增强
是
收藏
0 条评论
回复 删除
下一页