Spring-IOC容器隨筆

前言

這篇文章,我打算對我認(rèn)知的ioc容器做一個總結(jié)。方便大家也來了解一下ioc容器,以便于激起大家求知的欲望而自己去翻閱ioc容器的源碼。如果有錯誤的地方,也請不吝指正,共同進(jìn)步。

ioc容器何時被創(chuàng)建

1、第一種方式,容器啟動

容器啟動的話,我們都知道容器中web.xml的載體是ServletContext,web.xml中可以配置listener來監(jiān)聽容器的啟動。如果我們想使用spring,那么就需要配置ContextLoaderListener,這是spring啟動的入口,容器啟動的時候,觸發(fā)listener-class的創(chuàng)建,調(diào)用contextInitialized()方法,在ContextLoaderListener的contextInitialized()方法總最終會調(diào)用AbstractApplicationContext.refresh(),開始容器的創(chuàng)建。

2、第二種方式,springboot啟動

springboot啟動稍微簡單一點(diǎn),啟動的入門在啟動類的run方法里,run方法里會調(diào)用refreshContext(context)進(jìn)行容器的啟動,最終還是調(diào)用AbstractApplicationContext.refresh()。

擴(kuò)展點(diǎn)

ApplicationContextInitializer

在spring初始化應(yīng)用上下文ApplicationContext的時候,可以實(shí)現(xiàn)ApplicationContextInitializer接口,來對應(yīng)用上下文進(jìn)行擴(kuò)展。例如添加一個beanFactoryPostProcessor。這是spring的第一個擴(kuò)展點(diǎn)。例如:

@Slf4j
public class MyApplicationContextInitializer implements ApplicationContextInitializer<ConfigurableApplicationContext> {

    @Override
    public void initialize(ConfigurableApplicationContext applicationContext) {
        FirstBeanDefinitionRegistryPostProcessor processor = new FirstBeanDefinitionRegistryPostProcessor();
        applicationContext.addBeanFactoryPostProcessor(processor);
        log.info("自定義BeanDefinitionRegistryPostProcessor已加載進(jìn)spring上下文");
    }
}
# 在yml或者propeties配置一下
context:
  initializer:
    classes: com.yameng.spring.beanFactoryPostPrecessors.MyApplicationContextInitializer

這樣就可以在上下文初始化的時候,把我們自定義的FirstBeanDefinitionRegistryPostProcessor加載進(jìn)beanFactoryPostPrecessors緩存。
這里有個問題。在初始化的時候,spring是怎么找到我們自定義的MyApplicationContextInitializer并執(zhí)行initialize()方法的。答案就是,其實(shí)spring在配置上下文環(huán)境的時候,會去所有的propertyResolver中尋找key為context.initializer.classes的value,這個context.initializer.classes就是我們在配置文件中配置的key。
spring提供的所有的擴(kuò)展點(diǎn),幾乎都是這么實(shí)現(xiàn)的(總結(jié)下來就是,你擴(kuò)展的類實(shí)現(xiàn)了擴(kuò)展的接口,要么以固定的key配置在配置文件里,要么帶上spring的官方注解被掃描加載到beanDefinitionMaps緩存里,然后spring根據(jù)接口的類型去beanDefinitionMaps輪詢獲?。?br> 我們前文這個擴(kuò)展的例子,因?yàn)樯舷挛某跏蓟臅r候,BeanFactory還沒有創(chuàng)建,所以我們只能采用第一種方式,也就是配置在配置文件的形式。

ImportBeanDefinitionRegistrar

@Slf4j
public class MyImportBeanDefinitionRegistrar implements ImportBeanDefinitionRegistrar {

    @Override
    public void registerBeanDefinitions(AnnotationMetadata importingClassMetadata, BeanDefinitionRegistry registry) {
      log.info("MyImportBeanDefinitionRegistrar.registerBeanDefinitions is run");
    }
}
@Configuration
@Import(MyImportBeanDefinitionRegistrar.class)
public class DemoConfig {
}

這也是ioc容器里一個比較重要的拓展點(diǎn), 在spring的bean上,使用@Import注解注冊一個ImportBeanDefinitionRegistrar,就可以在registerBeanDefinitions方法里注冊一些自己的bean定義。我一般是用來給某些bean注冊一些依賴的類和屬性。
看到這里,需要弄明白一個問題:ImportBeanDefinitionRegistrar的加載原理,什么時候被調(diào)用。
首先,MyImportBeanDefinitionRegistrar是依賴于DemoConfig,是在DemoConfig被注冊到beanDefinitionMaps的時候被調(diào)用的,DemoConfig被掃描到是因?yàn)橛蠤Configuration注解。所以一個大概流程就是:
當(dāng)掃描@Configuration注解的時候,掃描到了DemoConfig,然后把DemoConfig封裝成ConfigurationClass,然后發(fā)現(xiàn)這個類有@Impot注解,拿到@impot注解里的類,發(fā)現(xiàn)是ImportBeanDefinitionRegistrar類型,放到ConfigurationClass的importBeanDefinitionRegistrars屬性里,這是一個map,然后遍歷調(diào)用registerBeanDefinitions()方法。
我沒有講的很仔細(xì),你需要自己弄明白,什么時候去掃描@Configuration注解,哪個類干的這個活,在ioc的哪個流程里。自己擼一擼源碼就明白了,后面有時間我會內(nèi)容補(bǔ)充進(jìn)來。
后續(xù)我會做一個ioc容器的流程圖,哪些擴(kuò)展點(diǎn)在哪個環(huán)節(jié)。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容