SpringIOC源碼解析(上)
一、什么是SpringIOC
spring ioc指的是控制反轉(zhuǎn)懈糯,IOC容器負(fù)責(zé)實例化涤妒、定位、配置應(yīng)用程序中的對象及建立這些對象間的依賴昂利。交由Spring容器統(tǒng)一進行管理届腐,從而實現(xiàn)松耦合。
二蜂奸、SpringIOC源碼解析
在開始之前我們先通過一個簡單的示意圖來了解一下大概的一個流程
?
從示意圖可以看出犁苏,當(dāng)web容器啟動的時候,spring的全局bean的管理器會去xml配置文件中掃描的包下面獲取到所有的類扩所,并根據(jù)你使用的注解围详,進行對應(yīng)的封裝,封裝到全局的bean容器中進行管理祖屏,一旦容器初始化完畢助赞,beanID以及bean實例化的類對象信息就全部存在了袁勺,現(xiàn)在我們需要在某個service里面調(diào)用另一個bean的某個方法的時候雹食,我們只需要依賴注入進來另一個bean的Id即可,調(diào)用的時候期丰,spring會去初始化完成的bean容器中獲取即可群叶,如果存在就把依賴的bean的類的實例化對象返回給你吃挑,你就可以調(diào)用依賴的bean的相關(guān)方法或?qū)傩缘龋?/p>
本文會分析Spring的IOC模塊的整體流程,分析過程需要使用一個簡單的demo工程來啟動Spring街立,需要的童鞋可自行下載
https://github.com/cjinjun/spring-framework-demo
工程示例代碼
寫一個簡單的接口和接口實現(xiàn)類
public interface IOCService {
? ? String helloIoc();
}
public class IOCServiceImpl implements IOCService {
? ? @Override
? ? public String helloIoc() {
? ? ? ? return "Hello,IOC";
? ? }
}
新建一個application-ioc.xml
<?xml version="1.0" encoding="UTF-8" ?>
<beans xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
? ? ? xmlns="http://www.springframework.org/schema/beans"
? ? ? xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd" default-autowire="byName">
? ? <bean id="iocService" class="com.jinjun.demo.ioc.service.impl.IOCServiceImpl"/>
</beans>
啟動spring
public class IOCDemo {
public static void main (String args[]){
ApplicationContext context =new ClassPathXmlApplicationContext("classpath:application-ioc.xml");
? ? ? ? IOCService iocService=context.getBean(IOCService.class);
? ? ? ? System.out.println(iocService.helloIoc());
? ? }
}
ClassPathXmlApplicationContext
在看具體源碼之前先看一下這兄弟的類圖
?
最下邊ClassPathXmlApplicationContext就是咱們今天要擼的舶衬、分析的主角。
看一下這個類的源碼
?
里邊的方法基本上都是重載方法赎离,整體來看源碼也比較簡單只有setConfigLocations和refresh兩個方法沒有看到具體的實現(xiàn)逛犹。但是如果你因為這個而小瞧了Spring那可就大錯特錯了,setConfigLocations只是一個開胃小菜梁剔,refresh才是核心重點虽画。
setConfigLocations方法的主要工作有兩個:創(chuàng)建環(huán)境對象ConfigurableEnvironment和處理ClassPathXmlApplicationContext傳入的字符串中的占位符
?
?
?
這里的getEnironment就涉及到創(chuàng)建環(huán)境變量的操作。
這個接口ConfigurableEnvironment比較重要的就是兩部分內(nèi)容了憾朴,一個是設(shè)置Spring的環(huán)境就是我們經(jīng)常用的spring.profile配置狸捕。另外就是系統(tǒng)資源Property。
接著看`createEnvironment()`方法众雷,發(fā)現(xiàn)它返回了一個`StandardEnvironment`類灸拍,而這個類中的`customizePropertySources`方法就會往資源列表中添加Java進程中的變量和系統(tǒng)的環(huán)境變量
?
?
處理占位符
再次回到 `resolvePath`方法后跟進通過上方獲取的`ConfigurableEnvironment`接口的`resolveRequiredPlaceholders`方法,終點就是下方的這個方法砾省。這個方法主要就是處理所有使用${}方式的占位符
開胃小菜已經(jīng)說完了鸡岗,現(xiàn)在才是本文重中之重refresh
refresh
方法內(nèi)容比較多,以下將用較長的篇幅來解析說明這個方法编兄,童鞋們可以提前做好心里準(zhǔn)備轩性。
先看一下refresh方法里邊內(nèi)容
public void refresh()throws BeansException, IllegalStateException {
synchronized (this.startupShutdownMonitor) {
// Prepare this context for refreshing.
? ? ? prepareRefresh();
? ? ? // Tell the subclass to refresh the internal bean factory.
? ? ? ConfigurableListableBeanFactory beanFactory = obtainFreshBeanFactory();
? ? ? // Prepare the bean factory for use in this context.
? ? ? prepareBeanFactory(beanFactory);
? ? ? try {
// Allows post-processing of the bean factory in context subclasses.
? ? ? ? postProcessBeanFactory(beanFactory);
? ? ? ? // Invoke factory processors registered as beans in the context.
? ? ? ? invokeBeanFactoryPostProcessors(beanFactory);
? ? ? ? // Register bean processors that intercept bean creation.
? ? ? ? registerBeanPostProcessors(beanFactory);
? ? ? ? // Initialize message source for this context.
? ? ? ? initMessageSource();
? ? ? ? // Initialize event multicaster for this context.
? ? ? ? initApplicationEventMulticaster();
? ? ? ? // Initialize other special beans in specific context subclasses.
? ? ? ? onRefresh();
? ? ? ? // Check for listener beans and register them.
? ? ? ? registerListeners();
? ? ? ? // Instantiate all remaining (non-lazy-init) singletons.
? ? ? ? finishBeanFactoryInitialization(beanFactory);
? ? ? ? // Last step: publish corresponding event.
? ? ? ? finishRefresh();
? ? ? }
catch (BeansException ex) {
if (logger.isWarnEnabled()) {
logger.warn("Exception encountered during context initialization - " +
"cancelling refresh attempt: " + ex);
? ? ? ? }
// Destroy already created singletons to avoid dangling resources.
? ? ? ? destroyBeans();
? ? ? ? // Reset 'active' flag.
? ? ? ? cancelRefresh(ex);
? ? ? ? // Propagate exception to caller.
? ? ? ? throw ex;
? ? ? }
finally {
// Reset common introspection caches in Spring's core, since we
// might not ever need metadata for singleton beans anymore...
? ? ? ? resetCommonCaches();
? ? ? }
}
}
看著東西是不是比較多,容易懵狠鸳?不要慌揣苏,咱們一步一步分析。與它死磕到底件舵,不研究明白不罷休卸察。
第一行 synchronized 這個關(guān)鍵字作用我就不多說了把,如果想深入了解可以自行百度铅祸,在這里為了避免`refresh()` 還沒結(jié)束坑质,再次發(fā)起啟動或者銷毀容器引起的沖突
`prepareRefresh()` 從字面意思來看說 “預(yù)準(zhǔn)備refresh" 主要做一些準(zhǔn)備工作,記錄容器的啟動時間临梗、標(biāo)記“已啟動”狀態(tài)涡扼、檢查環(huán)境變量等
`obtainFreshBeanFactory()` 乍一看這個方法也沒幾行代碼,但是這個方法在執(zhí)行refreshBeanFactory時候創(chuàng)建一個默認(rèn)的BeanFactory:DefaultListableBeanFactory盟庞,并加載BeanDefinition吃沪。
prepareBeanFactory(beanFactory),為beanFactory設(shè)置一些屬性如ClassLoader,BeanExpressionResolver,PropertyEditorRegistrar,BeanPostProcessor等
postProcessBeanFactory()這個比較簡單什猖,是Spring的一個擴展點,如果有Bean實現(xiàn)了BeanFactoryPostProcessor接口巷波,那么在容器初始化以后萎津,Spring 會負(fù)責(zé)調(diào)用里面的 postProcessBeanFactory 方法
invokeBeanFactoryPostProcessors(beanFactory),為beanFactory注冊BeanFactoryPostProcessor
registerBeanPostProcessors(beanFactory)抹镊,注冊當(dāng)Bean創(chuàng)建時候的BeanPostProcessor
initMessageSource()初始化上下文的消息源:DelegatingMessageSource
initApplicationEventMulticaster()初始化了一個事件傳播器:SimpleApplicationEventMulticaster
`onRefresh()` 又是一個擴展點,子類可以在這里來做一些想做的事情
registerListeners()獲取ApplicationListener荤傲,并在事件傳播器中注冊他們
finishBeanFactoryInitialization(beanFactory)垮耳,獲取LoadTimeWeaverAware并初始化他們,初始化單例并且非懶加載的Bean
finishRefresh()完成refresh Context操作遂黍,初始化LifecycleProcessor并start终佛,發(fā)布ContextRefreshedEvent事件
resetCommonCaches()主要是清理緩存
一個ClassPathXmlApplicationContext的初始化過程基本如上,詳細(xì)的BeanDefinition加載過程雾家,獲取Bean操作期待下篇铃彰。