【原创文章,转载请注明出处】【本文地址】http://www.cnblogs.com/zffenger/p/5813470.html

在使用Spring的时候,我们经常需要先得到一个ApplicationContext对象,然后从该对象中获取我们配置的Bean对象。ApplicationContext隶属于org.springframework.context,是SpringFramework中Bean的管理者,为SpringFramework的诸多功能提供支撑作用。

下图是Spring-4.3.2.RELEASE版本中ApplicationContext相关的UML类视图(浅绿色的为接口,浅黄色的为类):

BeanFactory系列接口:

public interface BeanFactory

BeanFactory 是 Spring 管理 Bean 的最顶层接口,是一个 Bean 容器, 管理一系列的 bean,每一个 bean 使用一个String 类型的 name(或称之为id) 来唯一确定,这些 Bean 可以是 prototype 的或者 singleton的 。Spring 提倡使用依赖注入(Dependency Injection) 的方式装配 Bean。BeanFactory从“configuration source”加载Bean的定义,configuration source 可以是xml文件或者properties文件甚至是数据库。

public interface HierarchicalBeanFactory extends BeanFactory

BeanFactory的子接口HierarchicalBeanFactory是一个具有层级关系的Bean 工厂,拥有属性parentBeanFactory。当获取 Bean对象时,如果当前BeanFactory中不存在对应的bean,则会访问其直接 parentBeanFactory 以尝试获取bean 对象。此外,还可以在当前的 BeanFactory 中 override 父级BeanFactory的同名bean。

public interface ListableBeanFactory extends BeanFactory

ListableBeanFactory 继承了BeanFactory,实现了枚举方法可以列举出当前BeanFactory中所有的bean对象而不必根据name一个一个的获取。 如果 ListableBeanFactory 对象还是一个HierarchicalBeanFactory则getBeanDefinitionNames()方法只会返回当前BeanFactory中的Bean对象而不会去父级BeanFactory中查询。

其他接口:

public interface PropertyResolver

配置文件解析器的最顶级接口,解析配置文件获取属性值等作用

public interface Environment extends PropertyResolver

提供当前Application运行的所需环境

public interface EnvironmentCapable

这是一个Environment Holder,只有一个方法:Environment getEnvironment() 用来获取Environment对象

public interface ApplicationEventPublisher

该接口的功能是publish Event,向事件监听器(Listener)发送事件消息

public interface MessageSource

解析message的策略接口,方法形如: String getMessage(String, Object[], String, Locale),用于支撑国际化等功能

public interface ResourcePatternResolver extends ResourceLoader

其中ResourceLoader用于从一个源(如InputStream等)加载资源文件,ResourcePatternResolver 是ResourceLoader的子类,根据 path-pattern 加载资源。

ApplicationContext接口:

public interface ApplicationContext extends EnvironmentCapable, ListableBeanFactory, HierarchicalBeanFactory, MessageSource, ApplicationEventPublisher, ResourcePatternResolver

重点来了,ApplicationContext接口继承众多接口,集众多接口功能与一身,为Spring的运行提供基本的功能支撑。根据程序设计的“单一职责原则”,其实每个较顶层接口都是“单一职责的”,只提供某一方面的功能,而ApplicationContext接口继承了众多接口,相当于拥有了众多接口的功能,下面看看它的主要功能:

  • 首先,它是个BeanFactory,可以管理、装配bean,可以有父级BeanFactory实现Bean的层级管理(具体到这里来说它可以有父级的ApplicationContext,因为ApplicationContext本身就是一个BeanFactory。这在web项目中很有用,可以使每个Servlet具有其独立的context, 所有Servlet共享一个父级的context),它还是Listable的,可以枚举出所管理的bean对象。
  • 其次,它是一个ResourceLoader,可以加载资源文件;
  • 再次,它可以管理一些Message实现国际化等功能;
  • 还有,它可以发布事件给注册的Listener,实现监听机制。

ApplicationContext 的子接口:

ApplicationContext 接口具有两个直接子接口,分别是:

org.springframework.context.ConfigurableApplicationContext
org.springframework.web.context.WebApplicationContext

分别看这两个子接口:

public interface ConfigurableApplicationContext extends ApplicationContext, Lifecycle, Closeable

根据接口名可以判决,该接口是可配置的!ApplicationContext 接口本身是 read-only 的,所以子接口 ConfigurableApplicationContext 就提供了如setID()、setParent()、setEnvironment()等方法,用来配置ApplicationContext。

再看其继承的另外两个接口:

  • Lifecycle:Lifecycle接口中具有start()、stop()等方法,用于对context生命周期的管理;
  • Closeable:Closeable是标准JDK所提供的一个接口,用于最后关闭组件释放资源等;
public interface WebApplicationContext extends ApplicationContext

该接口仅仅在原接口基础上提供了getServletContext(),用于给servlet提供上下文信息。

public interface ConfigurableWebApplicationContext extends WebApplicationContext, ConfigurableApplicationContext

这里 ConfigurableWebApplicationContext 又将上述两个接口结合起来,提供了一个可配置、可管理、可关闭的WebApplicationContext,同时该接口还增加了setServletContext(),setServletConfig()等set方法,用于装配WebApplicationContext。

到这里ApplicationContext相关接口基本上已经讲完了,总结起来就两大接口:

org.springframework.context.ConfigurableApplicationContext
org.springframework.web.context.ConfigurableWebApplicationContext

对于普通应用,使用ConfigurableApplicationContext 接口的实现类作为bean的管理者,对于web应用,使用ConfigurableWebApplicationContext 接口的实现类作为bean的管理者。这两个接口,从结构上讲他们是继承关系,从应用上讲他们是平级关系,在不同的领域为Spring提供强大的支撑。

ApplicationContext相关实现类设计:

Spring是一个优秀的框架,具有良好的结构设计和接口抽象,它的每一个接口都是其功能具体到各个模块中的高度抽象,实际使用过程中相当于把接口的各个实现类按照接口所提供的组织架构装配起来以提供完整的服务,可以说掌握了Spring的接口就相当于掌握了Spring的大部分功能。

ApplicationContext 的实现类众多,然而

上文中分析了 ApplicationContext 接口的各个功能,下面将分析 ApplicationContext 的实现类对上述接口的各个功能都是怎样实现的(PS. 限于篇幅,这里仅仅指出上述各个功能在实现类中什么位置通过什么方法实现,至于其具体实现过程,每一个功能拿出来都可以单独写一篇文章了,这里不进行详述)。至于实现类又扩展了其他接口或者继承了其他父类,这些只是实现类为了扩展功能或者为了对实现上述接口提供便利而做的事情,对ApplicationContext接口抽象出来的功能没有影响或者没有太大帮助,因此略去。

以ClassPathXmlApplicationContext为例,其主要继承关系如下:

org.springframework.context.support.AbstractApplicationContext
org.springframework.context.support.AbstractRefreshableApplicationContext
org.springframework.context.support.AbstractRefreshableConfigApplicationContext
org.springframework.context.support.AbstractXmlApplicationContext
org.springframework.context.support.ClassPathXmlApplicationContext

而最顶层抽象类 AbstractApplicationContext 又实现了 ConfigurableApplicationContext 接口。

AbstractApplicationContext extends DefaultResourceLoader    implements ConfigurableApplicationContext, DisposableBean

根据上文所述,这里略去其父类 DefaultResourceLoader 和接口 DisposableBean ,只关注接口 ConfigurableApplicationContext,回忆一下该的主要功能:

Configable, //可配置(该接口本身扩展的功能)
Lifecycle, //生命周期可管理
Closeable,//可关闭(释放资源)
EnvironmentCapable,//可配置Environment
MessageSource, //可管理message实现国际化等功能
ApplicationEventPublisher, //可publish事件,调用Listener
ResourcePatternResolver,//加载pattern指定的资源
ListableBeanFactory, HierarchicalBeanFactory,//管理Bean的生命周期,这个最重要,放最后说

然后回到最顶层抽象类 AbstractApplicationContext ,该抽象类可以说是 ClassPathXmlApplicationContext 继承结构中代码量最多的类,上述的大部分功能也都在该类中实现。该类采用模板方法模式,实现了上述功能的大部分逻辑,然后又抽出许多 protected方法(或 abstract 方法)供子类override 。

各功能的实现列举如下:

Configable:如setParent/setEnvironment等方法,由AbstractApplicationContext实现 。代码示例:

@Override
public void setParent(ApplicationContext parent) {
this.parent = parent;
if (parent != null) {
Environment parentEnvironment = parent.getEnvironment();
if (parentEnvironment instanceof ConfigurableEnvironment) {
getEnvironment().merge((ConfigurableEnvironment) parentEnvironment);
}
}
}

Lifecycle:AbstractApplicationContext拥有一个LifecycleProcessor实例,用于管理自身的生命周期,AbstractApplicationContext的Lifecycle方法如start、stop等由会代理给LifecycleProcessor进行处理,代码示例:

@Override
public void start() {
getLifecycleProcessor().start();
publishEvent(new ContextStartedEvent(this));
}

Closeable:由AbstractApplicationContext实现,用于关闭ApplicationContext销毁所有beans,此外如果注册有JVM shutdown hook,同样要将其移除 。代码示例:

@Override
public void close() {
synchronized (this.startupShutdownMonitor) {
doClose();
if (this.shutdownHook != null) {
try {
Runtime.getRuntime().removeShutdownHook(this.shutdownHook);
}catch (IllegalStateException ex) {
// ignore - VM is already shutting down
}
}
}
}

EnvironmentCapable:由AbstractApplicationContext实现,其持有一个ConfigurableEnvironment实例,用来实现EnvironmentCapable接口的getEnvironment方法 。代码示例:

@Override
public ConfigurableEnvironment getEnvironment() {
if (this.environment == null) {
this.environment = createEnvironment();
}
return this.environment;
}

MessageSource:AbstractApplicationContext持有一个MessageSource实例,将MessageSource接口的方法代理给该实例来完成 。代码示例:

@Override
public String getMessage(String code, Object args[], String defaultMessage, Locale locale) {
return getMessageSource().getMessage(code, args, defaultMessage, locale);
}

ApplicationEventPublisher:由AbstractApplicationContext实现,如果存在父级ApplicationContext,则同样要将event发布给父级ApplicationContext。代码示例:

@Override
public void publishEvent(ApplicationEvent event) {
Assert.notNull(event, "Event must not be null");
if (logger.isTraceEnabled()) {
logger.trace("Publishing event in " + getDisplayName() + ": " + event);
}
getApplicationEventMulticaster().multicastEvent(event);
if (this.parent != null) {
this.parent.publishEvent(event);
}
}

ResourcePatternResolver:AbstractApplicationContext持有一个ResourcePatternResolver实例,该接口的方法代理给该实例完成 。代码示例:

@Override
public Resource[] getResources(String locationPattern) throws IOException {
return this.resourcePatternResolver.getResources(locationPattern);
}

ListableBeanFactory, HierarchicalBeanFactory: AbstractApplicationContext 间接实现了这两个接口,然而却并没有实现任何BeanFactory的任何功能。AbstractApplicationContext 拥有一个 ConfigurableListableBeanFactory实例,所有BeanFactory的功能都代理给该实例完成。代码示例:

@Override
public Object getBean(String name) throws BeansException {
assertBeanFactoryActive();
return getBeanFactory().getBean(name);
}

而AbstractApplicationContext 的 getBeanFactory() 方法是一个抽象方法,即由子类来提供这个BeanFactory。代码示例:

@Override
public abstract ConfigurableListableBeanFactory getBeanFactory() throws IllegalStateException;

在 ClassPathXmlApplicationContext 的继承体系中,类AbstractRefreshableApplicationContext实现了这个 getBeanFactory()方法。这里getBeanFactory()方法会创建一个DefaultListableBeanFactory实例作为返回值。

小结

本文以 Spring Framework 的 ApplicationContext 为中心,分析了 ApplicationContext 的机构体系和功能实现。接口 ApplicationContext 继承了众多接口,可以满足应用中“面向接口编程”的常用功能需求。抽象类 AbstractApplicationContext 实现了ApplicationContext 接口中简单不易变动的部分,然后通过“组合”将众多“容易变动”功能代理给它的一些成员变量来实现,最后再使用模板方法模式让子类为父类提供一些函数的支持或者设置替换父类的上述成员变量,从而实现了“对扩展开放,对修改封闭”的设计原则,为Spring Framework 提供了灵活性大可扩展性强的架构支撑。

【原创文章,转载请注明出处】【本文地址】http://www.cnblogs.com/zffenger/p/5813470.html

【Spring源码分析系列】ApplicationContext 相关接口架构分析的更多相关文章

  1. Spring源码分析(一):从哪里开始看spring源码(系列文章基于Spring5.0)

    概述 对于大多数第一次看spring源码的人来说,都会感觉不知从哪开始看起,因为spring项目源码由多个子项目组成,如spring-beans,spring-context,spring-core, ...

  2. Spring源码解析系列汇总

    相信我,你会收藏这篇文章的 本篇文章是这段时间撸出来的Spring源码解析系列文章的汇总,总共包含以下专题.喜欢的同学可以收藏起来以备不时之需 SpringIOC源码解析(上) 本篇文章搭建了IOC源 ...

  3. Spring源码阅读系列总结

    最近一段时间,粗略的查看了一下Spring源码,对Spring的两大核心和Spring的组件有了更深入的了解.同时在学习Spring源码时,得了解一些设计模式,不然阅读源码还是有一定难度的,所以一些重 ...

  4. Spring 源码学习系列

    前言 Spring框架之于 JavaEE 程序员来说,犹如锄头之于农民.Java 程序员每天都要使用Spring框架,Spring框架也确实是个可手的工具. 最初使用Spring的时候,我们需要配置m ...

  5. 【原】Spring源码浅析系列-导入源码到Eclipse

    用了Spring几年,平时也断断续续在项目里看过一些源码,大多都是比较模糊的,因为一旦从一个地方进去就找不到方向了,只能知道它大概是做了什么事能达到这个功能或者效果,至于细节一般没有太深入去研究.后来 ...

  6. Spring源码由浅入深系列一 简介

    概述: Spring是一个企业级的开源框架.它提供轻量级的依赖注入.面向切面编程.全方位的整合框架.下图是Spring框架的组成部分,各部分内容作了简单说明. 依赖注入:         依赖注入是S ...

  7. Spring源码由浅入深系列二 类结构

    BeanFactory 上一章中,我们提过Spring的依赖注入容器是BeanFactory.BeanFactory是一个基础接口,它有一个默认实现类:DefaultListableBeanFacto ...

  8. Spring源码窥探之:xxxAware接口

    Aware接口是一个标志性接口,继承此接口的接口xxxAware的实现类,在容器创建完成后,会回调实现方法,下面举例: 1. 有很多xxxAware接口,下面举两个例子 /** * descripti ...

  9. Spring源码由浅入深系列三 refresh

    spring中的refresh是一个相当重要的方法.它完成IOC的第一个阶段,将xml中的bean转化为beanDefinition.详细说明如上图所示. 在上图中,创建obtainFreshBean ...

随机推荐

  1. SSM-MyBatis-13:Mybatis中多条件查询

    ------------吾亦无他,唯手熟尔,谦卑若愚,好学若饥------------- 实体类 public class Book { private Integer bookID; private ...

  2. Git Submodule简单操作

    基于组件的项目很多,但是如果直接用包的方式直接引用到项目中,如果出现问题很难进行调试的操作,也很难进行组件的优化和管理,所以写了一篇文章来介绍下git submodule的用法,用submodule可 ...

  3. 概率与统计推断第二讲homework

    作业目的: 体会条件独立 1.现需要设计一个根据一个人是否是学生$S$(布尔变量)和其体重$W$(连续变量)判断该人的性别$G$(布尔变量).假设在给定$G$的情况下$S$和$W$独立,且假设概率分布 ...

  4. 用php过滤文字中的表情字符

    很多时候,如果文字中夹带表情,那么这些文字的处理就会出现问题,例如,如果一个用户的昵称带有表情,那么我怎么把这个昵称转换为拼音呢?在实际的开发中,我遇到了这个个问题,先是找到了 https://git ...

  5. java 基础之 反射技术

    1. java代码 在 java 语言中最核心的就是代码的运行, 按照面向对象的思想,在调用java代码时往往需要先创建对象,再调用方法, 而写在方法中的即所谓的java 代码 一段java代码在程序 ...

  6. Android 属性动画(Property Animation) 完全解析 (下)

    转载请标明出处:http://blog.csdn.net/lmj623565791/article/details/38092093 上一篇Android 属性动画(Property Animatio ...

  7. Java 读书笔记 (十三) for each 循环

    JDK 1.5引进了一种新的循环类型,被称为foreach循环或者加强型循环,它能在不使用下标的情况下遍历数组. 实例: public class TestArray{ public static v ...

  8. 前端BUG监控神器

    有时候,看到用户的反馈,我们往往会一脸茫然,因为反馈的信息太少了. 比如有用户反馈登录不了.为了解这个问题,一般的流程是这样的:首先试试自己能不能登录网站,发现没问题:然后查看后台日志,发现最近没有登 ...

  9. Sql函数笔记一、case when

    Case具有两种格式.简单Case函数和Case搜索函数. 简单Case函数 CASE sex WHEN '1' THEN '男' WHEN '2' THEN '女' ELSE '其他' END   ...

  10. Elasticsearch笔记四之配置参数与核心概念

    在es根目录下有一个config目录,在此目录下有两个文件分别是elasticsearch.yml和logging.yml. logging.yml是日志文件,es也是使用log4j来记录日志的,我在 ...