1.目标:熟练使用spring,并分析其源码,了解其中的思想。这篇主要介绍spring ioc 容器的加载
2.前提条件:会使用debug
3.源码分析方法:Intellj idea debug 模式下源码追溯
通过ClassPathXmlApplicationContext 进行xml 件的读取,从每个堆栈中读取程序的运行信息
4.注意:由于Spring的类继承体系比较复杂,不能全部贴图,所以只将分析源码之后发现的最主要的类继承结构类图贴在下方。
5.关于Spring Ioc Demo:我们从demo入手一步步进行代码追溯。

1.Spring Ioc Demo

1.定义数据访问接口IUserDao.java

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

2.定义IUserDao.java实现类IUserDaoImpl.java

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

3.定义业务逻辑接口UserService.java

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

4.定义UserService.java实现类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表示他代表的类,如果在包里的话需要加上包名-->    
 <bean id="userService"  class="UserServiceImpl" >      
        <!--property代表是通过set方法注入,ref的值表示注入的内容-->
        <property  name="userDao"  ref="userDao"/>  
 </bean>    
  <bean id="userDao"  class="UserDaoImpl"/>
</beans>
2.ApplicationContext 继承结构:

1.顶层接口:ApplicationContext
2.ClassPathXmlApplicationContext实现类继承AbstractXmlApplication 抽象类
3.AbstractXmlApplication 继承AbstractRefreshableConfigApplicationContext
4.AbstractRefreshableConfigApplicationContext抽象类继承AbstractRefreshableApplicationContext
5.AbstractRefreshableApplicationContext 继承 AbstractApplicationContext
6.AbstractApplicationContext 实现ConfigurableApplicationContext 接口
7.ConfigurableApplicationContext 接口继承
ApplicationContext接口
总体来说继承实现结构较深,内部使用了大量适配器模式。
以ClassPathXmlApplicationContext为例,继承类图如下图所示:




spring容器打开流量前的钩子函数_spring容器打开流量前的钩子函数


Spring ioc .png


3.Spring Ioc容器加载过程源码详解

在开始之前,先介绍一个整体的概念。即spring ioc容器的加载,大体上经过以下几个过程:
资源文件定位、解析、注册、实例化

1.资源文件定位
其中资源文件定位,一般是在ApplicationContext的实现类里完成的,因为ApplicationContext接口继承ResourcePatternResolver 接口,ResourcePatternResolver接口继承ResourceLoader接口,ResourceLoader其中的getResource()方法,可以将外部的资源,读取为Resource类。


2.解析DefaultBeanDefinitionDocumentReader,
解析主要是在BeanDefinitionReader中完成的,最常用的实现类是XmlBeanDefinitionReader,其中的loadBeanDefinitions()方法,负责读取Resource,并完成后续的步骤。ApplicationContext完成资源文件定位之后,是将解析工作委托给XmlBeanDefinitionReader来完成的
解析这里涉及到很多步骤,最常见的情况,资源文件来自一个XML配置文件。首先是BeanDefinitionReader,将XML文件读取成w3c的Document文档。
DefaultBeanDefinitionDocumentReader对Document进行进一步解析。然后DefaultBeanDefinitionDocumentReader又委托给BeanDefinitionParserDelegate进行解析。如果是标准的xml namespace元素,会在Delegate内部完成解析,如果是非标准的xml namespace元素,则会委托合适的NamespaceHandler进行解析最终解析的结果都封装为BeanDefinitionHolder,至此解析就算完成。
后续会进行细致讲解。


3.注册
然后bean的注册是在BeanFactory里完成的,BeanFactory接口最常见的一个实现类是DefaultListableBeanFactory,它实现了BeanDefinitionRegistry接口,所以其中的registerBeanDefinition()方法,可以对BeanDefinition进行注册这里附带一提,最常见的XmlWebApplicationContext不是自己持有BeanDefinition的,它继承自AbstractRefreshableApplicationContext,其持有一个DefaultListableBeanFactory的字段,就是用它来保存BeanDefinition
所谓的注册,其实就是将BeanDefinition的name和实例,保存到一个Map中。刚才说到,最常用的实现DefaultListableBeanFactory,其中的字段就是beanDefinitionMap,是一个ConcurrentHashMap。
代码如下:
>1.DefaultListableBeanFactory继承实现关系

public class DefaultListableBeanFactory
extends 
AbstractAutowireCapableBeanFactory   
implements
ConfigurableListableBeanFactory, 
BeanDefinitionRegistry,
Serializable { 
     // DefaultListableBeanFactory的实例中最终保存了所有注册的bean    beanDefinitionMap
     /** Map of bean definition objects, keyed by bean name */
     private final Map<String, BeanDefinition> beanDefinitionMap 
     = new ConcurrentHashMap<String, BeanDefinition>(64); 
     //实现BeanDefinitionRegistry中定义的registerBeanDefinition()抽象方法
     public void registerBeanDefinition(String beanName, BeanDefinition    beanDefinition)      throws BeanDefinitionStoreException {
     }

>2.BeanDefinitionRegistry接口

public interface BeanDefinitionRegistry extends AliasRegistry {   
    //定义注册BeanDefinition实例的抽象方法
    void registerBeanDefinition(String beanName, BeanDefinition beanDefinition)         throws BeanDefinitionStoreException;

4.实例化


注册也完成之后,在BeanFactory的getBean()方法之中,会完成初始化,也就是依赖注入的过程
大体上的流程就是这样,下一篇博客,再具体地从代码层面进行介绍。