【Spring源码分析系列】ApplicationContext 相关接口架构分析
【原创文章,转载请注明出处】【本文地址】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 相关接口架构分析的更多相关文章
- Spring源码分析(一):从哪里开始看spring源码(系列文章基于Spring5.0)
概述 对于大多数第一次看spring源码的人来说,都会感觉不知从哪开始看起,因为spring项目源码由多个子项目组成,如spring-beans,spring-context,spring-core, ...
- Spring源码解析系列汇总
相信我,你会收藏这篇文章的 本篇文章是这段时间撸出来的Spring源码解析系列文章的汇总,总共包含以下专题.喜欢的同学可以收藏起来以备不时之需 SpringIOC源码解析(上) 本篇文章搭建了IOC源 ...
- Spring源码阅读系列总结
最近一段时间,粗略的查看了一下Spring源码,对Spring的两大核心和Spring的组件有了更深入的了解.同时在学习Spring源码时,得了解一些设计模式,不然阅读源码还是有一定难度的,所以一些重 ...
- Spring 源码学习系列
前言 Spring框架之于 JavaEE 程序员来说,犹如锄头之于农民.Java 程序员每天都要使用Spring框架,Spring框架也确实是个可手的工具. 最初使用Spring的时候,我们需要配置m ...
- 【原】Spring源码浅析系列-导入源码到Eclipse
用了Spring几年,平时也断断续续在项目里看过一些源码,大多都是比较模糊的,因为一旦从一个地方进去就找不到方向了,只能知道它大概是做了什么事能达到这个功能或者效果,至于细节一般没有太深入去研究.后来 ...
- Spring源码由浅入深系列一 简介
概述: Spring是一个企业级的开源框架.它提供轻量级的依赖注入.面向切面编程.全方位的整合框架.下图是Spring框架的组成部分,各部分内容作了简单说明. 依赖注入: 依赖注入是S ...
- Spring源码由浅入深系列二 类结构
BeanFactory 上一章中,我们提过Spring的依赖注入容器是BeanFactory.BeanFactory是一个基础接口,它有一个默认实现类:DefaultListableBeanFacto ...
- Spring源码窥探之:xxxAware接口
Aware接口是一个标志性接口,继承此接口的接口xxxAware的实现类,在容器创建完成后,会回调实现方法,下面举例: 1. 有很多xxxAware接口,下面举两个例子 /** * descripti ...
- Spring源码由浅入深系列三 refresh
spring中的refresh是一个相当重要的方法.它完成IOC的第一个阶段,将xml中的bean转化为beanDefinition.详细说明如上图所示. 在上图中,创建obtainFreshBean ...
随机推荐
- C#通熟易懂观察者模式
观察者模式(有时又被称为模型-视图(View)模式.源-收听者(Listener)模式或从属者模式)是软件设计模式的一种.将观察者(watcher)和被观察者(subject)完美分离. 这里讲一个场 ...
- Canvas的基本用法
canvas没有设置宽度和高度的时候,会初始化宽度:300像素和高度:150像素.可以使用CSS来定义大小,但在绘制时图像会伸缩以适应它的框架尺寸:如果CSS的尺寸与初始画布的比例不一致,它会出现扭曲 ...
- types.go
} type ChannelStatsList []*ChannelStats func (c ChannelStatsList) Len() int { return len(c) } func ( ...
- bzoj 1098 poi2007 办公楼 bfs+链表
题意很好理解,求给出图反图的联通块个数. 考虑这样一个事情:一个联通块里的点,最多只会被遍历一次,再遍历时没有任何意义 所以用链表来存,每遍历到一个点就将该点删掉 #include<cstdio ...
- BZOJ_2734_[HNOI2012]集合选数_构造+状压DP
BZOJ_2734_[HNOI2012]集合选数_构造+状压DP 题意:<集合论与图论>这门课程有一道作业题,要求同学们求出{1, 2, 3, 4, 5}的所有满足以 下条件的子集:若 x ...
- Selenium在定位的class含有空格的复合类的解决办法整理
1.class属性唯一但是有空格,选择空格两边唯一的哪一个 <div id="tempConfigTable" class="dtb-style-1 table-d ...
- CentOS7解决firefox无法启用ibus中文输入的问题
最近换电脑,要换掉使用了6年的旧环境,开始折腾重装系统: 下了minimal版本的CentOS7.4,然后开始一点点装想用的东西,多少找到一点十年前折腾LFS的感觉:然后竟然被输入法拌住了半天,事后回 ...
- HTML标题
HTML 标题 在 HTML 文档中,标题很重要. HTML 标题 标题(Heading)是通过 <h1> - <h6> 标签进行定义的. <h1> 定义最大的标题 ...
- Spring事务的一些特性
事务的四大特征 1.原子性:一个事务中所有对数据库的操作是一个不可分割的操作序列,要么全做要么全不做 2.一致性:数据不会因为事务的执行而遭到破坏 3.隔离性:一个事物的执行,不受其他事务的干扰,即并 ...
- Java解析表达式
需求 思路 总结 需求 指定一个String表达式,表达式符合给出的运算符规范,比如:2!=2 and 2>=3 or 4<=4,计算出表达式的结果(true or false). 支持的 ...