Spring Ioc 源碼分析(一)--Spring Ioc容器的加載

1.目標(biāo):熟練使用spring,并分析其源碼,了解其中的思想。這篇主要介紹spring ioc 容器的加載
2.前提條件:會(huì)使用debug
3.源碼分析方法:Intellj idea debug 模式下源碼追溯
通過(guò)ClassPathXmlApplicationContext 進(jìn)行xml 件的讀取,從每個(gè)堆棧中讀取程序的運(yùn)行信息
4.注意:由于Spring的類(lèi)繼承體系比較復(fù)雜,不能全部貼圖,所以只將分析源碼之后發(fā)現(xiàn)的最主要的類(lèi)繼承結(jié)構(gòu)類(lèi)圖貼在下方。
5.關(guān)于Spring Ioc Demo:我們從demo入手一步步進(jìn)行代碼追溯。

1.Spring Ioc Demo


1.定義數(shù)據(jù)訪問(wèn)接口IUserDao.java

public interface IUserDao {  
    public void InsertUser(String username,String password);
}

2.定義IUserDao.java實(shí)現(xiàn)類(lèi)IUserDaoImpl.java

public class UserDaoImpl implements IUserDao {    
    @Override    
    public void InsertUser(String username, String password) { 
        System.out.println("----UserDaoImpl --addUser----");    
    }
}

3.定義業(yè)務(wù)邏輯接口UserService.java

public interface UserService {    
    public void addUser(String username,String password);
}

4.定義UserService.java實(shí)現(xiàn)類(lèi)UserServiceImpl.java

public class UserServiceImpl implements UserService {    
    private     IUserDao  userDao;    //set方法  
    public void  setUserDao(IUserDao  userDao) {        
        this.userDao = userDao;   
    }    
    @Override    
    public void addUser(String username,String password) { 
        userDao.InsertUser(username,password);    
    }
}

bean.xml配置文件

<beans xmlns="http://www.springframework.org/schema/beans"  
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"    
   xsi:schemaLocation="http://www.springframework.org/schema/beans  
http://www.springframework.org/schema/beans/spring-beans-3.0.xsd         ">  
 <!--id名字自己取,class表示他代表的類(lèi),如果在包里的話需要加上包名-->    
 <bean id="userService"  class="UserServiceImpl" >      
        <!--property代表是通過(guò)set方法注入,ref的值表示注入的內(nèi)容-->
        <property  name="userDao"  ref="userDao"/>  
 </bean>    
  <bean id="userDao"  class="UserDaoImpl"/>
</beans>

2.ApplicationContext 繼承結(jié)構(gòu):


1.頂層接口:ApplicationContext
2.ClassPathXmlApplicationContext實(shí)現(xiàn)類(lèi)繼承AbstractXmlApplication 抽象類(lèi)
3.AbstractXmlApplication 繼承AbstractRefreshableConfigApplicationContext
4.AbstractRefreshableConfigApplicationContext抽象類(lèi)繼承AbstractRefreshableApplicationContext
5.AbstractRefreshableApplicationContext 繼承 AbstractApplicationContext
6.AbstractApplicationContext 實(shí)現(xiàn)ConfigurableApplicationContext 接口
7.ConfigurableApplicationContext 接口繼承
ApplicationContext接口
總體來(lái)說(shuō)繼承實(shí)現(xiàn)結(jié)構(gòu)較深,內(nèi)部使用了大量適配器模式。
以ClassPathXmlApplicationContext為例,繼承類(lèi)圖如下圖所示:


Spring ioc .png

3.Spring Ioc容器加載過(guò)程源碼詳解


在開(kāi)始之前,先介紹一個(gè)整體的概念。即spring ioc容器的加載,大體上經(jīng)過(guò)以下幾個(gè)過(guò)程:
資源文件定位、解析、注冊(cè)、實(shí)例化

1.資源文件定位
其中資源文件定位,一般是在ApplicationContext的實(shí)現(xiàn)類(lèi)里完成的,因?yàn)锳pplicationContext接口繼承ResourcePatternResolver 接口,ResourcePatternResolver接口繼承ResourceLoader接口,ResourceLoader其中的getResource()方法,可以將外部的資源,讀取為Resource類(lèi)。


2.解析DefaultBeanDefinitionDocumentReader,
解析主要是在BeanDefinitionReader中完成的,最常用的實(shí)現(xiàn)類(lèi)是XmlBeanDefinitionReader,其中的loadBeanDefinitions()方法,負(fù)責(zé)讀取Resource,并完成后續(xù)的步驟。ApplicationContext完成資源文件定位之后,是將解析工作委托給XmlBeanDefinitionReader來(lái)完成的
解析這里涉及到很多步驟,最常見(jiàn)的情況,資源文件來(lái)自一個(gè)XML配置文件。首先是BeanDefinitionReader,將XML文件讀取成w3c的Document文檔。
DefaultBeanDefinitionDocumentReader對(duì)Document進(jìn)行進(jìn)一步解析。然后DefaultBeanDefinitionDocumentReader又委托給BeanDefinitionParserDelegate進(jìn)行解析。如果是標(biāo)準(zhǔn)的xml namespace元素,會(huì)在Delegate內(nèi)部完成解析,如果是非標(biāo)準(zhǔn)的xml namespace元素,則會(huì)委托合適的NamespaceHandler進(jìn)行解析最終解析的結(jié)果都封裝為BeanDefinitionHolder,至此解析就算完成。
后續(xù)會(huì)進(jìn)行細(xì)致講解。


3.注冊(cè)
然后bean的注冊(cè)是在BeanFactory里完成的,BeanFactory接口最常見(jiàn)的一個(gè)實(shí)現(xiàn)類(lèi)是DefaultListableBeanFactory,它實(shí)現(xiàn)了BeanDefinitionRegistry接口,所以其中的registerBeanDefinition()方法,可以對(duì)BeanDefinition進(jìn)行注冊(cè)這里附帶一提,最常見(jiàn)的XmlWebApplicationContext不是自己持有BeanDefinition的,它繼承自AbstractRefreshableApplicationContext,其持有一個(gè)DefaultListableBeanFactory的字段,就是用它來(lái)保存BeanDefinition
所謂的注冊(cè),其實(shí)就是將BeanDefinition的name和實(shí)例,保存到一個(gè)Map中。剛才說(shuō)到,最常用的實(shí)現(xiàn)DefaultListableBeanFactory,其中的字段就是beanDefinitionMap,是一個(gè)ConcurrentHashMap。
代碼如下:
>1.DefaultListableBeanFactory繼承實(shí)現(xiàn)關(guān)系

public class DefaultListableBeanFactory
extends 
AbstractAutowireCapableBeanFactory   
implements
ConfigurableListableBeanFactory, 
BeanDefinitionRegistry,
Serializable { 
     // DefaultListableBeanFactory的實(shí)例中最終保存了所有注冊(cè)的bean    beanDefinitionMap
     /** Map of bean definition objects, keyed by bean name */
     private final Map<String, BeanDefinition> beanDefinitionMap 
     = new ConcurrentHashMap<String, BeanDefinition>(64); 
     //實(shí)現(xiàn)BeanDefinitionRegistry中定義的registerBeanDefinition()抽象方法
     public void registerBeanDefinition(String beanName, BeanDefinition    beanDefinition)      throws BeanDefinitionStoreException {
     }

>2.BeanDefinitionRegistry接口

public interface BeanDefinitionRegistry extends AliasRegistry {   
    //定義注冊(cè)BeanDefinition實(shí)例的抽象方法
    void registerBeanDefinition(String beanName, BeanDefinition beanDefinition)         throws BeanDefinitionStoreException;

4.實(shí)例化


注冊(cè)也完成之后,在BeanFactory的getBean()方法之中,會(huì)完成初始化,也就是依賴注入的過(guò)程
大體上的流程就是這樣,下一篇博客,再具體地從代碼層面進(jìn)行介紹。

博客搬家:大坤的個(gè)人博客
歡迎評(píng)論哦~

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

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

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