图6. Bean的解析类
当然还有具体对tag的解析 在这里并未列出
3.2 Context组件
Context组件在Spring的org.springframework.context包下,前面已经讲解了Context组件在Spring中的作用,它实际上就是给Spring提供一个运行时的环境,用以保存各个对象的状态。下面看一下这个环境是如何构建的。
ApplicationContext是Context的顶级父类,它除了能标识一个应用环境的基本信息外,它还继承了5个接口,这5个接口主要是扩展了Context的功能。下面是Context类结构图:
图7. Context相关的类结构图
从上图中可以看出ApplicationContext继承了BeanFactory,这也说明了Spring容器中运行的主体对象是Bean,另外,ApplicationContext继承了ResourceLoader接口,这使得ApplicationContext可以访问到任何外部资源,这将在Core中详细说明。
ApplicationContext的子类主要包含两个方面: 1.
ConfigurableApplicationContext表示该Context是可修改的,也就是在构建Context中用户可以动态添加或修改配置信息,它下面又有多个子类,其中最经常使用的是可更新的Context,即AbstractRefreshableApplicationContext类 2.
WebApplicationContext 顾名思义,就是为web准备的Context,它可以直接访问到ServletContext,通常情况下这个接口使用的少
再往下分就是按照构建Context的文件类型,接着就是访问Context的方式。这样一级一级构成了完整的Context等级层次。总体来说ApplicationContext必须要完成以下几件事: ? ?
标识一个应用环境
利用BeanFactory创建Bean对象
? ?
保存对象关系表 能够捕获各种事件
Context作为Spring的IOC容器,基本上整合了Spring的大部分功能,或者说是大部分功能的基础
3.3 Core核心组件
Core组件作为Spring的核心组件,包含了很多的关键类,其中一个重要的组成部分就是定义了资源的访问方式。这种把所有资源都抽象成一个接口的方式很值得以后在设计中学习。下面就看一下这部分在Spring中的作用。
下面是Resource相关的类结构图:
图8. Resource相关的类结构图
从上图可以看出Resource接口封装了各种可能的资源类型,就是说对使用者来说屏蔽了文件类型的不同。对资源的提供者来说,如何把资源包装起来交给其他人用这也是一个问题,我们看到Resource接口继承了InputStreamSource接口,这个接口中有一个getInputStream方法,返回的是InputStream类。这样所有的资源都可以通过InputStream类来获取,所以也屏蔽了资源的提供者。另外还有一个就是加载资源的问题,也就是资源的加载者要统一,从上图中可以看出这个任务是由ResourceLoader接口来完成,它屏蔽了所有资源加载者的差异,只需要实现这个接口就可以加载所有的资源,它的默认实现是DefaultResourceLoader。
下面看一下Context和Resource是如何建立关系的,首先看一下它们的类关系图:
图9. Context和Resource的类关系图
从上图可以看出,Context是把资源的加载,解析和描述工作委托给了ResourcePatternResolver类来完成,它相当于一个接头人,它把资源的加载,解析和资源的定义整合在一起便于其他组件使用。Core组件中还有很多类似的方式。
3.4 IOC容器如何工作
前面介绍了Core组件,Beans组件和Context组件和他们之间的相互关系,下面从使用者的角度看下他们是如何运行的,以及我们如何让Spring完成各种功能,Spring到底有哪些功能,这些功能是如何得来的?
3.4.1如何创建BeanFactory工厂
正如图2描述的那样,IOC容器实际上就是Context组件结合其他两个组件共同构建了一个Bean的关系网。如何构建这个关系网?构建的入口就在AbstractApplicationContext类的refresh方法中。代码如下:
清单1. AbstractApplicationContext.refresh
public void refresh() throws BeansException, IllegalStateException { synchronized(startupShutdownMonitor) { //Prepare this context for refreshing
prepareRefresh();
//tell the subclass to refresh the internal bean factory
ConfigurableListableBeanFactory beanFactory = obtainFreshBeanFactory(); //Prepare the bean factory for use in this context prepareBeanFactory(beanFactory); try{
//Allows post-processing of the bean factory in context subclass postProcessBeanFactory(beanFactory);
//Invoke factory processors registered as beans in the context invokeBeanFactoryPostProcessors(beanFactory);
//Register bean processors that intercept bean creation registerBeanPostProcessors(beanFactory); //Initialize message source for this context initMessageSource();
//Initialize event multicaster for this context initApplicationEventMulticaster();
//Initialize other special beans in specific context subclasses onRefresh();
//Check for listener beans and register them registerListeners();
//Instantiate all remaining(non-lazy-init) singletons finishBeanFactoryInitialization(beanFactory); //Last step: public corresponding event finishRefresh(); }catch(BeansException ex) { destroyBeans(); cancelRefresh(ex); throw ex; } }
}
这个方法就是构建整个IOC容器的完整代码,了解里面的每一行代码基本上就了解了Spring的大部分的原理和功能了。这段代码主要包含以下几个步骤:
? ? ? ?
构建BeanFactory,以便产生所需的“演员” 注册可能感兴趣的事件 创建Bean实例对象 触发被监听的时间
下面就结合代码分析这几个过程。
第二三句就是在创建和配置BeanFactory,这里refresh也就是刷新配置,前面介绍了Context有可更新的子类,这里正是实现这个功能,当BeanFactory已经存在就更新,如果没有就新建,下面是更新BeanFactory的代码:
protected final void refreshBeanFactory() throws BeansException { if(hasBeanFactory()) { destroyBeans(); closeBeanFactory(); } try {
DefaultListableBeanFactory beanFactory = createBeanFactory(); beanFactory.setSerializationId(getId()); customizeBeanFactory(beanFactory); loadBeanDefinitions(beanFactory); synchronized(beanFactoryMonitor) { this.beanFactory = beanFactory; }
} catch(IOException ex) {
throw new ApplicationContextException((new StringBuilder(\parsing bean definition source for \ } }