spring配置类
2022-01-26 10:31:36 0 举报
AI智能生成
spring配置类,classconfigurationpostprocessor
作者其他创作
大纲/内容
spring配置类的解析与注册是通过一个bean工厂的后置处理器ConfigurationClassPostProcessor实现的,以容器refresh之前注册的配置类为起点开始解析
什么条件的bean会认为是配置类:加了@Configuration、@Component、@ComponentScan、带@Import注解以及@Import导入的类和importselector返回的普通类、@ImportResource或者带@Bean方法的,满足其中一个条件就是配置类,Configuration.proxyBeanMethods=true的是full配置类,否则是lite配置类
org.springframework.context.annotation.ConfigurationClassParser#parse
将每个配置类的beanDefinition封装成ConfigurationClass后,调用processConfigurationClass处理
ConfigurationClassParser.processConfigurationClass
处理配置类,并加到ConfigurationClassParser.configurationClasses中,以便后续使用ConfigurationClassBeanDefinitionReader.loadBeanDefinitions加载beandefinition
ConfigurationClassParser.doProcessConfigurationClass
处理@Component
对于这种配置类,如果它的嵌套类(内部类和静态内部类)是配置类,则把嵌套类作为配置类来解析
嵌套类和@Import之间会检查循环导入问题,通过一个栈结构的ArrayDeque来解决,处理每个配置类前先判断当前类是否已经在栈中,如果已经在了则报CircularImport的异常,如果不在栈中再入栈,处理完成后出栈
嵌套的配置类相当于是外部类导入的,beanName的生成方式相同,都是类全限定名,比如org.example.configclass.AppConfig$InnerPrivateClass
处理配置类上的PropertySource:可以为properties,yml,xml,生成PropertySource对象加到environment
处理@ComponentScan
创建一个ClassPathBeanDefinitionScanner来处理,设置includeFilters、excludeFilters、lazyInit,最终以哪些包为基础包:直接指定的ComponentScan.basePackages, basePackageClasses指定的类所在的包,如果basePackages, basePackageClasses为空,才会以@ComponentScan标注的类所在的包为基础包
扫描得到beandefintiion后,再设置full配置类和lite配置类,解析其中的配置类,默认都是@Component的,会处理内部类,@ComponentScan扫出来的默认都是配置类
processImports
@Import可以用在其他注解上,比如@EnableXX
@Import导入的类分几种情况
ImportSelector
先实例化ImportSelector: 多个构造器默认使用无参的,如果只有一个有参构造器,会尝试进行依赖注入,注意这里只能注入Environment、ResourceLoader、BeanFactory、ClassLoader类型的,其他引用类型会注入空值,基本类型会注入零值,因为这时容器还未开始创建非懒加载单例bean
调用Aware接口的方法,同样也只能是上面4种类型
调用selectImports方法,入参是@Import所标注的类的注解元数据,方法内可以根据它获取注解指定的属性
对selectImports的返回值继续当成导入@Import导入的类来处理,也就是调用processImports处理
selectImports返回的类相当于是@Import导入的类,如果是普通类它就是配置类,不管是否加了注解
DeferredImportSelector
是延迟的ImportSelector,不是延迟到所有配置类处理完毕,而是导入它的配置类这一批的最后再处理,因此会覆盖同一批bean的声明
getImportGroup返回null时,用法和ImportSelector一样,实现selectImports即可;否则使用getImportGroup.selectImports返回的Entry.getImportClassName,Group相当于是ImportSelector
group的实现类只能是无参构造器,或者参数Environment、ResourceLoader、BeanFactory、ClassLoader类型的,因此不能是内部类(默认第一个参数类型是外部类)
ImportBeanDefinitionRegistrar
和ImportSelector一样,也是先实例化,多个构造器默认使用无参的,如果只有一个有参构造器,会尝试进行依赖注入,注意这里只能注入Environment、ResourceLoader、BeanFactory、ClassLoader类型的
实例化后先不调用,而是先加入ConfigurationClass.importBeanDefinitionRegistrars属性,同时加入的还有@Import标注的配置类的注解元数据
ImportSelector和ImportBeanDefinitionRegistrar实现类本身不会注册成一个bean,而是实例化后调用它们的方法,向容器添加其他beandefinition
其他
封装成ConfigurationClass,并把导入它的配置类加到importedBy属性
调用processConfigurationClass当成配置类处理,不管是否加了注解
Import进来的配置类,beanName就是beanClass,是全限定名,比如org.example.configclass.Car
处理@ImportResource
获取ImportResource.locations,加入ConfigurationClass.importedResources,处理完所有配置类后再处理
处理@Bean
获取当前配置类所有@Bean方法,以及实现的接口和父接口中@Bean标注的默认方法,封装成BeanMethod加进ConfigurationClass.beanMethods
处理父类
轮询父类,把父类也当成配置类调用doProcessConfigurationClass来处理,但不会生成父类beandefinition其实也不应该生成,应该生成的是子类)
对于@Component,只要子类加了,父类就会处理它的内部类
对于@Import,导入的类的importedBy属性是子类而不是父类,即认为是子类导入的;ImportSelector.selectImports和ImportBeanDefinitionRegistrar入参是父类的注解元数据,而DeferredImportSelector.selectImports入参是子类的注解元数据
几种配置类声明方式的区别
@ComponentScan在扫描时就生成了beandefinition,而其他几种直到所有配置类都处理完毕,再在ConfigurationClassPostProcessor.processConfigBeanDefinitions用ConfigurationClassBeanDefinitionReader读取beandefinition
本身的bedefinition在扫描时就生成了,但还是会把他当成配置类处理并且加到configurationClasses, 因为@Component类可能会通过内部类,@Bean,@Import,父类等方式引入其他bean
ConfigurationClassBeanDefinitionReader.loadBeanDefinitions
加载除@ComponentScan之外的beandefinition,包括导入的配置类(内部类和@Import普通类,ImportSelector)、@bean方法、@Import(ImportBeanDefinitionRegistrar)
生成beandefinition并且注册进bean工厂(beandefinitionmap和beanDefinitionNames)
导入的配置类:生成的beandefinition的beanName是类全限定名,设置@Lazy、@DependsOn、@Role、@Primary
@Bean
name属性可以指定多个值,第一个值作为beanName,其它的是别名,否则是方法名
如果方法是静态的,beandefinition设置beanclass为配置类和factorymethodname,否则设置factoryBeanName和factorymethodname
@Bean方法上也可以用@Lazy、@DependsOn、@Role、@Primary
还可以设置autowireCandidate、initMethod、destroyMethod
beanName相同时, 覆盖的情况
Role值更大的覆盖更小的,ROLE_INFRASTRUCTURE>ROLE_SUPPORT>ROLE_APPLICATION
@Bean覆盖@ComponentScan扫描出来的
@Import和内部类覆盖@Bean
多个@Bean,优先使用作用域广的(public>default>private),和参数多的
@Bean引入的配置类不会生效,因为FactoryMethodName不为空
ImportBeanDefinitionRegistrar
调用registerBeanDefinitions注册beandefinition,入参:父类的注解元数据、bean工厂,beanname生成器
它注册的如果是配置类,会生效
0 条评论
下一页