自定義SpringIOC(理論分析)
上一篇:設計模式開源實戰:觀察者模式不知道怎么用?手撕Spring源碼中跟著大佬學編程
上一篇我們研究了大佬在Spring源碼中使用的觀察者模式,今天我們再來聊聊Spring的核心功能——Sping IOC容器,最終我們跟著大佬的思路實現一個屬于自己的IOC容器!Start Go!
Spring IOC核心組件
1) BeanFactory
BeanFactory作為最頂層的一個接口,定義了IoC容器的基本功能規范。
從類圖中我們可以發現最終的默認實現類是DefaultListableBeanFactory
,它實現了所有的接口。那么為何要定義這么多層次的接口呢?
每個接口都有它的使用場合,主要是為了區分在 Spring 內部操作過程中對象的傳遞和轉化,對對象的數據訪問所做的限制。
例如,
ListableBeanFactory
接口表示這些 Bean 可列表化。HierarchicalBeanFactory
表示這些 Bean 是有繼承關系的,也就是每個 Bean 可能有父 BeanAutowireCapableBeanFactory
接口定義 Bean 的自動裝配規則。
這三個接口共同定義了 Bean 的集合、Bean 之間的關系及 Bean 行為。
在 BeanFactory 里只對 IOC 容器的基本行為做了定義,根本不關心你的 Bean 是如何定義及怎樣加載的。正如我們只關心能從工廠里得到什么產品,不關心工廠是怎么生產這些產品的。
2 ) ApplicationContext
BeanFactory 有一個很重要的子接口,就是 ApplicationContext 接口,該接口主要來規范容器中的 bean 對象是非延時加載,即在創建容器對象的時候就對象 bean 進行初始化,并存儲到一個容器中。
//延時加載
BeanFactory factory = new XmlBeanFactory(new ClassPathResource("bean.xml"));//立即加載
ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext("bean.xml");
User user = context.getBean("user", User.class);
ApplicationContext 的子類主要包含兩個方面:
-
ConfigurableApplicationContext 表示該 Context 是可修改的,也就是在構建 Context 中用戶可以動態添加或修改已有的配置信息
-
WebApplicationContext 顧名思義,就是為 web 準備的 Context 他可以直接訪問到 ServletContext,通常情況下,這個接口使用少
要知道工廠是如何產生對象的,我們需要看具體的 IOC 容器的實現,Spring 提供了許多 IOC 容器實現,比如:
- ClasspathXmlApplicationContext : 根據類路徑加載 xml 配置文件,并創建 IOC 容器對象。
- FileSystemXmlApplicationContext :根據系統路徑加載 xml 配置文件,并創建 IOC 容器對象。
- AnnotationConfigApplicationContext :加載注解類配置,并創建 IOC 容器。
總體來說 ApplicationContext 必須要完成以下幾件事。
- 標識一個應用環境
- 利用 BeanFactory 創建 Bean 對象
- 保存對象關系表
- 能夠捕獲各種事件
3) Bean定義:BeanDefinition
這里的 BeanDefinition 就是我們所說的 Spring 的 Bean,我們自己定義的各個 Bean 其實會轉換成一個個 BeanDefinition 存在于 Spring 的 BeanFactory 中。
public class DefaultListableBeanFactory extends AbstractAutowireCapableBeanFactoryimplements ConfigurableListableBeanFactory, BeanDefinitionRegistry, Serializable {//DefaultListableBeanFactory 中使用 Map 結構保存所有的 BeanDefinition 信息private final Map<String, BeanDefinition> beanDefinitionMap = new ConcurrentHashMap<>(256);
}
BeanDefinition 中保存了我們的 Bean 信息,比如這個 Bean 指向的是哪個類、是否是單例的、是否懶加載、這個 Bean 依賴了哪些 Bean 等等。
4) BeanDefinitionReader
Bean 解析過程非常復雜,功能被分得很細,因為這里需要被擴展的地方很多,必須保證足夠的靈活性,以應對可能的變化。Bean的解析主要就是對 Spring 配置文件的解析。
這個解析過程主要通過 BeanDefinitionReader 來完成,看看 Spring 中 BeanDefinitionReader 的類結構圖,如下圖所示。
BeanDefinitionReader 接口定義的功能
public interface BeanDefinitionReader {/*下面的loadBeanDefinitions都是加載bean定義,從指定的資源中*/int loadBeanDefinitions(Resource resource) throws BeanDefinitionStoreException;int loadBeanDefinitions(Resource... resources) throws BeanDefinitionStoreException;int loadBeanDefinitions(String location) throws BeanDefinitionStoreException;int loadBeanDefinitions(String... locations) throws BeanDefinitionStoreException;
}
5) BeanFactory后置處理器
后置處理器是一種拓展機制,貫穿Spring Bean的生命周期
后置處理器分為兩類:
BeanFactory后置處理器:BeanFactoryPostProcessor
實現該接口,可以在spring的bean創建之前,修改bean的定義屬性
public interface BeanFactoryPostProcessor {/** 該接口只有一個方法postProcessBeanFactory,方法參數是ConfigurableListableBeanFactory,通過該參數,可以獲取BeanDefinition*/void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) throws BeansException;
}
6) Bean后置處理器:BeanPostProcessor
BeanPostProcessor是Spring IOC容器給我們提供的一個擴展接口
實現該接口,可以在spring容器實例化bean之后,在執行bean的初始化方法前后,添加一些處理邏輯
public interface BeanPostProcessor {//bean初始化方法調用前被調用Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException;//bean初始化方法調用后被調用Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException;
}
IOC流程圖
- 容器環境的初始化(系統、JVM 、解析器、類加載器等等)
- Bean 工廠的初始化( IOC 容器首先會銷毀舊工廠,舊 Bean 、創建新的工廠)
- 讀取:通過 BeanDefinitonReader 讀取我們項目中的配置(application.xml)
- 定義:通過解析 xml 文件內容,將里面的 Bean 解析成 BeanDefinition(未實例化、未初始化)
- 將解析得到的 BeanDefinition ,存儲到工廠類的Map容器中
- 調用 BeanFactoryPostProcessor 該方法是一種功能增強,可以在這個步驟對已經完成初始化的 BeanFactory 進行屬性覆蓋,或是修改已經注冊到 BeanFactory 的 BeanDefinition
- 通過反射實例化 bean 對象
- 進入到 Bean 實例化流程,首先設置對象屬性
- 檢查 Aware 相關接口,并設置相關依賴
- 前置處理器,執行 BeanPostProcesser 的before 方法對 bean 進行擴展
- 檢查是否有實現 initializingBean 回調接口,如果實現就要回調其中的 AftpropertiesSet() 方法,(通過可以完成一些配置的加載)
- 檢查是否有配置自定義的 init-method ,
- 后置處理器執行 BeanPostProcesser 的after 方法 --> AOP 就是在這個階段完成的, 在這里判斷 bean 對象是否實現接口,實現就使用 JDK 代理,否則選擇 CGLIB
- 對象創建完成,添加到BeanFactory的單例池中。
往期回顧
設計模式開源實戰:觀察者模式不知道怎么用?手撕Spring源碼中跟著大佬學編程
設計模式開源實戰:大佬是怎么使用工廠模式的?來看看Spring中工廠模式的應用就知道了