Spring-IOC源码解读2-容器的初始化过程
1. IOC容器的初始化过程:IOC容器的初始化由refresh()方法启动,这个启动包括:BeanDifinition的Resource定位,加载和注册三个过程。初始化的过程不包含Bean依赖注入的实现。
- 第一个过程是Resource的定位过程。这个Resource的定位指的是BeanDefinition的资源定位,它由ResourceLoader通过统一的Resource接口完成。
 - 第二个过程是BeanDefinition的载入,这个过程是把用户定义好的Bean表示为容器的内部数据结构(即BeanDefinition)
 - 第三个过程是向IOC容器注册这些BeanDefinition的过程。
 
2. 下面我们以ClassPathXmlApplicationContext 为例分析这个ApplicationContext的实现,使用的spring版本是3.0.2版本。首先看下我们测试的代码和配置文件:
- 2.1:javaBean的定义
 
public class Person {
	private String name;
	private int age;
	private int sex;
	private Dog dog;
	private List<Address> addressList;
      
}
public class Dog {
	private String dogName;
}
public class Address {
	private String type;
	private String city;
}
- 2. 2beans.xml文件定义:
 
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns="http://www.springframework.org/schema/beans"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans-3.0.xsd">
<!-- person对象 -->
<bean id="person" class="com.pepper.spring.model.Person" >
<property name="name" value="pepper" />
<property name="age" value="24" />
<property name="sex" value="1" />
<property name="dog" ref="dog" />
<property name="addressList">
<list>
<ref bean="home"/>
<ref bean="work"/>
</list>
</property>
</bean> <!-- person对象的Dog属性 -->
<bean id="dog" class="com.pepper.spring.model.Dog">
<property name="dogName" value="Edward" />
</bean> <!-- person对象AddressList属性的两个值 -->
<bean id="home" class="com.pepper.spring.model.Address">
<property name="type" value="home" />
<property name="city" value="SX" />
</bean>
<bean id="work" class="com.pepper.spring.model.Address">
<property name="type" value="work" />
<property name="city" value="SZ" />
</bean>
</beans>
- 2.3. 容器启动类:
 
public class TestSpring {
	public static final String BEAN_CONFIG_FILE = "E:/workspace_selflearn/read-spring/src/spring-beans.xml";
	public static final String BEAN_CONFIG_CLASS = "spring-beans.xml";
	public static void main(String[] args) {
		testApplicationContext();
	}
	//使用XmlBeanFactory
	public static void testBeanFactory() {
		Resource res = new ClassPathResource(BEAN_CONFIG_CLASS);
		BeanFactory fac = new XmlBeanFactory(res);
		Person p = fac.getBean("person", Person.class);
		System.out.println(p);
	}
        //使用ApplicationContext
	public static void testApplicationContext() {
		ApplicationContext ac = null;
	     // ac = new FileSystemXmlApplicationContext(BEAN_CONFIG_FILE);
		ac = new ClassPathXmlApplicationContext(BEAN_CONFIG_CLASS);
		Person p = ac.getBean("person", Person.class);
		System.out.println(p);
	}
}
3. 我们先看下ClassPathXmlApplicationContext类的定义:
public class ClassPathXmlApplicationContext extends AbstractXmlApplicationContext {
    private Resource[] configResources;
    public ClassPathXmlApplicationContext() {
    }
    public ClassPathXmlApplicationContext(ApplicationContext parent) {
        super(parent);
    }
    // configLocation对象表示BeanDefinition所在的文件路径
    public ClassPathXmlApplicationContext(String configLocation) throws BeansException {
        this(new String[] {configLocation}, true, null);
    }
    // Spring支持传入多个BeanDefinition配置文件
    public ClassPathXmlApplicationContext(String... configLocations) throws BeansException {
        this(configLocations, true, null);
    }
    // 此构造方法除了包含配置文件路径,还允许指定想要使用的父类IOC容器
    public ClassPathXmlApplicationContext(String[] configLocations, ApplicationContext parent) throws BeansException {
        this(configLocations, true, parent);
    }
    public ClassPathXmlApplicationContext(String[] configLocations, boolean refresh) throws BeansException {
        this(configLocations, refresh, null);
    }
    //对象的初始化过程中,调用refresh()方法启动BeanDefinition的载入过程
    public ClassPathXmlApplicationContext(String[] configLocations, boolean refresh, ApplicationContext parent)throws BeansException {
        super(parent);
        setConfigLocations(configLocations);
        if (refresh) {
            refresh();
        }
    }
    public ClassPathXmlApplicationContext(String[] paths, Class clazz) throws BeansException {
        this(paths, clazz, null);
    }
    public ClassPathXmlApplicationContext(String[] paths, Class clazz, ApplicationContext parent) throws BeansException {
        super(parent);
        Assert.notNull(paths, "Path array must not be null");
        Assert.notNull(clazz, "Class argument must not be null");
        this.configResources = new Resource[paths.length];
        for (int i = 0; i < paths.length; i++) {
            this.configResources[i] = new ClassPathResource(paths[i], clazz);
        }
        refresh();
    }
    //获取资源配置文件
    @Override
    protected Resource[] getConfigResources() {
        return this.configResources;
    }
} 
容器启动的时候会调用ClassPathXmlApplicationContext的构造方法,在这个构造方法中会调用refresh()方法,这个方法十分重要,这是我们分析容器初始化过程中至关重要的一个接口,我们后面分析的Bean的载入,解析,注册都是以这个方法作为入口开始的。
public void refresh() throws BeansException, IllegalStateException {
        synchronized (this.startupShutdownMonitor) {
            // Prepare this context for refreshing.准备上下文
            prepareRefresh();
            // Tell the subclass to refresh the internal bean factory.通知子类刷新内部的bean工厂
            ConfigurableListableBeanFactory beanFactory = obtainFreshBeanFactory();
            // Prepare the bean factory for use in this context.准备beanfactory来使用这个上下文.做一些准备工作,例如classloader,beanfactoryPostProcessor等
            prepareBeanFactory(beanFactory);
            try {
                // Allows post-processing of the bean factory in context subclasses.在子类上下文中允许beanfactory进行后置处理
                postProcessBeanFactory(beanFactory);
                // Invoke factory processors registered as beans in the context.调用工厂处理器作为bean注册到上下文中
                invokeBeanFactoryPostProcessors(beanFactory);
                // Register bean processors that intercept bean creation.开始注册BeanPostProcessor来拦截bean的创建过程
                registerBeanPostProcessors(beanFactory);
                // Initialize message source for this context.为上下文初始化消息源
                initMessageSource();
                // Initialize event multicaster for this context.为上下文初始化事件广播
                initApplicationEventMulticaster();
                // Initialize other special beans in specific context subclasses.在具体的子类上下文中初始化特殊的bean
                onRefresh();
                // Check for listener beans and register them.检查监听器bean并注册
                registerListeners();
                // Instantiate all remaining (non-lazy-init) singletons.实例化所有的剩余的singleton的bean
                finishBeanFactoryInitialization(beanFactory);
                // Last step: publish corresponding event.最后一步,发布应用
                finishRefresh();
            }
            catch (BeansException ex) {
                // Destroy already created singletons to avoid dangling resources.
                destroyBeans();
                // Reset 'active' flag.
                cancelRefresh(ex);
                // Propagate exception to caller.
                throw ex;
            }
        }
    }
Spring-IOC源码解读2-容器的初始化过程的更多相关文章
- Spring Ioc源码分析系列--容器实例化Bean的四种方法
		
Spring Ioc源码分析系列--实例化Bean的几种方法 前言 前面的文章Spring Ioc源码分析系列--Bean实例化过程(二)在讲解到bean真正通过那些方式实例化出来的时候,并没有继续分 ...
 - Spring IoC源码解读——谈谈bean的几种状态
		
阅读Spring IoC部分源码有一段时间了,经过不断的单步调试和参阅资料,对Spring容器中bean管理有了一定的了解.这里从bean的几个状态的角度出发,研究下IoC容器. 一.原材料 Xml中 ...
 - 精尽Spring MVC源码分析 - WebApplicationContext 容器的初始化
		
该系列文档是本人在学习 Spring MVC 的源码过程中总结下来的,可能对读者不太友好,请结合我的源码注释 Spring MVC 源码分析 GitHub 地址 进行阅读 Spring 版本:5.2. ...
 - Spring Ioc源码分析系列--Ioc容器BeanFactoryPostProcessor后置处理器分析
		
Spring Ioc源码分析系列--Ioc容器BeanFactoryPostProcessor后置处理器分析 前言 上一篇文章Spring Ioc源码分析系列--Ioc源码入口分析已经介绍到Ioc容器 ...
 - Spring Ioc源码分析系列--Ioc容器注册BeanPostProcessor后置处理器以及事件消息处理
		
Spring Ioc源码分析系列--Ioc容器注册BeanPostProcessor后置处理器以及事件消息处理 前言 上一篇分析了BeanFactoryPostProcessor的作用,那么这一篇继续 ...
 - Spring IOC 源码分析
		
Spring 最重要的概念是 IOC 和 AOP,本篇文章其实就是要带领大家来分析下 Spring 的 IOC 容器.既然大家平时都要用到 Spring,怎么可以不好好了解 Spring 呢?阅读本文 ...
 - spring IoC源码分析 (3)Resource解析
		
引自 spring IoC源码分析 (3)Resource解析 定义好了Resource之后,看到XmlFactoryBean的构造函数 public XmlBeanFactory(Resource ...
 - Spring IoC源码解析之invokeBeanFactoryPostProcessors
		
一.Bean工厂的后置处理器 Bean工厂的后置处理器:BeanFactoryPostProcessor(触发时机:bean定义注册之后bean实例化之前)和BeanDefinitionRegistr ...
 - Spring IoC源码解析之getBean
		
一.实例化所有的非懒加载的单实例Bean 从org.springframework.context.support.AbstractApplicationContext#refresh方法开发,进入到 ...
 
随机推荐
- 为什么字符串String是不可变字符串&&"".equals(str)与str.equals("")的区别
			
为什么字符串String是不可变字符串 实际上String类的实现是char类型的数组 虽然说源码中设置的是private final char[] value; final关键词表示不可变动 但是只 ...
 - sourceTree配置bitbucket
			
1. 为github增加账号信息 选择添加远程库 选择添加一个账号 输入用户名: 按照提示输入密码 选择bitbuchet为默认 选中搜索克隆
 - Codeforces Round #318 (Div. 2) D 	 Bear and Blocks (数学)
			
不难发现在一次操作以后,hi=min(hi-1,hi-1,hi+1),迭代这个式子得到k次操作以后hi=min(hi-j-(k-j),hi-k,hi+j-(k-j)),j = 1,2,3... 当k ...
 - 签名ipa,让其它手机也安装
			
开发的时候,需要将app让其它人装上测试,虽然通过xcode可以使用编译进去,但是仍显不方便. 网上有个工具, http://code.google.com/p/iresign/ 通过这个工具,使用自 ...
 - 制作新的train,test数据集
			
之前的数据集的train和test是直接按照网上下载的数据的前7000个作为训练集,后2212个作为测试集.看得出来,这个数据集是由开车录制视频转换来的图片数据,后面2000多个图片的场景和前面的场景 ...
 - orcal中创建和删除表空间和用户
			
1.创建表空间 create tablespace NW_DATA logging datafile 'F:\oracle\product\10.2.0\oradata\nwdb\NW_DATA.db ...
 - Luogu P3938 斐波那契
			
Luogu P3938 斐波那契 第一眼看到这题,想到的是LCA,于是开始想怎么建树,倒是想出了\(n^{2}\)算法,看了下数据范围,果断放弃 想了想这数据范围,大的有点不正常,这让我想起了当年被小 ...
 - Bootstrap 响应式表格
			
响应式表格 通过把任意的 .table 包在 .table-responsive class 内,您可以让表格水平滚动以适应小型设备(小于 768px).当在大于 768px 宽的大型设备上查看时,您 ...
 - http常用状态吗以及分别代表什么意思?
			
http常用状态码: 状态码 定义 说明 1xx 信息 街道请求继续处理 2xx 成功 成功的收到.理解.接受 3xx 重定向 浏览器需要执行某些特殊处理一完成请求 4xx 客户端错误 请求的语法有问 ...
 - [LUOGU] P4767 [IOI2000]邮局
			
https://www.luogu.org/problemnew/show/P4767 四边形不等式好题! 可以设f[i][j]表示前i个村庄,建了j个邮局的最小代价. 转移:f[i][j]=min{ ...