Spring 是 Java web 开发一站式的开源框架 。以 IoC (Inverse of Control ,控制反转) 和 AOP (Aspect Oriented Programming,切面编程) 为内核,提供了展现层 Spring MVC , 持久层 Spring JDBC 以及业务层事务管理等一站式的企业级应用技术。
Spring 核心模块实现了 IoC 的功能 ,它将类与类之间的依赖从代码中脱离出来。用配置的方式进行依赖关系描述,由 IoC 容器负责依赖类之间的创建、拼接、管理、获取等工作。象之间的依赖关系交由 IoC进行控制,避免硬编码所造成的过度程序耦合。有了Spring,用户不必再为单例模式、属性文件解析等这些底层的需求编写代码。可以更专注于上层的应用。 BeanFactory 是 Spring 框架的核心接口,它实现了容器的许多核心的功能。
Context 模块构建于核心模块之上,扩展了 BeanFactory 的功能,添加了 il8n 国际化、 Bean 生命周期控制、 框架事件体系、资源加载透明化等多项功能。此外,该模块还提供了许多企业级服务的支持,如邮件服务、任务调度、JNDI 获取、EJB 集成、远程访问等。 ApplicationContext 是 Context 模块的核心接口。
表达式语言模块是统一表达式语言(Unified EL)的一个扩展,该表达式语言用于查询和管理运行期的对象,支持设置/获取对象属性,调用对象方法 ,操作数组、集合等。此外该模块还提供了逻辑表达式运算、变量定义等功能,可以方便的通过表达式串和 Spring IoC 容器进行交互。
BeanFactory 是 Spring 框架最核心的接口,它提供了高级 IoC 配置机制。 BeanFactory 使管理不同类型的 Java 对象成为可能 ,ApplicationContext 是建立在 BeanFactory 基础之上 ,提供了更多面向应用的功能,提供了国际化支持和框架事件体系,更易于创建实际应用。我们一般称 BeanFactory 为 IoC 容器,而 ApplicationContext 为应用上下文。对于二者的用途,我们可以进行简单的划分: BeanFactory 是 Spring 框架的基础设施 ,面向 Spring 本身, ApplicationContext 面向使用 Spring 框架的开发者 ,几乎所有的场合都可以直接使用 ApplicationContext 而非底层的 BeanFactory 。
BeanFactory 接口位于类结构树的顶端,它最主要的方法及是 getBean(String beanName) , 该方法从容器中返回特定名称的 Bean。 BeanFactory 的功能通过其他接口不断扩展。
ListableBeanFactory : 该接口定义了访问容器中 Bean 基本信息的若干方法 ,如查看 Bean 的个数,获取某一类型 Bean 的配置名,查看容器中是否包含某一 Bean。
HierarchicalBeanFactory: 父子级联 Ioc 容器的接口,子容器可以通过接口方法访问父容器。
ConfigurableBeanFactory : 这是一个重要的接口,增强了 Ioc 容器的可定制性。它定义了设置类加载器、属性编辑器、容器初始化后置处理器等方法。
AutowireCapableBeanFactory :定义了将容器中的 Bean 按某种规则(如按名字匹配、按类型匹配等)进行自动装配的方法。
SingletonBeanRegistry :定义了允许在运行期向容器注册单实例 Bean 的方法。
BeanDefinitionRegistry : Spring 配置文件中每一个 节点元素在 Spring 容器里都通过一个 BeanDefinition 对象表示,它描述了 Bean 配置信息。而 BeanDefinition Registry 接口提供了向容器手工注册 BeanDefinition 对象的方法。
通过 HierarchicalBeanFactory 接口, Srping 的 Ioc 容器可以建立父子层级关联的容器体系,子容器可以访问父容器中的 Bean , 但父容器不能访问子容器中的 Bean ,
在容器内, Bean 的 id 必须是唯一的 ,但子容器可以拥有一个和父容器 id 相同的 Bean 。父子容器层级体系扩展了 Spring 容器体系架构的扩展性和灵活性,因为第三方可以通过编程的方式为一个已经存在的容器添加一个或多个特殊用途的子容器,以提供一些额外功能。
Spring 使用父子容器实现了很多功能,比如在 SpringMVC 中,展现层 Bean 位于一个子容器中,而业务层和持久层 Bean 位于父容器中。这样,展现层 Bean 可以引用业务层和持久层 Bean ,而业务层和持久层 Bean 则看不到展现层 Bean。
如果说 BeanFactory 是 Spring 的“心脏” , 那么 ApplicationContext 就是完整的 “身躯” 。 ApplicationContext 是由 BeanFactory 派生而来,提供了更多面向实际应用的功能。 在 BeanFactory 中,很多功能需要以编程的方式实现,而在 ApplicationContext 中则可以通过配置的方式实现。
ApplicationContext 的主要实现类 ClassPathXmlApplicationContext 和 FileSystemXmlApplicationContext , 前者默认从类加载路径加载配置文件,后者默认从文件系统中加载配置文件。
从上图中可以看出 ApplicationContext 继承了 HierarchicalBeanFactory 和 ListableBeanFactory 接口,在此基础上,还通过多个其他的接口扩展了 BeanFactory 的功能,这些接口如下 :
- ApplicationEventPublisher : 让容器拥有发布应用上下文事件的功能,包括容器启动事件、关闭事件等。实现了 ApplicationListener 事件监听接口的 Bean可以接受到容器事件,并对事件进行响应处理。在 ApplicationContext 抽象实现类 AbstractApplicationContext 中存在一个 ApplicationEventMulticaster,它负责保存所有的监听器 ,以便在容器产生上下文事件时通知这些事件的监听者。
- MessageSource : 为应用提供 il8n 国际化消息访问的功能。
- ResourcePatternResolver : 所有 ApplicationContext 实现类都实现了类似于 PathMatchingResourcePatternResolver 的功能,可以通过带前缀的 Ant 风格的资源文件路径加载 Spring 的配置文件。
- LifeCycle : 该接口提供了 start() 和 stop() 方法,主要用于控制异步过程。在具体使用时,该接口同时被 ApplicationContext 实现及 具体 Bean 实现 , ApplicationContext 会将 start/stop 的信息传递给容器中所有实现了该接口的 Bean ,已达到管理和控制 JMX、任务调度等目的。
- ConfigurableApplicationContext 扩展于 ApplicationContext ,它新增了两个主要的方法 : refresh() 和 close(), 让 ApplicationContext 具有启动、刷新和关闭应用上下文的能力。在应用上下文关闭的情况下调用 refresh() 即可启动应用上下文,在已经启动的状态下调用 refresh() 则可清除缓存并重新加载配置信息,而调用 close 则可关闭应用上下文。这些接口方法为容器的控制管理带来了便利。
WebApplicationContext 是专门为 Web 应用准备的,它允许从相对于 Web 根目录的路径加载配置文件完成初始化工作。 从WebApplicationContext 中可以获得 ServletContext 的引用 , 整个 Web 应用上下文对象将作为属性放到到 ServletContext 中,以便 Web 应用环境可以访问 Spring 应用上下文。 Spring 专门为此提供了一个工具类 WebApplicationContextUtils ,通过该类的 getWebApplicationContext(ServletContext sc)方法,可以从 ServletContext 中获取 WebApplicationContext 实例。
在非 Web 应用的环境下,Bean 只有 singleton 和 prototype 两种作用域。 WebApplicationContext 为 Bean 添加了三个新的作用域:request、session、和 global session 。下图为 WebApplicationContext 的继承体系:
由于 Web 应用比一般的应用拥有更多的特性,因此 WebApplicationContext 扩展了 ApplicationContext 。 WebApplicationContext 定义了一个常量 WebApplicationContext.ROOT_WEB_APPLICATION_CONTEXT_ATTRIBUTE , 在上下文启动时, WebApplicationContext 实例以此为键放置在 ServletContext 的属性列表中,可以通过以下语句从 Web 容器中获取 WebApplicationContext:
WebApplicationContext webContext = (WebApplicationContext) servletContext.getAttribute(WebApplicationContext.ROOT_WEB_APPLICATION_CONTEXT_ATTRIBUTE);
ConfigurableWebApplicationContext 扩展了 WebApplicationContext , 它允许通过配置的方式实例化 WebApplication , 同时定义了两个重要的方法 :
- setServletContext(ServletContexxt servletContext) :为Spring 设置 Web 应用上下文 ,以便两者整合。
-setConfigLocation(String[] configLocations) :为Spring 设置配置文件路径,一般情况下,配置文件地址相对于 Web 根目录的地址,如
/WEB-INF/smart-dao.xm、/WEB-INF/smart-service.xml 等。但用户也可以使用带资源类型前缀的地址,如 classpath:com/smart/beans.xml 等
WebApplicationContext 的初始化方式和 BeanFactory 、ApplicationContext 有所区别,因为 WebApplicationContext 需要 ServletContext 实例,也就是说在拥有 Web 容器的前提下才能完成启动工作。可以在 web.xml 中配置自启动的 Servlet 或定义 Web容器监听器 (ServletContextListener),借助二者中的任何一个,就可以完成 Spring Web 应用上下文的工作。