关于Spring,我们先从Spring的架构图开始说起
这是一张经典图,介绍了Spring 各个模块的位置和作用,SpringIOC是最基本的模块,包含了最为基本的IOC容器BeanFactory,也包括一系列它的实现,当然单纯的容器是不能够支撑开发的,还需要一系列外围支持,就像只有CPU,没有外围一样,这些外围包括支持Resource访问资源的抽象和定位。另外,Spring还提供了IOC容器的高级形态ApplicationContext应用上下文供用户使用,刚学Spring的时候,我们应该都用过ClassPathXmlApplicationContext这个类,也许,真像离我们真的很近。
IOC和控制反转
如果对象的引用或者依赖关系由具体对象来完成。会导致代码的高度耦合,而且有一种牵一发而动全身的感觉,这种复杂的面向对象系统的设计是非常不利的;如果,将这些依赖关系交给框架或者IOC容器来完成,那么就可以在解耦代码的同时提高代码的可测试性。在Spring中,IOC容器是这个模式的载体,IOC也是Spring框架要解决的核心问题。下面我们从IOC中两个核心的接口BeanFactory和Appliationontext中来秘境探幽。
我们知道,BeanFactory接口是一个根接口,他有一系列实现,这部分实现了容器的基本功能;另一个是ApplicationContext应用上下文,它作为容器的高级形态出现,增加了许多面向框架的特性。另外一点,Spring通过定义BeanDefinition来管理基于Spring的应用中的各种对象以及他们之间的相互依赖关系。IOC和BeanDefinition的关系是这样的,IOC是用来管理对象依赖关系的,而BeanDefinition是让容器起作用的数据模型,是对控制反转模式中管理的对象依赖关系的数据抽象,控制反转是通过围绕其来完成的,就像水桶和水的关系,IOC是水桶,BeanDefinition是水。
我们知道BeanFactory定义了几个关于Bean的最基本方法,他们是:
//1、创建IOC配置文件的抽象资源,包含BeanDefinition的定义信息
ClassPathResource resource = new ClassPathResource("META-INF/spring/minstrel.xml");
//2、创建一个BeanFactory
DefaultListableBeanFactory defaultListableBeanFactory = new DefaultListableBeanFactory();
//3、创建一个载入BeanDefinition的读取器,其通过一个回调配置给BeanFactory
XmlBeanDefinitionReader xmlBeanDefinitionReader = new XmlBeanDefinitionReader(defaultListableBeanFactory);
//4、从定义好的资源位置读入配置信息,完成整个载入和注册Bean的功能
xmlBeanDefinitionReader.loadBeanDefinitions(resource);
上面介绍了一部分理论知识,其实只是很小的一部分,因为我们的重点是分析源码,最好能一步步断点调试下。所以下面以ClassPathXmlApplicationContext入手,来分析下。
简单来说,IOC容器的初始化是由下面的refresh()方法来启动的,整个启动包括BeanDefinition的Resource定位、载入和注册三个过程。
public ClassPathXmlApplicationContext(String[] configLocations, boolean refresh, ApplicationContext parent)
throws BeansException {
super(parent);
setConfigLocations(configLocations);
if (refresh) {
refresh();
}
}
下面简单先叙述介绍下这三个过程:
private final Map beanDefinitionMap = new ConcurrentHashMap(64);
将解析得到的BeanDefinition向IOC容器中的beanDefinitionMap注册的过程是在载入后完成的,注册的过程如下:
在processBeanDefinition(Element ele, BeanDefinitionParserDelegate delegate)会完成BeanDefinition的注册,如下:
protected void processBeanDefinition(Element ele, BeanDefinitionParserDelegate delegate) {
BeanDefinitionHolder bdHolder = delegate.parseBeanDefinitionElement(ele);
if (bdHolder != null) {
bdHolder = delegate.decorateBeanDefinitionIfRequired(ele, bdHolder);
try {
// Register the final decorated instance.
BeanDefinitionReaderUtils.registerBeanDefinition(bdHolder, getReaderContext().getRegistry());
}
catch (BeanDefinitionStoreException ex) {
getReaderContext().error("Failed to register bean definition with name '" +
bdHolder.getBeanName() + "'", ele, ex);
}
// Send registration event.
getReaderContext().fireComponentRegistered(new BeanComponentDefinition(bdHolder));
}
}
@Override
public void registerBeanDefinition(String beanName, BeanDefinition beanDefinition)
throws BeanDefinitionStoreException {
Assert.hasText(beanName, "Bean name must not be empty");
Assert.notNull(beanDefinition, "BeanDefinition must not be null");
if (beanDefinition instanceof AbstractBeanDefinition) {
try {
((AbstractBeanDefinition) beanDefinition).validate();
}
catch (BeanDefinitionValidationException ex) {
throw new BeanDefinitionStoreException(beanDefinition.getResourceDescription(), beanName,
"Validation of bean definition failed", ex);
}
}
BeanDefinition oldBeanDefinition;
synchronized (this.beanDefinitionMap) {
oldBeanDefinition = this.beanDefinitionMap.get(beanName);
if (oldBeanDefinition != null) {
if (!this.allowBeanDefinitionOverriding) {
throw new BeanDefinitionStoreException(beanDefinition.getResourceDescription(), beanName,
"Cannot register bean definition [" + beanDefinition + "] for bean '" + beanName +
"': There is already [" + oldBeanDefinition + "] bound.");
}
else if (oldBeanDefinition.getRole() < beanDefinition.getRole()) {
// e.g. was ROLE_APPLICATION, now overriding with ROLE_SUPPORT or ROLE_INFRASTRUCTURE
if (this.logger.isWarnEnabled()) {
this.logger.warn("Overriding user-defined bean definition for bean '" + beanName +
" with a framework-generated bean definition ': replacing [" +
oldBeanDefinition + "] with [" + beanDefinition + "]");
}
}
else {
if (this.logger.isInfoEnabled()) {
this.logger.info("Overriding bean definition for bean '" + beanName +
"': replacing [" + oldBeanDefinition + "] with [" + beanDefinition + "]");
}
}
}
else {
this.beanDefinitionNames.add(beanName);
this.frozenBeanDefinitionNames = null;
}
this.beanDefinitionMap.put(beanName, beanDefinition);
}
if (oldBeanDefinition != null || containsSingleton(beanName)) {
resetBeanDefinition(beanName);
}
}
可以看到BeanDefinition的注册都和声明的Map有关,而且会判断是否可以覆盖,其会先去根据beanDefinition的名字去Map中取,然后判断是否允许覆盖,最后添加。