1.IoC容器初始化:
Spring的IoC容器初始化包括:Bean定义资源文件的定位、载入和注册3个基本过程。
(1).Bean定义资源文件的定位:
Bean定义资源文件定位由ResourceLoader通过统一的Resource接口来完成,Resource接口将各种形式的Bean定义资源文件封装成统一的、IoC容器可进行载入操作的对象。
(2).Bean定义资源文件的载入:
Bean定义资源文件载入的过程是将Bean定义资源文件中配置的Bean转换成IoC容器中所管理Bean的数据结构形式。SpringIoC中管理的Bean的数据结构是BeanDefinition,BeanDefinition是POJO对象在IoC容器中的抽象。
(3).Bean定义的注册:
通过调用BeanDefinitionRegistry接口把从Bean定义资源文件中解析的Bean向IoC容器进行注册,在IoC容器内部,是通过一个HashMap来存储这些Bean对象数据的。
注意:IoC容器和上下文初始化一般不包含Bean依赖注入的实现。一般而言,依赖注入发送在应用第一次通过getBean方法向容器获取Bean时。但是有个特例是:IoC容器预实例化配置的lazyinit属性,如果某个Bean设置了lazyinit属性,则该Bean的依赖注入在IoC容器初始化时就预先完成了。
Spring4.1源代码包
以这个例子开始:
public class UserServiceTest {
private ApplicationContext ctx;
@Test
public void testAdd() throws Exception {
ctx = new ClassPathXmlApplicationContext("beans.xml" );
UserService userService = (UserService)ctx.getBean("userService" );
userService.add( new User());
}
}
背景说明:
ApplicationContext是一个BeanFactory基础上提供了扩展的接口(BeaFactory是Spring中最基本最基础的Ioc容器)。具体对IOC容器的实现常用的有3个:
FileSystemXmlApplicationContext 从文件系统中读取定义bean的资源文件。
ClassPathXmlApplicationContext 从ClassPath的路径中读取定义bean的资源文件。
XmlWebApplicationContext 从web容器中读取定义bean的资源文件。
bean资源文件就是beans.xml文件。
bean资源文件定位的过程:
在
ctx
=
new
ClassPathXmlApplicationContext(
"beans.xml"
);打断点。
1.发现直接先进入了下面的静态模块:
现在我还不知道是做什么用的。
static{
// Eagerly load the ContextClosedEvent class to avoid weird classloader issues
// on application shutdown in WebLogic 8.1. (Reported by Dustin Woods.)
ContextClosedEvent.class.getName();
}
这个静态模块出现在AbstractApplicationContext中,在整个容器的创建的过程中只执行一次。
这个作用是,翻译上面的话:为了避免应用程序在weblogic8.1关闭的时候出现加载类加载异常的问题,所以较早的加载这个ContextClosedEvent事件。
public ClassPathXmlApplicationContext(String configLocation ) throws BeansException {
this(new String[] {configLocation}, true, null);
}
这个构造方法通过this()方法又调用了同类下的正真的入口方法:
public ClassPathXmlApplicationContext(String[] configLocations , boolean refresh , ApplicationContext parent )throws BeansException {
super(parent );
setConfigLocations(configLocations);
if ( refresh) {
refresh();
}
}
这个才是真正的入口方法:
这个方法两步:
1.定位资源文件。
2.启动加载以及注册。
本篇讲定位也就是: super()和setConfigLocation(cinfigLocations)所做的事情。
1-先看super(parent) 这个parent是null在这里。
调用了父类的构造方法,发现它调用了父类AbstractRefreshableConfigApplicationContext的构造方法:
public AbstractXmlApplicationContext(ApplicationContext parent) {
super(parent );
}
再进入发现它又调用了
AbstractRefreshableConfigApplicationContext
的父类的构造方法,
。。。
以此类推,它分别依次调用了
AbstractXmlApplicationContext
AbstractRefreshableConfigApplicationContext
AbstractRefreshableApplicationContext
的父类方法直到
AbstractApplicationContext 为止.
我们得到这样一张在后面很有用的结构图:
除了ClassPathXmlApplicationContext 其他的父类都是抽象类。就是说通过这几个抽象类分了这几个层次,而最后实现类就只有:ClassPathXmlApplicationContext。
继续看,在AbstractApplicationContext中的构造方法是这样的:
public AbstractApplicationContext(ApplicationContext parent ) {
this ();
setParent( parent);
}
也是两步:
a 调用自身的构造方法 this();
public AbstractApplicationContext() {
this. resourcePatternResolver = getResourcePatternResolver();
}
这个构造方法,通过getResourcePatternResolver来获得了一个 resourcePatternResolver, 这是一个Spring Source的加载器。
getResourcePatternResolver的方法实现是这样的:
protected ResourcePatternResolver getResourcePatternResolver() {
return new PathMatchingResourcePatternResolver(this);
}
直接new了一个
PathMatchingResourcePatternResolver对象,这个对象创建了spring的资源加载器。
其实上图中AbstractApplication上面继承了DefaultResourceLoader而DefaultResourceLoader实现了ResourceLoader接口,所以当前对象本身就是一个Spring资源加载器,它的getResources方法就是用于加载资源的。
PathMatchingResourcePatternResolver对象,它里面的实现是这样的:
public PathMatchingResourcePatternResolver(ResourceLoader resourceLoader) {
Assert.notNull(resourceLoader, "ResourceLoader must not be null");
this. resourceLoader = resourceLoader;
}
就是把AbstractApplicationContext对象设置成一个资源加载器。赋值给
到这里完成了this(),这个构造函数所做的工作,把自身AbstractApplicationContext的对象传给
PathMatchingResourcePatternResolver的resourceLoader属性,设置了容器的资源加载器。
b 然后 setParent(parent);
其实我们发现,我们一路super(parent)父类构造方法,到这里,ClassPathXmlApplicationContext 调用父类真正的构造方法就是这个setParent(parent);
而这个例子中,我们传入到parent是null,暂时先不考虑。
到这里最初方法里的super(parent)就完成了。
2-下面看
setConfigLocations(
configLocations
);
下篇讲。