springboot内嵌容器初始化
2022-01-12 17:39:48 8 举报
AI智能生成
springboot内嵌容器初始化
作者其他创作
大纲/内容
springboot应用
SpringApplication
SA
spring上下文(AnnotationConfigServletWebServerApplicationContext)
SpringContext
SC
DefaultListableBeanFactory
DF
名称简写
1. 设置资源加载器,可以通过SA构造方法传入(SA缩写含义查看左侧说明) this.resourceLoader = resourceLoader
2. 设置主配置源,即SpringBootApplicatio注解所在的类,这个类在#2.6.8中会被加载到DF#beanDefinitionMap中 在#2.7.5.1.2.1进行bean定义解析时会扫描该类同级及子包下的bean,还会解析该类注解中引入的其他bean定义 this.primarySources = new LinkedHashSet<>(Arrays.asList(primarySources));
3. 判断是否为web环境,设置到SA#webApplicationType 属性中 this.webApplicationType = WebApplicationType.deduceFromClasspath();
顾名思义是用来对SC进行些初始化操作用的,在#2.6.3中会执行初始化方法
4. 获取应用上下文初始化器ApplicationContextInitializer,设置到SA#initializers中 setInitializers((Collection) getSpringFactoriesInstances(ApplicationContextInitializer.class));
此处会获取到一个比较关键的监听器:ConfigFileApplicationListener该监听器会读取spring或第三方(如Apollo)yml或properties配置。详情查看#2.4.3
5. 获取应用监听器ApplicationListener,设置到SA#listeners中,和4中基本类似 setListeners((Collection) getSpringFactoriesInstances(ApplicationListener.class));
1. 实例化SpringApplication对象
1. 创建SpringApplicationRunListeners对象,主要是加载广播器,然后将#1.5中的应用监听放入到广播器中span style=\
事件类关系图
事件uml类关系图
自定义监听示例
2. 广播ApplicationStartingEvent事件 listeners.starting();
3. 将main方法中的args转为ApplicationArguments对象,在#6.5中会被注册成单例bean ApplicationArguments applicationArguments = new DefaultApplicationArguments(args);
1 执行AbstractEnvironment构造方法,回调子类的customizePropertySources方法
2. 执行StandardServletEnvironment的customizePropertySources方法
3. 执行StandardEnvironment的customizePropertySources方法
1. 创建StandardServletEnvironment对象
1. 如果SA中environment为空,则创建StandardServletEnvironment对象(web环境)ConfigurableEnvironment environment = getOrCreateEnvironment();
1. 通过双重检索的方式实例化一个单例ApplicationConversionService对象
2. 将单例对象设置到environment的propertyResolver属性的conversionService
1. 往environment中添加defaultProperties
2. 往environment中添加commandLineArgs(添加到列表头,优先级最高)
2. 往environment中添加新的PropertySource
3. 添加spring.profiles.active配置及additionalProfiles值到environment的activeProfiles
2. 对上一步构建的环境对象environment进行进一步配置font color=\"#0076b3\
1. 添加RandomValuePropertySource到environment
1. 设置属性值解析器placeholdersResolver
2. 设置资源加载器resourceLoader
3. 设置propertySourceLoaders(从spring.factories加载PropertySourceLoader配置)
2. 实例化Loader对象
1. 执行initializeProfiles方法将active的配置添加到profiles队列
1 如果当前profile不为null且不是default,添加到environment的activeProfiles列表中
1. 获配置文件位置列表
1. 对位置是目录的进行获取配置文件名列表(默认application)
2. 遍历上一步获取的文件列表加载配置添加到loaded
2. 循环遍历位置列表
2. 加载当前profile,将加载好的配置添加到loaded列表中
3. 将当前profile添加到已完成列表processedProfiles
2. 循环处理profiles队列
3. 执行load方法
1. ConfigFileApplicationListener加载spring或第三方(如Apollo)yml或properties配置
3. 广播ApplicationEnvironmentPreparedEvent事件listeners.environmentPrepared(environment);
4. 绑定environment对象到SpringApplication对象中 bindToSpringApplication(environment);
configurationProperties相关类关系
5. 添加configurationProperties到environment,如果已存在先移除再添加ConfigurationPropertySources.attach(environment);
4. 构造容器环境font color=\"#0076b3\
DefaultListableBeanFactory类关系图
1. 进入父类GenericApplicationContext执行构造方法实例化beanFactory属性为DF对象
1. 设置registry 属性为SC
Profile注解示例
2. 设置conditionEvaluator属性为ConditionEvaluator对象,用来在doRegisterBean的时候判断需要注册的bean定义是否有@Conditional(如:ConditionalOnBean,@Profile等注解都是包含该注解的)注解,有的话进一步判断条件是否满足,不满足则不进行注册操作
能解析 @Order 注解和 @Priority 注解
1. 设置DF#dependencyComparator为AnnotationAwareOrderComparator
提供处理延迟加载的功能
2. 设置DF#autowireCandidateResolver为ContextAnnotationAutowireCandidateResolver
3. 将beanFactory后置处理器ConfigurationClassPostProcessor注册到DF#beanDefinitionMap中 该后置处理器非常的重要,主要用来解析bean定义,在#2.7.5.1.2中会被实例化
4. 将bean后置处理器AutowiredAnnotationBeanPostProcessor注册到DF#beanDefinitionMap中 也是比较重要的一个,主要用来处理bean依赖注入,如@Autowired依赖注入
5. 将bean后置处理器CommonAnnotationBeanPostProcessor注册到DF#beanDefinitionMap中 和AutowiredAnnotationBeanPostProcessor类似,主要要来处理java中自带的注解,如@Resource
6. 将beanFactory后置处理器EventListenerMethodProcessor注册到DF#beanDefinitionMap中 在#2.7.11.5.2中会被使用到,用来在所有非lazy单例Bean实例化完成后做些事情,如:将@EventListener注册的监听添加到SC事件发布器中
7. 将DefaultEventListenerFactory注册到DF#beanDefinitionMap中
3. 注册注解配置的后置处理器
1. 实例化reader属性为AnnotatedBeanDefinitionReader对象this.reader = new AnnotatedBeanDefinitionReader(this);
2. 注册默认的过滤器,比如注解过滤器用来表示标注了该注解的类才进行扫描也可以通过new AnnotationTypeFilter(Component.class)的方式定义过滤器添加进来
3. 设置environment
1. 设置resourcePatternResolver
2. 设置metadataReaderFactory
4. 设置resourceLoader
2. 实例化scanner属性为ClassPathBeanDefinitionScanner对象this.scanner = new ClassPathBeanDefinitionScanner(this);
2. 执行本类的无参构造
5. 创建AnnotationConfigServletWebServerApplicationContext类型的应用上下文对象SC context = createApplicationContext();
1. 设置父类AbstractApplicationContext的environment属性
2. 通过environment构造ConditionEvaluator设置到reader的
3. 设置scanner的environment属性
1. 设置环境为#2.4中构建的环境对象,主要包括三个地方 context.setEnvironment(environment);
2. 设置beanFactory的conversionService属性为ApplicationConversionService postProcessApplicationContext(context)
SharedMetadataReaderFactoryContextInitializer添加CachingMetadataReaderFactoryPostProcessor
ConfigurationWarningsApplicationContextInitializer添加ConfigurationWarningsPostProcessor
1. 其中有两个对象的initialize方法会执行addBeanFactoryPostProcessor方法 往SC#beanFactoryPostProcessors中添加beanFactory后置处理器,在#2.7.5.1中将会执行
3. 循环调用#1.4中initializers对象的initialize(C applicationContext)方法,执行一些初始化操作 applyInitializers(context);
4. 广播ApplicationContextInitializedEvent事件 listeners.contextPrepared(context);
5. 通过#2.3中的ApplicationArguments对象注册成单例bean springApplicationArguments beanFactory.registerSingleton(\"springApplicationArguments\
需要注意的是通过ClassPathBeanDefinitionScanner扫描的方式注册bean时如果出现bean名称相同该值是不起作用的因为在调用DF中的注册方法之前就会对扫描到的包进行检查,详情查看#2.6.8.2.2.1.2.2.5
6. 如果beanFactory为DefaultListableBeanFactory则设置allowBeanDefinitionOverriding值为false,表示不允许用相同的名称重新注册 setAllowBeanDefinitionOverriding(this.allowBeanDefinitionOverriding)
7. 获取#1.2中的primarySources及SA中的sources(可通过SpringApplication#setSources方法设置)添加到Set中 Set<Object> sources = getAllSources();
1. 设置需要加载的sources为#2.6.7中获取的sources
2. 实例化一个新的AnnotatedBeanDefinitionReader对象annotatedReader用来加载注解类型的BeanDefinition primarySources会被该对象注册到DF#beanDefinitionMap中
3. 实例化一个XmlBeanDefinitionReader对象用来加载xml类型的BeanDefinition
4. 实例化一个ClassPathBeanDefinitionScanner对象scanner用来以包扫描的方式注册BeanDefinition
5. 为4中的scanner对象设置不过滤规则,将sources中Class类型的source放入到过滤列表中
1. 通过#2.6.7中获取的source和SC中的beanFactory创建一个BeanDefinitionLoader对象font color=\"#0076b3\
1. 判断该类是否符合加载条件,比如有Component注解则直接进行加载
1. 通过注解类annotatedClass构造一个AnnotatedGenericBeanDefinition对象 abd
2. 通过 conditionEvaluator.shouldSkip方法判断abd元数据中是否有Conditional注解且满足加载条件 不满足则直接不进行接下来的注册操作,关于conditionEvaluator在#2.5.2.1.2中有描述
3. 指定创建 bean 实例的回调方法,此处为 null
4. 解析adb中是否有指定scope(没指定默认为单例),设置到abd中
5. 通过beanNameGenerator获取bean名称beanName
6. 主要处理 @Lazy @DependsOn @Primary @Role @Description 等注解,处理完成后设置到abd中
7. 主要是用来处理注册时有传qualifiers的情况
8. 将 ./5中获取的beanName和adb构造成一个BeanDefinitionHolder对象definitionHolder
9. 设置代理模型,此处不进行代理,直接返回definitionHolder
1. 从definitionHolder中取出beanName
2. 调用SC对象的registerBeanDefinition方法进行注册,实际上是调用DF#registerBeanDefinition方法 将bean定义注册到DF#beanDefinitionMap中
3. 如果有设置别名则进行别名注册
10. 通过工具类BeanDefinitionReaderUtils.registerBeanDefinition方法进行注册操作
2. 通过annotatedReader.register方法进行注册 最终注册逻辑在doRegisterBean方法中完成
1. 通过#2.6.8.1.2创建的annotatedReader对象注册primarySources
1. 获取已经注册的BeanDefinition总数量beanCountAtScanStart
1. class文件是否可读的
2. class文件不在excludeFilters过滤规则且在includeFilters(如有@Component注解)规则
3. 该class是可实例化的
1. 调用父类ClassPathScanningCandidateComponentProvider#findCandidateComponents方法 查找包路径下符合条件的class转化成ScannedGenericBeanDefinition添加到集合candidates中 此处不会去管class中是否又引入其他class 配置,那是#2.7.5.1.2中ConfigurationClassPostProcessor 干的事
1. 解析scope属性并设置到candidate
2. 通过beanNameGenerator获取bean名称beanName
3. 如果candidate是AbstractBeanDefinition类型,则为candidate设置默认值(如是否懒加载,初始化方法,销毁方法等)
如果该bean名称没有被注册过则和#2.6.8.2.1.2.10中那样通过BeanDefinitionReaderUtils.registerBeanDefinition方法进行注册
1. 已经存在的bean定义不是ScannedGenericBeanDefinition实例
2. 新注册的bean定义和已经存在的bean定义source相同(说明是同一个.class被扫描了两次)
3. 新注册的bean定义和已经存在的bean定义本身是相同的
满足其中一个条件则表示兼容
如果bean名称被注册过了则判断将要添加的bean定义和已经存在的bean定义是否兼容兼容则不进行注册,不兼容则抛出ConflictingBeanDefinitionException异常
5. 对将要添加的bean名称做检查
2. 循环BeanDefinition集合candidates
2. 执行真正的扫描注册逻辑
同时满足这三个添加才会被添加到集合candidates中
3. 计算注册的BeanDefinition数量进行返回
1. 执行scanner.scan方法进行注册
2. 通过#2.6.8.1.4中的scanner扫描包路径注册 (需要设置SC属性sources且source为包路径才会执行此操作)
2. 调用loader.load()方法将source逐一加载
8. 将#2.6.7中获取的sources加载到SC中font color=\"#0076b3\
1. 会循环SA中所有的监听器添加到SC中,如果监听器实现了ApplicationContextAware接口,会先执行监听器的setApplicationContext方法
1. 其中ConfigFileApplicationListener监听器会监听该事件 并往SC#beanFactoryPostProcessors中添加beanFactory后置处理器,在#2.7.5.1中将会执行
2. 通过广播器内部的initialMulticaster对象广播ApplicationPreparedEvent事件
9. 广播ApplicationPreparedEvent事件 listeners.contextLoaded(context);
6. 对上一步创建的SC进行些设置,为下一步进行refresh 做些准备工作font color=\"#0076b3\
1 清除SC中scanner对象的metadataReaderFactory属性的本地类元数据缓存
1. 设置应用上下文启动时间
2. 设置应用上下文close状态为false
3. 设置应用上下文active状态为true
4. 对environment做些初始化操作,比如上下文中有设置servletContext值则会从设置的对象中取出 servletContextInitParams替换environment中设置的servletContextInitParams
5. 验证environment必填属性是否填写
6. 设置监听器为#1.5中的那些监听器到SC中
2. 调用父类的prepareRefresh方法
1. 为应用上下文刷新做些准备工作prepareRefresh();
1. 调用DF#setSerializationId方法往serializableFactories Map属性中put值 key为spring应用的名称,值为一个弱引用,该弱引用引用对象为当前DF对象
2. 将DF对象#2.5.1中的DF对象返回
2. 获取beanFactory对象,该对象在#2.5.1中已经创建好了\t\t\tConfigurableListableBeanFactory beanFactory = obtainFreshBeanFactory();
1. 设置DF的beanClassLoader为SC的classLoader
2. 设置EL表达式解析器(Bean初始化完成后填充属性时会用到)
3. 设置属性注册解析器PropertyEditor 这个主要是对bean的属性等设置管理的一个工具
EnvironmentAware
EmbeddedValueResolverAware
ResourceLoaderAware
ApplicationEventPublisherAware
MessageSourceAware
ApplicationContextAware
4. 添加ApplicationContextAwareProcessor bean后置处理器,用于实现在bean中对SC的织入 需要注意的是该处理器postProcessBeforeInitialization方法除了会判断是否实现了ApplicationContextAware接口进行织入外 还会判断是否有实现右侧的接口,因为SC实现了右侧的那个些接口,直接将SC转为对应的接口类型即可。 因此会将右侧的那些接口添加到ignoreDependencyInterface中,被添加到ignoreDependencyInterface中的接口被 bean实现setXXX方法则就不会进行依赖注入了(如通过@AutoWrite注解依赖)
BeanFactory
ResourceLoader
ApplicationEventPublisher
ApplicationContext
5. 往resolvableDependencies中添加自动装配对象,这些自动装配的对象不会以bean的形式存在IOC容器中 但却可以通过@Autowired装配,因为在依赖注入时会先检查resolvableDependencies中是否存在依赖的bean
6. 添加ApplicationListenerDetector bean后置处理器,用于在Bean初始化后检查是否实现了ApplicationListener接口,实现了就添加到applicationListeners中
7. 检查容器中是否包含名称为loadTimeWeaver的bean,有则添加LoadTimeWeaverAwareProcessor bean后置处理器 实际上是增加Aspectj的支持
8. 注入单例bean environment
9. 注入单例bean systemProperties
10. 注入单例bean systemEnvironment
3. 对beanFactory做些准备工作 prepareBeanFactory(beanFactory)
1. 添加WebApplicationContextServletContextAwareProcessor bean后置处理器 为实现ServletContextAware接口的bean设置ServletContext对象 或为实现ServletConfigAware接口的bean设置ServletConfig对象
2. 将ServletContextAware类型添加到ignoredDependencyInterfaces中 因为后置处理器WebApplicationContextServletContextAwareProcessor的父处理器中会对该接口进行了处理 关于ignoredDependencyInterfaces查看#2.7.3.4
在doGetBean源码分析#4.9.2中会使用
1. 实例化一个RequestScope对象添加到DF#scopes中,key为request
2. 实例化一个SessionScope对象添加到DF#scopes中,key为session
此处是@AutoWrite HttpServletRequest时保证线程安全的关键在依赖注入HttpServletRequest时其实是注入了AutowireUtils#ObjectFactoryDelegatingInvocationHandler代理对象(代码见备注)该代理对象代理了HttpServletRequest的所有方法,在调用某个方法时先通过RequestObjectFactory#getObject获取当前请求的request对象然后通过request对象反射执行对应的方法,从而保证线程安全性
3. 实例化一个RequestObjectFactory对象添加到resolvableDependencies中,key为ServletRequest.class
4. 实例化一个ResponseObjectFactory对象添加到resolvableDependencies中,key为ServletResponse.class
5. 实例化一个SessionObjectFactory对象添加到resolvableDependencies中,key为HttpSession.class
6. 实例化一个WebRequestObjectFactory对象添加到resolvableDependencies中,key为WebRequest.class
3. 注册scrop及resolvableDependencies
1. 调用SC父类ServletWebServerApplicationContext的postProcessBeanFactory方法
2. SA#basePackages属性是否有值,有值则进行scanner.scan操作将符合条件的bean定义先注册beanDefinitionMap中
3. 和上面操作相似,只是是通过注解的方式进行加载
4. AbstractApplicationContext模板方法,供子类做些自定义实现 postProcessBeanFactory(beanFactory);
1. 循环SC#beanFactoryPostProcessors中的后置处理器,如果处理器实现了 BeanDefinitionRegistryPostProcessor则执先行该处理器的postProcessBeanDefinitionRegistry方法 然后添加处理器到registryProcessors 列表中,否则添加到regularPostProcessors列表中
1. 根据beandefinitionregistry生成全局唯一的registryid
2. 如果该registeryid已经执行过了则抛出异常,不再执行
3. 将当前registeryid添加到registriespostprocessed中 用于后面进来判断是否已执行
1. \"Full\"模式 有@Configuration注解的类,是则标识为full属性值
2. \"lite\"模式 有@Component,@ComponentScan,@Import,@ImportResource注解的类 或在@Component注解类中通过@Bean注解标识方法的方式
1. 从df#beanDefinitionmap中找出符合条件的beanDef放入configcandidates列表中 所谓的符合条件的有两种情况包含右侧两种情况,两者的区别见备注 此时@SpringBootApplication标识的类会被添加(在#2.6.8.2.1放入beanDefinitionMap) font color=\"#0076b3\
2. 对 configCandidates 进行按优先级排序
如果DF中没有internalConfigurationBeanNameGenerator单例bean则使用默认的AnnotationBeanNameGenerator其生成规则为Bean扫描方式为首字母小写,import模式为全类名
3. 为Bean扫描方式及import方式设置BeanNameGenerator
4. 设置environment,此处environment不为空不会执行,因为ConfigurationClassPostProcessor 实现了EnvironmentAware接口在bean初始化的时候就被织入了environment
5. 实例化ConfigurationClassParser对象parser
6. 将List 对象configCandidates构建成一个Set 对象candidates进行去重处理 Set<BeanDefinitionHolder> candidates = new LinkedHashSet<>(configCandidates);
1. 判断是否加载这个配置类,如果不满足Condition注解条件则直接返回
1. 存在的那个configClass也是@Import则进行合并操作
2. 不符合上面的条件则不进行当前configClasss的解析操作了
1.如果当前需要继续的configClass是@Import类型的
2. 如果上一步的条件则移除已存在的,继续解析当前configClass
2. 如果这个配置类已经存在configurationClasses中了
3. 将configClass 作为原始类,在下一步的解析操作中如果原始类的父类符合解析条件会递归解析 SourceClass sourceClass = asSourceClass(configClass);
1. 先处理内部类中是否有内部类配置,有则先处理内部类配置
2. 对@PropertySource注解进行解析,如@PropertySource(\"classpath:test.properties\") 会将该配置添加到environment中
3. 处理@ComponentScans 先获取所有的@ComponentScans,然后循环执行扫描操作(通过ComponentScanAnnotationParser) 扫描到bean会直接被添加到DF#beanDefinitionmap中,不会等到 ../../../3 中loadBeanDefinitions再添加 而且如果被添加的bean定义是full或lite bean 则递归执行 ../../../1 的parse操作
1. 将@Import注解中的Class值包装为SourceClass放入Set<SourceClass> imports中 供下一步processImports使用,此过程会递归查找包装后的SourceClass中是否又有@Import 其他Class,有的话也会添加到improts集合中 getImports(sourceClass)
1. 如果importCandidates(实参为imports)为空直接return
2. 如果存在循环@import则抛出CircularImportProblem异常
1. 实例化当前candidate的类并转为ImportSelector类型对象selector
2. 对上一步的selector进行一些Aware
3. 判断该selector是否还实现了DeferredImportSelector接口 有则添加到deferredImportSelectorHandler中,在../../../../../../2中解析 否则进入下一步逻辑font color=\"#0076b3\
4. selector没有实现DeferredImportSelector接口,通过selector.selectImports 查找出需要import的类名称数组,再将该数组包装为Collection<SourceClass>集合importSourceClasses 最后递归调用 ../../2 的processImports方法将selectImports进来的那些类进行解析font color=\"#0076b3\
1. 如果当前candidate实现了ImportSelector接口,否则进入下一步逻辑
1. 实例化当前candidate的类并转为ImportBeanDefinitionRegistrar类型对象registrar
2. 对上一步的registrar进行一些Aware
3. 将registrar 添加到configClass#importBeanDefinitionRegistrars中 key为registrar,值为currentSourceClass.getMetadata()
2. 如果当前candidate实现了ImportBeanDefinitionRegistrar接口,否则进入下一步逻辑
ImportAware使用示例
3. 将当前currentSourceClass的元数据信息添加到ConfigurationClassParser,内部类ImportStack的import属性中 key为当前candidate的类名称,值为currentSourceClass.getMetadata()(在实现ImportAware接口时setImportMetadata方法中的参数值就是来源于此处) 然后递归调用 ../../../../../1 的processConfigurationClass方法解析当前candidate 需要注意的是asConfigClass时传入了configClass,这样configClass将会被添加到构建的ConfigurationClass#importedBy集合中 processConfigurationClass(candidate.asConfigClass(configClass));
3. 循环importCandidates
2. 循环解析上一步获取的imports,最后的true参数表示检测循环importfont color=\"#0076b3\
4. 处理@Import注解
5. 处理@ImportResource注解 获取@ImportResource注解中locations属性的数组值String[] resources 再取出reader属性的值Class readerClass(默认值为BeanDefinitionReader.class) 最后循环resources 添加到当前font color=\"#0076b3\
6. 处理@Bean注解的方法 获取所有@Bean注解值放入Set<MethodMetadata> beanMethods集合中 然后循环beanMethods将MethodMetadata 包装成BeanMethod对象后添加到 当前configClass#beanMethods属性中
7. 处理接口上带@Bean的默认方法 和上一步一样,只不过是去当前configClass类的实现接口中查找默认方法上是否有@Bean注解
8. 如果当前sourceClass有父类且父类名称非java开头,则返回父类的sourceClass包装递归解析父类 否则的话返回null跳出 ../4 中的do while循环
4. 执行configClass解析操作,会通过 do{}while(sourceClass!=null) 递归解析父类 font color=\"#0076b3\
5. 将解析好的当前configClass添加到ConfigurationClassParser#configurationClassess 属性中,key和value都是当前configClassfont color=\"#0076b3\
1. 针对不同的BeanDefinition构造成ConfigurationClass对象 然后调用 processConfigurationClass(ConfigurationClass configClass)
2. 处理上一步处理过程中需要延迟执行的ImportSelector(./1.4.4.2.3.1.3出添加) this.deferredImportSelectorHandler.process();
1. 执行parse操作 parser.parse(candidates);
标注@Configuration的类不能被Final修饰不然会抛出FinalConfigurationProblem异常
标注@Configuration的类中有@Bean注解标注的方法则该方法需要能被冲洗不然会抛出NonOverridableMethodError异常
2. 对解析出来的对象做校验,主要是对有解析出来的带@Configuration注解的对象进行校验 主要是为了支持#2.7.1.5.1中对full模式的bean进行cglib代理 parser.validate();
1. 该configClass的类是@Import value属性中导入的类(通过importedBy属性不为空表示是@Import导入) 且引入该@Import注解的类本身也是被@Import导入的。 importedBy属性的设置可以查看 ../../1.1.4.4.2.3.3
2. 标注了@Condition注解且不满足条件
1. 判断是否要跳过该configClass加载,有如右两种情况需要跳过
2. 对@Import导入的configClass注册为bean定义,能来到此处说明importedBy属性为空 不然上一步就被跳过了 registerBeanDefinitionForImportedConfigurationClass(configClass);
需要注意的是:同一个配置类中通过@Bean(\"xxx\")定义两个相同名称的bean会忽略后面定义的那个如果是不同的配置类中通过@Bean定义两个相同名称的bean在执行注册的时候会判断allowBeanDefinitionOverriding的值如果该值为false则会抛出BeanDefinitionOverrideException异常
3. 对包含@Bean标注方法的configClass进行处理,循环将所有的方法注册为bean定义 loadBeanDefinitionsForBeanMethod(beanMethod);
4. 对ImportedResources 的configClass进行注册 loadBeanDefinitionsFromImportedResources(configClass.getImportedResources());
5. 对@Import导入且实现了ImportBeanDefinitionRegistrar接口(../../1.1.4.4.2.3.3)的configClass注册为bean定义 loadBeanDefinitionsFromRegistrars(configClass.getImportBeanDefinitionRegistrars());
3. 通过ConfigurationClassBeanDefinitionReader对象将上一步解析出来的 ConfigurationClass对象列表做为bean定义循环添加到DF#beanDefinitionmap中 this.reader.loadBeanDefinitions(configClasses);
4. 如果DF中通过上一步新增的bean定义中存在未解析的full或lite bean定义 则继续添加到 candidates中继续解析
7. 循环解析candidates 中bean定义引入的相关ConfigurationClass对象 然后将这些对象解析为bean定义添加到DF#beanDefinitionmap中
8. 将ConfigurationClassParser对象中的importStack属性注册为单例bean 通过上面的操作importStack中保存了所以@Import进来的配置类信息,比如在实现ImportAware接口时会用到font color=\"#0076b3\
4. 执行真正的解析逻辑
1. ConfigurationClassPostProcessor#postProcessBeanDefinitionRegistry 会在此时执行(在#2.5.2.1.3.3中被添加进来了),该处理器实现了PriorityOrdered接口 所以优先级会比较高
2. 从DF(包含beanDefinitionMap和已手动注册的单例bean)中获取所有实现了BeanDefinitionRegistryPostProcessor的 beanDefinition,再从中筛选出实现了PriorityOrdered接口的处理器进行加载成bean实例后执行 postProcessBeanDefinitionRegistry方法,最后将该处理器实例添加到registryProcessors 列表中 (其实此处符合执行条件的就只有#2.5.2.1.3.3中添加的ConfigurationClassPostProcessor)
像自定义类只实现BeanDefinitionRegistryPostProcessor接口的话会在这一步执行postProcessBeanDefinitionRegistry方法
3. 和2中一样,只不过是筛选出只实现了Ordered(该接口是PriorityOrdered的父接口)接口的处理器 其实目的只是为了控制那些实现了PriorityOrdered接口的处理器能先执行
4. 和2中一样,只不过是将那些既没有实现PriorityOrdered接口,也没实现Ordered接口的处理器进行执行 postProcessBeanDefinitionRegistry方法,同样是为了控制处理器的执行顺序
1. 对@Configuration注解的beanDefinition进行cglib代理增强 enhanceConfigurationClasses(beanFactory);
2. 添加 ImportAwareBeanPostProcessor后置处理器 beanFactory.addBeanPostProcessor(new ImportAwareBeanPostProcessor(beanFactory));
1. ConfigurationClassPostProcessor#postProcessBeanFactory 方法会在此时执行
5. 循环执行registryProcessors中beanFactory处理器的postProcessBeanFactory方法
6. 循环执行regularPostProcessors中beanFactory处理器的postProcessBeanFactory方法
PropertySourcesPlaceholderConfigurer#postProcessBeanFactory将在这一步被调用该后置处理器是由PropertyPlaceholderAutoConfiguration自动引入进来的会通过环境中的值替换${}占位符中的值,需要注意的是@Value注解中的${}占位符是在属性依赖的时候进行解析的
7. 和2中类似,只不过是从DF中获取所有实现了BeanFactoryPostProcessor 的后置处理器,执行顺序也是和BeanDefinitionRegistryPostProcessor一样 按照PriorityOrdered,Ordered,nonOrdered的顺序执行处理器的postProcessBeanFactory方法
1. 将DF和SC#beanFactoryPostProcessors做为参数调用PostProcessorRegistrationDelegate#invokeBeanFactoryPostProcessors方法
2. 和#2.7.3.7做同样的事情
5. 执行BeanFactory后置处理器 invokeBeanFactoryPostProcessors(beanFactory)
1. SC#beanFactoryPostProcessors中的BeanDefinitionRegistryPostProcessor类型postProcessBeanDefinitionRegistry方法
2. DF#beanDefinitionMap中BeanDefinitionRegistryPostProcessor+PriorityOrdered类型的postProcessBeanDefinitionRegistry方法
3. DF#beanDefinitionMap中BeanDefinitionRegistryPostProcessor+Ordered类型的postProcessBeanDefinitionRegistry方法
4. DF#beanDefinitionMap中BeanDefinitionRegistryPostProcessor类型的postProcessBeanDefinitionRegistry方法
5. SC#beanFactoryPostProcessors中的BeanDefinitionRegistryPostProcessor类型postProcessBeanFactory方法
6. DF#beanDefinitionMap中的BeanDefinitionRegistryPostProcessor类型postProcessBeanFactory方法
7. SC#beanFactoryPostProcessors中的BeanFactoryPostProcessor类型postProcessBeanFactory方法
8. DF#beanDefinitionMap中的BeanFactoryPostProcessor+PriorityOrdered类型postProcessBeanFactory方法
9. DF#beanDefinitionMap中的BeanFactoryPostProcessor+Ordered类型postProcessBeanFactory方法
10. DF#beanDefinitionMap中的BeanFactoryPostProcessor类型postProcessBeanFactory方法
执行顺序
1.获取DF中类型为BeanPostProcessor的所有bean名称postProcessorNames,会从beanDefinitionNames和manualSingletonNames中去查找
2. 添加BeanPostProcessorChecker bean后置处理器到DF#beanPostProcessors中
3. 主要逻辑为按priorityOrdered,ordered,nonOrdered的顺序分别将1中postProcessorNames包含的bean取出各自排序后添加到DF#beanPostProcessors中 在各自取出的过程中如果bean实现了MergedBeanDefinitionPostProcessor则放在一个list中等其他beanPostProcessor都添加好了再添加 整个过程和#2.7.5.1有点类似,只是没有执行后置处理器中的方法,只是添加到了DF#beanPostProcessors中 需要注意的是自定义的bean如果实现了BeanPostProcessor接口在这一步就加载bean了,而不是在 #2.7.11进行加载,所以想要对实现了BeanPostProcessor接口的 bean初始化的时候执行postProcessAfterInitialization或postProcessBeforeInitialization则需要定义一个优先级比它高的处理器
4. 添加ApplicationListenerDetector bean后置处理器到DF#beanPostProcessors中 其实在#2.7.3.6中已经添加了该处理器,这里再次添加只是为了让该处理器处于列表的最后,因为添加DF#addBeanPostProcessor方法会先移除再添加
6. 按优先顺序将BeanPostProcessor类型的bean定义取出实例化后添加到DF#beanPostProcessors中 registerBeanPostProcessors(beanFactory);
1. 实例化一个DelegatingMessageSource对象dms
2. 为dms设置父MessageSource
3. 将dms注册为一个名为messageSource的单例bean
7. 初始化消息源 initMessageSource();
8. 初始化SC的事件多播器applicationEventMulticaster为SimpleApplicationEventMulticaster,并注册为单例bean initApplicationEventMulticaster();
1. 调用父类GenericWebApplicationContext#onRefresh方法初始化模板源
在autoconfigure模块的spring.factories文件中有引入ServletWebServerFactoryAutoConfigurationServletWebServerFactoryAutoConfiguration类中Import了多个静态类,包括EmbeddedTomcat.class,EmbeddedJetty.class其中EmbeddedTomcat.class会通过@Bean引入TomcatServletWebServerFactory bean
1. 从DF中加载ServletWebServerFactory类型的bean,springboot默认内嵌tomcat 所以此处加载的是TomcatServletWebServerFactory
1. 设置spring根上下文到ServletContent的属性中,属性名为org.springframework.web.context.WebApplicationContext.ROOT 属性值为SC,并为SC#servletContext属性设置
1. 通过ServletContent构造一个ServletContextScope对象appScope
2. 将appScope添加到DF#scope Map中
3. 将appScope添加到ServletContent属性中
2. 注册应用作用域
3. 注册Servlet的一些单例bean,如servletContext,contextParameters,contextAttributes等
如果有引入springsecurity,则DelegatingFilterProxyRegistrationBean就是在这一环节被加载然后在后面执行onStart方法的时候会将DelegatingFilterProxy过滤器添加到servlet上下文中
ServletContextInitializer类关系图
1. 在DF中查找符合ServletContextInitializer类型的bean进行加载,此处会加载DispatcherServletRegistrationBean 该bean是在DispatcherServletAutoConfiguration中进行引入的,而DispatcherServletAutoConfiguration 是在spring.factories中被引入的
2. 主要是从DF中加载Servlet,Filter,EventListener 类型的bean,然后包适配成RegistrationBean 所以我们自定义一个Filter类然后加上@Component注解也是会被加载到servlet上下文中
3. 将上两步收集的bean排序后放入List<ServletContextInitializer> sortedList属性中供后面循环执行onStart()方法
4. 获取所有ServletContextInitializer bean
5. 循环调用上一步中bean的onStart()方法,将各自bean中的Servlet/Filter/Listener注册到servlet上下文中
2. 执行ServletWebServerFactory#getWebServer方法,该方法接收一个ServletContextInitializer 对象 在getWebServer方法中会实例化一个TomcatWebServer对象进行返回,在TomcatWebServer的构造中会调用 ServletContextInitializer的onStartup(ServletContext servletContext)方法
3. 和#2.7.1.2.4中执行的逻辑差不多,只是现在servletContent是有值的,会替换environment中设置的servletContextInitParams
2. 调用createWebServer()方法,执行创建web服务的操作
9. 创建web服务 onRefresh();
监听器示例
1. 将#1.5中获取到的那些监听器添加到SimpleApplicationEventMulticaster#applicationListeners集合中 在#2.6.9.1中有将#1.5中的那些监听器添加到SC#applicationListeners中,所以此处getApplicationListeners方法能获取到#1.5中的监听器 正因为将这些监听器添加到了SimpleApplicationEventMulticaster中,所以#1.5中的那些监听器也能监听到SC中广播的事件
2. 从DF中查找ApplicationListener类型的bean名称添加到SimpleApplicationEventMulticaster#applicationListenerBeans集合中
3. 判断SC的earlyApplicationEvents属性中是否有早期应用事件,有则直接发布,并清空earlyApplicationEvents属性
10. 注册监听器 registerListeners();
1. 设置初始化上下文转换服务,在#2.6.2中已经设置过了,所以此处不会再设置
2. 将DF中LoadTimeWeaverAware类型的bean进行实例化
3. 停止使用临时的类加载器
4. 冻结所有的bean定义,不再允许修改
1. 如果当前bean定义不是RootBeanDefinition则先转为RootBeanDefinition进行返回供后面实例化 同时添加到DF#mergedBeanDefinitions中供下次直接获取
如果是工厂bean则通过&+bean名称去getBean实例,获取到的是bean工厂本身实例如果该工厂bean是SmartFactoryBean实例且工厂bean的isEagerInit()方法返回值为true则去getObject
doGetBean源码分析
getBean具体加载流程查看\"doGetBean源码分析\"
如果是普通bean则直接进行加载
2. 只对非抽象类非延迟加载的单例bean定义进行实例化
1. 根据DF#beanDefinitionNames中的名称进行循环初始化
@EventListener示例
2. 对SmartInitializingSingleton类型的bean执行回调方法afterSingletonsInstantiated 用来在所有非lazy单例Bean实例化完成后做写事情,比如EventListenerMethodProcessor 在此时会将@EventListener注册的监听添加到SC事件发布器中
5. 实例化bean定义 beanFactory.preInstantiateSingletons();
11. 实例化非延迟加载的单例bean finishBeanFactoryInitialization(beanFactory);
1. 清除一些上下文中的缓存,比如scanning的时的一些元数据缓存 clearResourceCaches();
2. 初始化生命周期处理器DefaultLifecycleProcessor,将它作为单例bean添加到bean 容器中 initLifecycleProcessor();
3. 调用上面处理器的onRefresh方法,这个方法会找出实现了SmartLifecycle接口的bean进行start方法的调用 getLifecycleProcessor().onRefresh();
4. 发布ContextRefreshedEvent事件 publishEvent(new ContextRefreshedEvent(this));
1. 往MBeanServer中注册了LiveBeansView对象,其中保存了属性applicationContexts
2. 将SC上下文对象添加到applicationContexts中 SpringApplicationAdminJmxAutoConfiguration对注册SpringApplicationAdminMXBeanRegistrar bean 该bean中有个内部类SpringApplicationAdmin,该内部类实现了SpringApplicationAdminMXBean
font color=\"#0076b3\
12. 完成容器刷新后的一些其他事情 finishRefresh()
7. refresh应用上下文refreshContext(context);
8. 广播ApplicationStartedEvent事件listeners.started(context);
9. 回调ApplicationRunner或CommandLineRunner bean的run方法font color=\"#0076b3\
2. 执行SpringApplication对象的run方法
Apollo在获取配置的时候会先从系统环境中获取,如果能取到就直接返回了所以需要覆盖Apollo配置可以通过-Dxxx=xxx进行覆盖
1. 外部配置(如Apollo)
2. commandLineArgs(命令行传参)
3. servletConfigInitParams
4. servletContextInitParams
5. systemProperties(系统属性)
6. systemEnvironment(环境变量)
7. [classpath://xxx.xxx](配置文件)
8. defaultProperties(默认配置如通过SpringApplicationBuilder.properties(Map)添加)
配置优先顺序
springboot内嵌容器初始化(2.1.3.RELEASE)
0 条评论
回复 删除
下一页