Spring-IOC原始碼淺析

Google愛喝茶發表於2018-09-29

試著把自己看原始碼對一些理解寫下來 從相對巨集觀的角度去分析整個過程碼

還是從經典的例子開始入手

private void applicationEntrance(){
        ApplicationContext context = new FileSystemXmlApplicationContext("classpath:applicationContext.xml");
        context.getBean("account");
    }

public ClassPathXmlApplicationContext(String[] configLocations, boolean refresh, ApplicationContext parent){
    super(parent);
    setConfigLocations(configLocations);
    if (refresh) {
        refresh();
    }
}
複製程式碼

要開車了,坐穩了,我們逐步進行分析
首先呼叫new FileSystemXmlApplicationContext(xml)方法,最後發現方法來到了refresh()方法,這個可以一個大名鼎鼎的方法,凡是看過或者嘗試看過spring原始碼對同學應該都對這個方法不陌生,這是一個標準的模板方法模式,由父類指定整個程式碼的執行邏輯,由子類去決定每個方法的具體實現。額,還是上程式碼吧重要的地方會寫註釋

refresh()
    //applicaitonContext其實就是高配版本的Beanfactory所以很多工作還是要BeanFactory來做
    //去初始化beanFactory,包括1)讀取xml,2)將xml中的bean轉為beanDefination,3)並註冊到容器中
     1)obtainFreshBeanFactory()
        refreshBeanFactory()
            //建立BeanFactory
            createBeanFactory()
            loadBeanDefinitions(beanFactory)
                loadBeanDefinitions(demo.xml)
                    1.讀取配置檔案
                        //將配置檔案抽象為resource
                        resourceLoader.load(String confLocation)
                        容器讀取resource
                    2.將配置檔案中的bean轉為spring中的格式BeanDefination並註冊到容器中
                        //將resource轉為document
                        Document doc = doLoadDocument(inputSource, resource)
                            //獲取xml的驗證模式
                            getValidationModeForResource(resource)
                                判斷是DTD or XSD(根據是否具有DOCTYPE)
                            //對xml進行解析獲取document(根據驗證模式)
                            this.documentLoader.loadDocument(inputSource, getEntityResolver(), this.errorHandler,getValidationModeForResource(resource),isNamespaceAware());
                        //註冊beanDefination  
                        registerBeanDefinitions(doc, resource)  
                            將document轉為beanDefination
                                根據element進行構造
                            對beanDefination進行校驗
                            //beanName-BeanDefinition存放在Map<String, BeanDefinition> beanDefinitionMap
                            this.beanDefinitionMap.put(beanName, beanDefinition);
    //大佬在這裡被呼叫,唯一可以插手容器啟動階段的一個bean,可以對beanDefinition進行修改
    //對該型別bean會提前執行BeanFactory.getBean()
    2)invokeBeanFactoryPostProcessors()
    //註冊BeanPostProcessor
    //真正幹活的還是beanFactory = =!
    3)registerBeanPostProcessors(beanFactory)
    //例項化所有單例懶載入beans
    4)finishBeanFactoryInitialization(beanFactory) 
        遍歷 beanDefinitionMap找到單例非抽象懶載入的bean呼叫BeanFactory的getBean(beanName)   
            單例bean先從緩衝中讀取,如果沒有才去建立;反之直接返回
            獲取depend-on到bean先去對這些bean呼叫getBean()
            //以單例bean為例子
            createBean()
                //這裡要和postProcessBeforeInitialization區分
                InstantiationAwareBeanPostProcessor#postProcessBeforeInstantiation,如果這裡返回的bean非空那麼直接return(短路了)
                //核心類 AbstractAutowireCapableBeanFactory
                //核心方法,建立bean->填充->初始化
                doCreateBean(beanName,beanDefination,args)
                    //建立bean的例項並用BeanWrapper包裹
                    1、createBeanInstance(beanName, mbd, args) 
                        instantiateBean(beanName, mbd)
                            //策略模式決定如何例項化bean cglib or reflect
                            //反射策略居然是cglib策略的父類= =!
                            //對於look-up之類的功能需要cglib來支援
                            getInstantiationStrategy().instantiate(mbd, beanName, parent)
                            BeanWrapper bw = new BeanWrapperImpl(beanInstance);
                            initBeanWrapper(bw);
                            return bw
                    //對BeanWrapper進行屬性填充
                    2、populateBean(beanName, mbd, instanceWrapper)
                        先去從BeanDefination中獲取property屬性放到pv中
                        InstantiationAwareBeanPostProcessor#postProcessAfterInstantiation
                        程式碼來到了byName byType
                            //注意beanDefination中的pv僅僅表示配置的屬性,而非全屬性
                            以byName為例,先去遍歷已經例項化的beanWrapper中的set/is開頭的方法
                            再去判斷這個屬性是否是一個bean,如果是將對應的bean放到pv中稍後一起填充
                        InstantiationAwareBeanPostProcessor#postProcessPropertyValues
                        //屬性填充
                        applyPropertyValues(beanName, mbd, bw, pvs)
                            這裡有個地方之前都沒有注意過,假如beanA需要beanB的注入這時候注入對B是一份深拷貝
                            BeanWrapperImpl#setPropertyValue(PropertyTokenHolder tokens, PropertyValue pv)方法對例項進行屬性填充
                    //初始化bean
                    3、initializeBean(beanName, exposedObject, mbd)
                        //這裡對實現各種aware結尾介面的相關屬性進行注入
                        invokeAwareMethods(beanName, bean)
                        //beanPostProcessor的前置方法
                        applyBeanPostProcessorsBeforeInitialization
                        //呼叫bean的初始化方法
                        invokeInitMethods(beanName, wrappedBean, mbd)
                            先執行InitializingBean型別的bean都afterPropertiesSet()方法
                            再執行<bean init-method>
                        //beanPostProcessor的後置方法
                        applyBeanPostProcessorsAfterInitialization
                    //註冊DisposableBean和<destroy-bean>
                    4、registerDisposableBeanIfNecessary
複製程式碼

AbstractAutowireCapableBeanFactory這個類是很重要的一個類

相關文章