Spring 源码解析:onRefresh 方法深度剖析与高频面试题解析

164 阅读3分钟

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();
    }
}

五、高频面试题与答案

问题 1onRefresh 方法的调用时机是什么?它的作用是什么?
答案

  • 调用时机:在 BeanFactory 初始化完成之后,单例 Bean 实例化之前。
  • 作用:允许子类在容器刷新过程中插入自定义逻辑(如启动 Web 服务器、初始化全局组件)。

问题 2:Spring Boot 如何通过 onRefresh 启动嵌入式 Tomcat?
答案

  • ServletWebServerApplicationContext 重写 onRefresh,调用 createWebServer() 方法。
  • 通过 ServletWebServerFactory 创建 WebServer 实例,并初始化 Servlet 上下文。

问题 3onRefreshrefresh() 方法的关系是什么?
答案

  • refresh() 是 Spring 容器初始化的入口方法,包含 12 个标准步骤。
  • onRefreshrefresh() 流程中的一个扩展点,供子类实现特定逻辑。

问题 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 可实现高度定制化的容器初始化逻辑。