1、 Ioc容器的初始化: Ioc容器的初始化包括三个过程:Bean定义资源文件的定位、载入和注册3个基本过程。 (1)Bean定义资源文件的定位: Bean定义资源文件定位由ResourceLoader通过统一的Resource接口来完成,Resource接口将各种形式的Bean定义资源文件封装成统一的、Ioc容器可进行载入操作的对象。 (2)Bean定义资源文件的载入: Bean定义资源文件载入的过程是将Bean定义资源文件中配置的Bean转换成Ioc容器中所管理的Bean数据结构形式。SpringIoc中管理的数据结构是BeanDefinition,BeanDefinition是POJO对象在Ioc容器中的抽象。 (3)Bean定义的注册: 通过调用BeanDefinitionRegistry接口把从Bean定义资源文件中解析的Bean向Ioc容器进行注册,在Ioc容器内部,是通过一个HashMap来存储这些Bean对象数据的。 注意:Ioc容器和上下文初始化一般不包含Bean依赖注入的实现。一般而言,依赖注入发生在应用第一次通过getBean方法向容器获取Bean时。但是有个特例是:Ioc容器预实例化配置的lazyinit属性,如果某个Bean设置了lazyinit属性,则该Bean依赖注入在Ioc容器初始化时就预先完成了。 2、Bean定义资源文件的定位过程 ApplicationContext是一个在BeanFactory基础上提供了扩展的接口,具体的IoC容器实现常用的有:FileSystemXmlApplicationContet(从文件系统中读入Bean定义资源文件)、ClassPathXmlApplicationContext(从ClassPath类路径中读入Bean定义资源文件)和XmlWebApplicationContext(从Web容器和Tomcat中读入Bean定义资源文件)等等,下面将分别对这几种实现过程进行描述。 3、FileSystemXmlApplicationContext的初始化过程
public class FileSystemXmlApplicationContext extends AbstractXmlApplicationContext {
public FileSystemXmlApplicationContext() {
}
public FileSystemXmlApplicationContext(ApplicationContext parent) {
super(parent);
}
/**
* configLocation传入的Bean定义资源路径
*/
public FileSystemXmlApplicationContext(String configLocation) throws BeansException {
this(new String[] {configLocation}, true, null);
}
/**
* 传入多个Bean定义资源路径
*/
public FileSystemXmlApplicationContext(String... configLocations) throws BeansException {
this(configLocations, true, null);
}
public FileSystemXmlApplicationContext(String[] configLocations, ApplicationContext parent) throws BeansException {
this(configLocations, true, parent);
}
public FileSystemXmlApplicationContext(String[] configLocations, boolean refresh) throws BeansException {
this(configLocations, refresh, null);
}
/**
* FileSystemXmlApplicationContext Ioc进行初始化的构造函数入口
* @see #refresh()
*/
public FileSystemXmlApplicationContext(String[] configLocations, boolean refresh, ApplicationContext parent)
throws BeansException {
super(parent);
//调用AbstractRefreshableConfigApplicationContext的方法,设置Bean定义资源文件,完成 IoC容器Bean定义资源的定位
setConfigLocations(configLocations);
if (refresh) {
//调用父类AbstractApplicationContext的refresh()
//函数启动载入Bean定义的过程,是Ioc容器载入Bean定义的入口
refresh();
}
}
/**
*该方法覆盖父类DefaultResourceLoader的方法,通过Bean定义文件路径封装得到
*IoC容器要读入的定位Bean定义的资源
*/
@Override
protected Resource getResourceByPath(String path) {
if (path != null && path.startsWith("/")) {
path = path.substring(1);
}
//其他类型的IoC容器会用其他类型的Resource来定位Bean定义,如
//ClasspathResource等
return new FileSystemResource(path);
}
}
通过分析FileSystemXmlApplicationContext的源代码可以知道,在创建FileSystemXmlApplicationContext容器时,构造方法做以下两项重要工作:
首先,调用父类容器的构造方法(super(parent)方法)为容器设置好Bean资源加载器。
然后,再调用父类AbstractRefreshableConfigApplicationContext的setConfigLocations(configLocations)方法设置Bean定义资源文件的定位路径。
4. FileSystemXmlApplicationContext调用父类构造方法所做的工作:
通过追踪FileSystemXmlApplicationContext的继承体系,发现其父类的父类AbstractApplicationContext中初始化IoC容器所做的主要源码如下:
public abstract class AbstractApplicationContext extends DefaultResourceLoader
implements ConfigurableApplicationContext, DisposableBean {
//静态初始化块,在整个容器创建过程中只执行一次
static {
//了避免应用程序在Weblogic8.1关闭时出现类加载异常加载问题,加载IoC容
//器关闭事件(ContextClosedEvent)类
ContextClosedEvent.class.getName();
}
//FileSystemXmlApplicationContext调用父类构造方法调用的就是该方法
public AbstractApplicationContext(ApplicationContext parent) {
this();
setParent(parent);
}
//设置父Bean定义资源加载器
@Override
public void setParent(ApplicationContext parent) {
this.parent = parent;
if (parent != null) {
Environment parentEnvironment = parent.getEnvironment();
if (parentEnvironment instanceof ConfigurableEnvironment) {
//将父加载器要加载的类容和新的要加载的内容整合在一起
getEnvironment().merge((ConfigurableEnvironment) parentEnvironment);
}
}
}
}
在设置容器的资源加载器之后,接下来FileSystemXmlApplicationContet执行setConfigLocations方法调用父类其类的相关方法定位Bean定义资源文件。
5、AbstractRefreshableConfigApplicationContext定位Bean定义资源文件:
在对FileSystemXmlApplicationContet的源码分析中我们看到,在其入口构造函数中,通过调用其父类AbstractRefreshableConfigApplicationContext的方法进行对Bean定义资源文件的定位,该方法的源码如下:
//处理单个资源文件路径为一个字符串的情况
public void setConfigLocation(String location) {
//String CONFIG_LOCATION_DELIMITERS = ",; /t/n";
//即多个资源文件路径之间用” ,; /t/n”分隔,解析成数组形式
setConfigLocations(StringUtils.tokenizeToStringArray(location, CONFIG_LOCATION_DELIMITERS));
}
//解析Bean定义资源文件的路径,处理多个资源文件字符串数组
public void setConfigLocations(String... locations) {
if (locations != null) {
Assert.noNullElements(locations, "Config locations must not be null");
this.configLocations = new String[locations.length];
for (int i = 0; i < locations.length; i++) {
// resolvePath为同一个类中将字符串解析为路径的方法
this.configLocations[i] = resolvePath(locations[i]).trim();
}
}
else {
this.configLocations = null;
}
}
通过这两个方法的源码我们可以看出,我们既可以使用一个字符串来配置多个Spring Bean定义资源文件,也可以使用字符串数组,即下面两种方式都是可以的:
a. ClasspathResource res = new ClasspathResource(“a.xml,b.xml,……”);
多个资源文件路径之间可以是用” ,; /t/n”等分隔。
b. ClasspathResource res = new ClasspathResource(new String[]{“a.xml”,”b.xml”,……});
至此,Spring IoC容器在初始化时将配置的Bean定义资源文件定位为Spring封装的Resource。
备注:本文内容主要参考来源于,http://blog.csdn.net/chjttony/article/details/6256709,仅供自己学习使用。
浙公网安备 33010602011771号