Spring 源码解析:onRefresh 方法深度剖析与高频面试题解析
一、onRefresh 方法概述
onRefresh 是 Spring Framework 中 AbstractApplicationContext 类的核心方法之一,在 Spring 容器的刷新流程中扮演重要角色。作为容器生命周期钩子方法,它的核心作用是触发子类在容器刷新阶段的定制化初始化逻辑,例如初始化 Web 服务器、消息监听器、定时任务等。
二、源码定位与执行时机
1. 源码位置
org.springframework.context.support.AbstractApplicationContext#onRefresh
protected void onRefresh() throws BeansException {
// 默认空实现,子类按需覆盖
}
2. 执行时机
在 AbstractApplicationContext#refresh() 方法的调用链中,onRefresh 的触发顺序如下:
1. prepareRefresh()
2. obtainFreshBeanFactory()
3. prepareBeanFactory()
4. postProcessBeanFactory()
5. invokeBeanFactoryPostProcessors()
6. registerBeanPostProcessors()
7. initMessageSource()
8. initApplicationEventMulticaster()
9. onRefresh() <-- 关键点
10. registerListeners()
11. finishBeanFactoryInitialization()
12. finishRefresh()
核心特点:
- 在
BeanFactory初始化完成后调用,早于单例 Bean 的实例化(finishBeanFactoryInitialization)。 - 子类通过覆盖此方法实现容器级初始化逻辑,而非单个 Bean 的初始化。
三、子类扩展与典型实现
1. ServletWebServerApplicationContext(Web 应用)
源码路径:
org.springframework.boot.web.servlet.context.ServletWebServerApplicationContext#onRefresh
核心逻辑:
@Override
protected void onRefresh() {
super.onRefresh();
try {
createWebServer(); // 创建嵌入式 Web 服务器(Tomcat/Jetty)
} catch (Throwable ex) {
// 异常处理
}
}
- 作用:在容器刷新阶段启动嵌入式 Web 服务器。
- 关键对象:通过
ServletWebServerFactory动态创建服务器实例。
2. AbstractRefreshableWebApplicationContext(传统 Spring MVC)
源码路径:
org.springframework.web.context.support.AbstractRefreshableWebApplicationContext#onRefresh
核心逻辑:
- 初始化主题资源(ThemeSource)。
- 注册 Servlet 特定的作用域(Request/Session/Application)。
四、自定义扩展实战
场景:在 Spring Boot 应用中添加自定义初始化逻辑(如启动时加载缓存)。
实现方式:
public class CustomApplicationContext extends AnnotationConfigServletWebServerApplicationContext {
@Override
protected void onRefresh() {
super.onRefresh();
// 自定义逻辑:初始化全局缓存
CacheManager.initGlobalCache();
// 启动后台线程
new Thread(() -> System.out.println("Background task started")).start();
}
}
五、高频面试题与答案
问题 1:onRefresh 方法的调用时机是什么?它的作用是什么?
答案:
- 调用时机:在
BeanFactory初始化完成之后,单例 Bean 实例化之前。 - 作用:允许子类在容器刷新过程中插入自定义逻辑(如启动 Web 服务器、初始化全局组件)。
问题 2:Spring Boot 如何通过 onRefresh 启动嵌入式 Tomcat?
答案:
ServletWebServerApplicationContext重写onRefresh,调用createWebServer()方法。- 通过
ServletWebServerFactory创建WebServer实例,并初始化 Servlet 上下文。
问题 3:onRefresh 与 refresh() 方法的关系是什么?
答案:
refresh()是 Spring 容器初始化的入口方法,包含 12 个标准步骤。onRefresh是refresh()流程中的一个扩展点,供子类实现特定逻辑。
问题 4:如果需要在容器启动时执行某些初始化代码,应该选择 onRefresh 还是 @PostConstruct?
答案:
onRefresh:适合容器级初始化(如启动服务),此时 Bean 尚未实例化。@PostConstruct:适合单个 Bean 的初始化逻辑(如数据库连接)。
问题 5:如何避免在 onRefresh 中阻塞主线程?
答案:
- 在
onRefresh中启动异步线程或使用 Spring 的TaskExecutor。 - 示例:
@Override protected void onRefresh() { super.onRefresh(); taskExecutor.execute(() -> initializeHeavyResource()); }
六、总结
onRefresh 是 Spring 容器刷新流程中的关键扩展点,理解其执行时机与子类实现方式,是掌握 Spring 生命周期机制的重要一环。在面试中,面试官通常会通过此方法考察候选人对 Spring 容器启动流程和扩展点设计的理解深度。实际开发中,合理利用 onRefresh 可实现高度定制化的容器初始化逻辑。