完成以上操作之后,程序便调用 SpringApplicationRunListeners 的 contextPrepared 方法通知监听器,至此第一阶段的准备操作完成 。
应用上下文加载阶段应用上下文加载阶段包含以下步骤:打印日志和 Profile 的设置、设置是否允许覆盖注册、获取全部配置源、将配置源加载入上下文、通知监控器 contex 加载完成 。
首先进入应用上下文加载阶段的操作为打印日志和 Profile 的设置,对此不展开讲解 。随后,便是获得 ConfigurableL istableBeanFactory 并注册单例对象,注册的单例对象包含:
ApplicationArguments 和 Banner 。当 BeanFactory 为 DefaultL istableBeanFactory 时,进入设置是否允许覆盖注册的处理逻辑 。
此处需注意的是,当进行了 ApplicationArguments 类单例对象的注册之后,也就意味着我们在使用 Spring 应用上下文的过程中可以通过依赖注入来使用该对象 。
@Resourceprivate ApplicationArguments applicat ionArguments;
完成以.上操作后,便进入配置源信息的处理阶段,这一步通过 getAllSources 方法来对配置源信息进行合并操作 。
public Set<Object> getAllSources() {Set<0bject> allSources = new LinkedHashSet<>();if (!CollectionUtils.isEmpty(this . primarySources)) {allSources.addAll(this.primarySources);if (!CollectionUtils . isEmpty(this. sources)) {allSources. addAll(this.sources);}}
return Collections . unmodifiableSet(allSources); }以上操作逻辑很简单,如果 Set 集合中不存在 primarySources 配置源或 sources 配置源,则将其添加入 Set 中,同时将 Set 设置为不可修改,并返回 。
前面章节已经提到,变量 primarySources 的值 来自 SpringApplication 的构造参数,变量sources 的值来自 setResources 方法 。
当获得所有的配置源信息之后,通过 load 方法将配置源信息加载到上下文中,代码如下 。
protected void load(ApplicationContext context, Object[] sources) {/日志打印BeanDefinitionLoader loader = createBeanDefinitionLoader(getBeanDefinitionRegistry(context), sources);f (this. beanNameGenerator != nu1l).loader. setBeanNameGenerator(this . beanNameGenerator);if (this.resourceLoader != nu1l) {loader . setResourceLoader(this . resourceLoader);if (this. environment != null) {loader . setEnvironment (this . environment) ;loader. load();}
该方法主要通过 BeanDefinitionL oader 来完成配置资源的加载操作 。我们进一步查看方法createBeanDefinitionL oader 的源代码,会发现它最终调用了 BeanDefinitionL oader 的构造方法,并进行初始化操作 。
【SpringBoot运行源码分析:Spring应用上下文准备】BeanDefinitionLoader(BeanDefinitionRegistry registry, Object... sources) {this. sources = sources;this . annotatedReader = new AnnotatedBeanDefinitionReader(registry);this . xmlReader = new XmlBeanDefinitionReader(registry);if (isGroovyPresent())this. groovyReader = new GroovyBeanDefinitionReader(registry);}
通过 BeanDefinitionLoader 的构造方法我们可以看到 BeanDefinitionLoader 支持基于AnnotatedBeanDefinitionReaderXmlBeanDefinitionReader、GroovyBeanDefinitionReader等 多种类型的加载操作 。
在执行完 BeanDefinitionL oader 的创建及基本属性设置之后,调用其 load方法,该方法最终执行以下代码 。
private int load(0bject source) {Assert. notNull(source, "Source must not be null");if (source instanceof Class<?>) {return load((Class<?>) source);}if (source instanceof Resource)return load( (Resource) source);}if (source instanceof Package) {return load( (Package) source);}if (source instanceof CharSequence) {return load( (CharSequence) source);throw new IllegalArgumentException("Invalid source type ”+ source. getClass());}
从以上代码可以看出,BeanDefinitionLoader 加载支持的范围包括:
Class、Resource、 Package 和 CharSequence 四种 。前面我们已经提到变量 sources的来源有 primarySources 配置源和 sources 配置源 。变量 primarySources 在初始化时接收的类型为 Class,而变量 sources 通过 set(Set<String> )方法接收的参数为 String 集合 。
因此,在实际使用的过程中,Resource 和 Package 的判断分支始终无法进入执行阶段 。
完成以上操作后,接下来执行 SpringApplicationRunListeners 的 contextL oaded 方法通知监听器上下文加载完成,至此整个 Spring 应用上下文的准备阶段完成 。
推荐阅读
- 骁龙870能流畅运行原神吗?骁龙865处理器玩原神怎么样?
- Zookeeper ZAB协议实现源码分析
- Win10关闭系统更新
- Bullet-joggle 内网穿透 Web管理工具,附源码
- Redis源码剖析之SDS
- 看了两天HashMap源码,终于把红黑树插入平衡规则搞懂了
- 程序运行后性能总会下降?你应该先了解编程语言的内存布局与管理
- 这份源码阅读步骤你值得拥有
- 使用Docker来构建、运行、发布微服务
- 一行代码让你的python运行速度提高100倍