SpringBoot运行源码分析:Spring应用上下文刷新

1496 篇文章 10 订阅
1494 篇文章 14 订阅

Spring应用上下文的刷新

Spring 应用上下文的刷新,是通过调用 SpringApplication 中的 refreshContext 方法来完成的。SpringApplication 中 refreshContext 方法相关代码如下。

private void refreshContext(ConfigurableApplicationContext context) {
//调用 refresh 方法
refresh(context);
if (this.registerShutdownHook) {
try
//注册 shutdownHook 线程, 实现销毁时的回调
context . registerShutdownHook();
} catch (AccessControlException ex) {
//在某些环境中不允许使用,会报出此异常,但此处并无处理操作
protected void refresh(ApplicationContext applicationContext) {
Assert. isInstanceOf(AbstractApplicationContext. class, applicationContex
t);
((AbstractAppl icationContext) applicat ionContext) .refresh();
}
}

其中 refresh 方法调用的是
AbstractApplicationContext 中的 refresh 方法,该类属于 spring-context 包。AbstractApplicationContext 的 refresh 方法更 多的是 Spring 相关的内容,这里我们通过 refresh 方法的顶层代码了解该方法都做了些什么,不过多深入 Spring 内部进行讲解。

blic void refresh() throws BeansException, IllegalStateException {
//整个过程同步处理
synchronized (this. startupShutdownMonitor) {
//准备刷新工作
prepareRefresh();
//通知子类刷新内部 beanI 厂
ConfigurablelistableBeanFactory beanFactory = obtainFreshBeanFactory();
//为当前 context 准备 beanI 厂
prepareBeanF actory(beanFactory);
/允许 context 的子类对 beanIJ 进行后置处理
postProcessBeanFactory(beanFactory);
//调用 context 中注册为 bean 的工厂处理器
invokeBeanFactoryPostProcessors (beanFactory);
// 注册 bean 处理器(beanPostProcessors)
registerBeanPostProcessors (beanFactory);
//初始化 context 的信息源,和国际化有关
initMessageSource();
// 初始化 context 的專件传播器
ini tApplicationEventMulticaster();
//初始化其他子类特殊的 bean
onRefresh();
//检查并炷册事件监昕器
registerListeners();
//实例化所有非巅加裁单例
finishBeanFactoryInitialization(beanFactory);
//最后一步:发布对应事件
finishRefresh();
} catch (BeansException ex) {
// .....
finally {
// .....
}}}

在上面的代码中,调用 finishRefresh 方法初始化容器的生 命周期处理器并发布容器的生命周期事件之后,Spring 应用 上下文正式开启,Spring Boot 核心特性也随之启动。完成 refreshContext 方法操作之后,调用 afterRefresh 方 法。最新版本的 Spring Boot 中refreshContext 方法的实现默认为空,可由开发人员自行扩展,相关代码如下。

但需要注意的是,该方法在以往的版本中方法定义和实现差距较大,如果对此方法进行扩展,在升级版本时需特别留意。

protected void afterRefresh(ConfigurableApplicationContext context,
Applicat ionArguments args) {
//默认实现为空
}

完成以上操作之后,调用 SpringApplicationRun isteners 的 started 方法,通知监听器容器启动完成,并调用 ApplicationRunner 和 CommandL ineRunner 的运行方法。

调用 ApplicationRunner 和 CommandLineRunner

ApplicationRunner 和 CommandL ineRunner 是通过 SpringApplication 类的 callRunners方法来完成的,具体代码如下。

private void callRunners (ApplicationContext context, Applicat ionArguments a
rgs) {
List<0bject> runners = new ArrayList<>();
runners . addAll(context. getBeansOfType(ApplicationRunner. class). values());
runners . addAll(context . getBeansOfType(CommandL ineRunner . class).values());
AnnotationAwareOrderComparator. sort (runners);
for (Object runner : new LinkedHashSet<>(runners)) {
if (runner instanceof ApplicationRunner) {
callRunner((ApplicationRunner) runner, args);
}
if (runner instanceof Commandl ineRunner)
callRunner( (CommandL ineRunner) runner, args);
private void callRunner(ApplicationRunner runner, ApplicationArguments arg
s)i
try {
(runner). run(args);
} catch (Exception ex) {
throw new IllegalStateException("Failed to execute ApplicationRunner",
ex);
private void callRunner (CommandL ineRunner runner, ApplicationArguments arg
s) {
//内容与上面方法相同
}
}

以上代码,首先从 context 中获得类型为 ApplicationRunner 和 CommandLineRunner 的Bean, 将 它 们 放 入 List 列 表 中 并 进 行 排 序 。 然 后 再 遍 历 调 用 其 run 方 法 , 并 将ApplicationArguments 参数传入。

Spring Boot 提供这两个接口的目的,是为了我们在开发的过程中,通过它们来实现在容器启动时执行一-些操作,如果有多个实现类,可通过@Order 注解或实现 Ordered 接口来控制执行顺序。

这两个接口都提供了一个 run 方法,但不同之处在于: ApplicationRunner 中 run 方法的参数为 ApplicationArguments,而 CommandLineRunner 接口 中 run 方法的参数为 String 数组。

以上方法执行完成后,会通过
SpringApplicationRunListeners 的 running 方法通知监听器:

容器此刻已处于运行状态。至此,SpringApplication 的 run 方法执行完毕。

小结

本章重点围绕 Spring Boot 启动过程中 SpringApplication 类的 run 方法的执行流程进行讲解,并做了一些功能和知识点的拓展,其中重点为在此过程中的事件监听、初始化环境、容器的创建及初始化操作。

本章也是 Spring Boot 的核心功能之一,读者如果感兴趣可以进一步查看 Spring 相关源代码。

本文给大家讲解的内容是Spring应用上下文刷新和调用 ApplicationRunner 和 CommandLineRunner;

  1. 下篇文章给大家讲解的是Spring Boot 外化配置源码解析;
  2. 觉得文章不错的朋友可以转发此文关注小编;
  3. 感谢大家的支持!

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值