前言
- 看Refresh 部分看的心态有点崩, 就不多废话了。
在源码学习第二篇中我们提到过,CreateApplicationContext实际执行了
- 创建web应用上下文,对其部分属性:reader、scanner、beanFactory进行了实例化
- reader中实例化了属性conditionEvaluator
- scanner中添加了两个AnnotationTypeFilter:一个针对@Component,一个针对@ManagedBean;
- beanFactory中注册了8个注解配置处理器的Bean。
- 应用上下文类型实际上是AnnotationConfigServletWebServerApplicationContext,beanFactory的类型是DefaultListableBeanFactory
正文
代码的全貌
- 代码
context.setEnvironment(environment);
- 如果debug进去就可以发现 这是一个看似很简单的代码
- 代码实际上就是把环境变量里的初始化好的系统变量和配置信息复制给applicationContext
之前我们的应用中有两个environment,一个在Applicationcontext中,一个在SpringApplication中。经过此方法后,就只会存在SpringApplication中的environment了,而context中的原environment会被回收
出现两个environment的原因
第一次出现environment是springApplication创建的 这是一个springboot的类
- 第二次出现是在createApplicationContext的时候由AnnotatedBeanDefinitionReader创建的 这是一个spring的类, 在spring的类中直接用springboot的特性 这事不是十分的妥当
postProcessApplicationContext(context);
- 这里是为需要定制的springContext使用的 默认 这两个值都为null 也就是什么都不会做 (具体能做什么 还在学习中)
applyInitializers(context);
- 先看一眼代码
@SuppressWarnings({ "rawtypes", "unchecked" }) protected void applyInitializers(ConfigurableApplicationContext context) { for (ApplicationContextInitializer initializer : getInitializers()) { // 解析当前initializer实现的ApplicationContextInitializer的泛型参数 Class<?> requiredType = GenericTypeResolver.resolveTypeArgument( initializer.getClass(), ApplicationContextInitializer.class); // 断言context是否是requiredType的实例 Assert.isInstanceOf(requiredType, context, "Unable to call initializer."); // 向context应用初始化器 initializer.initialize(context); } }
- 实际上核心方法就是initializer.initialize(context); 执行了我们之前在spring.factories定义的一些初始化类
DelegatingApplicationContextInitializer
-
- 在配置了context.initializer.classes的情况下,获取其值(逗号分隔的initializer列表字符串),转换成class列表,根据classes列表进行实例化获取initializer实例列表,再对每个initializer实例调用initialize方法。
- 默认启动不配置 等于啥都没没干
- 可以看成一个Initializer的扩展手段
ContextIdApplicationContextInitializer
- 获取spring.application.name 并将他注册到beanFactory中
ConfigurationWarningsApplicationContextInitializer
- 注册了一个BeanFactoryPostProcessor:ConfigurationWarningsPostProcessor用来对ComponentScanPackage进行检查
- BeanFactoryPostProcessor是个重点, 后面bean的初始化是以它为几点进行的, 这个东西我目前还看的比较自闭。感觉很复杂。
- 其他的Initializer初始化了几个listener不是很影响主要流程就不展开了
listeners.contextPrepared(context);
- springboot的spring.factories里面的listener 注册这个事件的只有一个 而且是个空实现 所以等于什么都没做
启动参数和banner各自注册了一个单例
load(context, sources.toArray(new Object[0])); (核心逻辑)
- 看看一下核心代码
protected void load(ApplicationContext context, Object[] sources) { if (logger.isDebugEnabled()) { logger.debug( "Loading source " + StringUtils.arrayToCommaDelimitedString(sources)); } BeanDefinitionLoader loader = createBeanDefinitionLoader( getBeanDefinitionRegistry(context), sources); if (this.beanNameGenerator != null) { loader.setBeanNameGenerator(this.beanNameGenerator); } if (this.resourceLoader != null) { loader.setResourceLoader(this.resourceLoader); } if (this.environment != null) { loader.setEnvironment(this.environment); } loader.load(); }
+ 这里看一下BeanDefinitionLoader这个对象 ![image.png](https://ata2-img.oss-cn-zhangjiakou.aliyuncs.com/37e06fd7613e0e994493ce510cc01140.png) + 能被加载的source类型包括:Class、Resource、Package和CharSequence四种,每种类型的加载方式也不一样,Class用AnnotatedBeanDefinitionReader处理、Resource用XmlBeanDefinitionReader处理、Package用ClassPathBeanDefinitionScanner,而CharSequence则比较特殊了,它按Class、Resource、Package的顺序处理,哪种处理成功就按哪种处理 + 继续debug进去我们发现 我们的source是class类型 ![image.png](https://ata2-img.oss-cn-zhangjiakou.aliyuncs.com/48e1958fbaea5bdd1e80c2db86b1365c.png) + 最终我们的启动类因为SpringBootApplication注解中包含component注解 被封装成一个名叫SpringBootDemoApplication的BeanDefinition对象,并将其注册到了beanFactory的BeanDefinitionMap中。 ![image.png](https://ata2-img.oss-cn-zhangjiakou.aliyuncs.com/8ace5f89382abd4f13db9beaa748064e.png) ### listeners.contextLoaded(context) + 广播ApplicationPreparedEvent时间 触发的listener有 + ConfigFileApplicationListener + 向context注册了一个BeanFactoryPostProcessor:PropertySourceOrderingPostProcessor, 该实例后面会对我们的property sources进行重排序。(目前还没看到) + LoggingApplicationListener + BackgroundPreinitializer + DelegatingApplicationListener + EnableEncryptablePropertiesBeanFactoryPostProcessor