Spring容器技術內幕
1.內部工作機制
Spring的AbstractApplicationContext是ApplicationContext的抽象實現類,該抽象類的reflesh方法定義了Spring容器在加載配置文件後的各項處理過程,這些處理過程清晰地刻畫了Spring容器啓動時所執行的各項操作,方法如下所示:
public void refresh() throws BeansException, IllegalStateException {
synchronized(this.startupShutdownMonitor) {
this.prepareRefresh();
// 1.初始化bean工廠
ConfigurableListableBeanFactory beanFactory = this.obtainFreshBeanFactory();
this.prepareBeanFactory(beanFactory);
try {
this.postProcessBeanFactory(beanFactory);
// 2.調用工廠後處理器
this.invokeBeanFactoryPostProcessors(beanFactory);
// 3.註冊bean後處理器
this.registerBeanPostProcessors(beanFactory);
// 4.初始化消息源
this.initMessageSource();
// 5.初始化應用上下文事件廣播器
this.initApplicationEventMulticaster();
// 6.初始化其他特殊的bean,有 具體子類實現
this.onRefresh();
// 7.註冊事件監聽器
this.registerListeners();
// 8.初始化所有單實例的bean,使用懶加載模式的bean除外
this.finishBeanFactoryInitialization(beanFactory);
// 9.完成刷新併發布容器刷新事件
this.finishRefresh();
} catch (BeansException var9) {
this.logger.warn("Exception encountered during context initialization - cancelling refresh attempt", var9);
this.destroyBeans();
this.cancelRefresh(var9);
throw var9;
} finally {
this.resetCommonCaches();
}
}
}
- 初始化BeanFactory:根據配置文件實例化BeanFactory,在obtainFreshBeanFactory()方法中,首先調用refleshBeanFactory方法刷新BeanFactory,然後調用getBeanFactory()方法獲取BeanFactory,這兩個方法都是由具體子類實現的 。在這一步,Spring將配置文件的信息裝入容器的Bean定義註冊表(BeanDefinitionRegistry)中,但此時Bean還未初始化
- 調用工廠後處理器:根據反射機制從BeanDefinitionRegistry中找出所有實現了BeanFactoryPostProcessor接口的bean,並調用其postProcessBeanFactory方法接口方法。
- 註冊bean後處理器:根據反射機制從BeanDefinitionRegistry中找出所有實現類BeanPostProcessor接口的bean,並將它們註冊到容器Bean後處理器的註冊表中
- 初始化消息源:初始化容器的國際化消息資源
- 初始化應用上下文事件廣播器
- 初始化其他特殊的bean:這是一個鉤子方法,子類可以藉助這個方法執行一些特殊的操作,如AbstractRefreshableWebApplicationContext就使用執行初始化ThemeSource的 操作
- 註冊事件監聽器
- 初始化所有單實例的bean,使用懶加載模式的bean除外:初始化bean後,將他們放在Spring的容器緩存池中
- 發佈上下文刷新事件:創建上下文刷新事件,事件廣播器負責將這些事件廣播到每個註冊的事件監聽器中
2.Spring從加載配置文件到創建一個完整的bean的作業流程
- ResourceLoader從存儲介質中加載Spring配置信息,並使用Resource表示這個配置文件的資源
- BeanDefinitionReader讀取Resource所指向的配置文件資源,然後解析配置文件。配置文件中的每個bean解析成一個BeanDefinition對象,並保存到BeanDefinitionRegistry中
- 容器掃描BeanDefinitionRegistry中的BeanDefinition,使用java反射機制自動識別出Bean工廠後處理器(實現了BeanFactoryPostProcessor接口的bean),然後調用這些bean工廠後處理器對BeanDefinitionRegistry中的BeanDefinition進行加工處理主要完成一下 兩項工作
- 對使用佔位符的<bean>元素標籤進行解析,得到最終的配置值。這意味着對一些半成品的BeanDefinition對象進行加工處理並得到成品的BeanDefinition對象
- 對BeanDefinitionRegistry中的BeanDefinition進行掃描,通過java反射機制找到所有的屬性編輯器的bean(實現了java.beans.PropertyEditor接口),並自動將它們註冊到Spring容器的屬性編輯器註冊表中(PropertyEditorRegistry)
- spring從BeanDefinitionRegistry中去除加工後的BeanDefinition,並調用InstantiationStrategy着手進行bean的實例化工作
- 在實例化bean時,Spring容器使用BeanWrapper對bean進行 封裝,BeanWrapper提供了以java反射操作bean的方法,它將結合該bean的BeanDefinition和容器中的屬性編輯器,完成bean的注入工作
- 利用容器中註冊的bean後處理器(實現了BeanPostProcessor)對已經完成屬性設置工作的bean進行後續加工,直接裝配出一個準備就緒的bean