Spring IoC容器的初始化過程
Spring IoC(Inversion of Control,控制反轉(zhuǎn))容器的初始化是 Spring 框架啟動的核心過程,它負責創(chuàng)建和管理 Bean,以及處理 Bean 之間的依賴關(guān)系。
以下是 Spring IoC 容器初始化的詳細流程,結(jié)合 源碼關(guān)鍵類 和 核心步驟 拆解:
一、核心流程概覽
Spring IoC 容器初始化分為 2 大階段:
- 容器啟動準備:加載配置(XML/注解),解析成
BeanDefinition
。 - Bean 實例化與依賴注入:根據(jù)
BeanDefinition
創(chuàng)建 Bean,處理依賴、初始化。
二、詳細步驟(以ClassPathXmlApplicationContext為例)
1.容器啟動(構(gòu)造方法調(diào)用)
// 示例:創(chuàng)建 Xml 應用上下文 ApplicationContext context = new ClassPathXmlApplicationContext("applicationContext.xml");
關(guān)鍵動作:
- 調(diào)用父類構(gòu)造方法,初始化 資源加載器(
ResourceLoader
)和 ** Bean 工廠**(DefaultListableBeanFactory
)。 - 記錄配置文件路徑(如
applicationContext.xml
)。
2.加載配置文件(refresh()方法觸發(fā))
refresh()
是容器初始化的核心方法,定義在 AbstractApplicationContext
中,包含 13 個關(guān)鍵步驟(簡化版流程):
public void refresh() throws BeansException, IllegalStateException { synchronized (this.startupShutdownMonitor) { // 1. 準備刷新:記錄啟動時間、標記活躍狀態(tài)、初始化屬性源 prepareRefresh(); // 2. 創(chuàng)建 Bean 工廠(若未創(chuàng)建),并加載 BeanDefinition ConfigurableListableBeanFactory beanFactory = obtainFreshBeanFactory(); // 3. 準備 Bean 工廠:設置類加載器、后置處理器等 prepareBeanFactory(beanFactory); try { // 4. 子類擴展:允許子類修改 Bean 工廠(Spring Boot 常用) postProcessBeanFactory(beanFactory); // 5. 執(zhí)行 BeanFactoryPostProcessor:修改 BeanDefinition(如 PropertyPlaceholderConfigurer) invokeBeanFactoryPostProcessors(beanFactory); // 6. 注冊 BeanPostProcessor:用于 Bean 初始化前后增強(如 AutowiredAnnotationBeanPostProcessor) registerBeanPostProcessors(beanFactory); // 7. 初始化 MessageSource:國際化支持 initMessageSource(); // 8. 初始化 EventMulticaster:事件廣播器 initApplicationEventMulticaster(); // 9. 子類擴展:初始化特殊 Bean(如 Spring MVC 的 DispatcherServlet) onRefresh(); // 10. 注冊事件監(jiān)聽器 registerListeners(); // 11. 實例化所有非延遲加載的單例 Bean finishBeanFactoryInitialization(beanFactory); // 12. 完成刷新:發(fā)布 ContextRefreshedEvent finishRefresh(); } catch (BeansException ex) { // 13. 異常處理:銷毀已創(chuàng)建的 Bean destroyBeans(); cancelRefresh(ex); throw ex; } } }
3.關(guān)鍵步驟拆解
(1)加載BeanDefinition(步驟 2:obtainFreshBeanFactory)
作用:
- 解析配置文件(XML/注解),生成
BeanDefinition
(包含 Bean 類名、作用域、依賴等信息)。
實現(xiàn):
- XML 配置:
XmlBeanDefinitionReader
解析<bean>
標簽,生成BeanDefinition
。 - 注解配置:
ClassPathBeanDefinitionScanner
掃描@Component
、@Service
等注解,生成BeanDefinition
。
示例:
- XML 中的
<bean id="userService" class="com.example.UserService"/>
會被解析為BeanDefinition
,記錄userService
的類名、作用域(默認單例)等。
(2)處理BeanFactoryPostProcessor(步驟 5:invokeBeanFactoryPostProcessors)
作用:
- 修改
BeanDefinition
(在 Bean 實例化前)。
典型實現(xiàn):
PropertyPlaceholderConfigurer
:替換BeanDefinition
中的占位符(如${jdbc.url}
→ 實際配置值)。ConfigurationClassPostProcessor
:處理@Configuration
類,解析@Bean
方法。
示例:
- 配置文件中
<bean id="dataSource" url="${jdbc.url}"/>
,PropertyPlaceholderConfigurer
會將${jdbc.url}
替換為application.properties
中的實際值。
(3)注冊BeanPostProcessor(步驟 6:registerBeanPostProcessors)
作用:
- 注冊用于 Bean 初始化前后增強的處理器(如
AutowiredAnnotationBeanPostProcessor
處理@Autowired
)。
典型實現(xiàn):
AutowiredAnnotationBeanPostProcessor
:解析@Autowired
注解,實現(xiàn)依賴注入。AnnotationAwareAspectJAutoProxyCreator
:實現(xiàn) AOP 代理,處理@Aspect
切面。
(4)實例化單例Bean(步驟 11:finishBeanFactoryInitialization)
作用:
- 創(chuàng)建所有非延遲加載的單例 Bean(默認
lazy-init="false"
)。
實現(xiàn):
- 遍歷
BeanDefinition
,調(diào)用getBean(beanName)
創(chuàng)建 Bean。 - 處理依賴注入(
populateBean
)、初始化(initializeBean
)。
關(guān)鍵方法:
// AbstractBeanFactory.java protected <T> T doGetBean(String name, @Nullable Class<T> requiredType, @Nullable Object[] args, boolean typeCheckOnly) throws BeansException { // 1. 檢查緩存:單例 Bean 先從緩存(singletonObjects)獲取 Object sharedInstance = getSingleton(beanName); if (sharedInstance != null) { return (T) sharedInstance; } // 2. 創(chuàng)建 Bean 實例:調(diào)用構(gòu)造器/工廠方法 BeanWrapper instanceWrapper = createBeanInstance(beanName, mbd, args); // 3. 依賴注入:填充屬性(@Autowired、<property>) populateBean(beanName, mbd, instanceWrapper); // 4. 初始化:調(diào)用 @PostConstruct、init-method exposedObject = initializeBean(beanName, exposedObject, mbd); // 5. 放入緩存(單例 Bean) addSingleton(beanName, exposedObject); return (T) exposedObject; }
(5)發(fā)布ContextRefreshedEvent(步驟 12:finishRefresh)
作用:
- 通知容器已完成初始化,觸發(fā)
ApplicationListener
處理。
示例:
- Spring MVC 的
DispatcherServlet
會監(jiān)聽此事件,完成自身初始化(如加載 HandlerMapping)。
三、核心類與職責
類名 | 職責 |
---|---|
BeanDefinition | 存儲 Bean 的元數(shù)據(jù)(類名、作用域、依賴等) |
BeanFactory | 基礎 IoC 容器接口,定義 Bean 的創(chuàng)建、查找方法 |
ApplicationContext | 高級 IoC 容器接口(繼承 BeanFactory),支持 AOP、事件、國際化等 |
AbstractApplicationContext | 實現(xiàn) ApplicationContext 核心邏輯(如 refresh() 方法) |
DefaultListableBeanFactory | 默認 Bean 工廠,存儲 BeanDefinition,創(chuàng)建 Bean 實例 |
BeanPostProcessor | Bean 初始化前后增強(如 AutowiredAnnotationBeanPostProcessor) |
BeanFactoryPostProcessor | Bean 實例化前修改 BeanDefinition(如 PropertyPlaceholderConfigurer) |
四、總結(jié)
Spring IoC 容器初始化的核心是 refresh()
方法,通過以下步驟完成:
- 加載配置 → 解析為
BeanDefinition
; - 處理
BeanFactoryPostProcessor
→ 修改BeanDefinition
; - 注冊
BeanPostProcessor
→ 增強 Bean 初始化; - 實例化單例 Bean → 處理依賴注入、初始化;
- 發(fā)布事件 → 通知容器就緒。
理解這一過程,能清晰掌握 Spring 如何管理 Bean 的生命周期,以及 AOP、依賴注入的實現(xiàn)時機。
以上為個人經(jīng)驗,希望能給大家一個參考,也希望大家多多支持腳本之家。
相關(guān)文章
Java中為什么start方法不能重復調(diào)用而run方法可以?
這篇文章主要介紹了Java中為什么start方法不能重復調(diào)用而run方法可以?帶著疑問一起學習下面文章的詳細內(nèi)容吧2022-05-05基于SpringBoot和Vue3的博客平臺的用戶注冊與登錄功能實現(xiàn)
本教程將指導您如何使用Spring?Boot和Vue3實現(xiàn)用戶注冊與登錄功能。我們將使用Spring?Boot作為后端框架,Vue3作為前端框架,同時使用MySQL作為數(shù)據(jù)庫,感興趣的朋友可以參考一下2023-04-04