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)圖如下圖所示:
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)論哦~