Spring源码之ApplicationContext(六)
前言:
Spring的两大容器ApplicationContext与BeanFactory,顾名思义ApplicationContext是应用的上下文,BeanFactory是bean工厂。
但是从代码层面来看ApplicationContext接口是继承了BeanFactory接口的,也就是说两者都有做容器的能力,而ApplicationContext
相对BeanFactory而言他又多了一些其他的功能,所以在我们常用的web应用中,ApplicationContext应用上下文是作为容器的最佳选择,
当然spring也是希望我们这么用的。
本文将简单阐述一下两个容器的区别,着重在源码层面进行分析两个容器的相辅相成及在spring生态中起到的重要作用。
0.简单阐述ApplicationContext与BeanFactory两种容器的区别
1.作用不同,BeanFactory是用来读取bean的配置文件,管理bean的加载,实例化及其整个生命周期并维护其依赖关系
ApplicationContext除了拥有BeanFactory的所有功能外,还有更完整的供应用使用的框架功能,如国际化,aop,事务等
2.bean的初始化时机不同,BeanFactory在启动的时候不会初始化bean实例,只有在使用bean的时候才会初始化
ApplicationContext是在启动的时候就初始化了所有的单例bean
综上所述,关于两个容器的选择,则需要按需选取,对于我们常用的web应用,肯定是选取ApplicationContext容器,因为他就是为了应用而生
而在两个容器都可以使用的情况下,我们就结合我们的硬件来考虑,需要占用较小资源的选择BeanFactory,反之选择ApplicationContext
ApplicationContext应用上下文
从字面来看不太好懂,应用就是咱们常说的web应用或者是其他种类的提供服务的一个程序,而上下文咱们可以通俗的理解为他是一个应用的环境或者是容器,意思是拿到这个context对象了,就相当于咱们拥有掌控这个应用的能力了。
如果把应用比作是一个人的话,那么ApplicationContext就是人的大脑或者是思想,他掌控着整个应用的生命周期。
1.1.ApplicationContext的接口继承关系
关于ApplicationContext的接口定义关系如下图,两个直接的继承接口,一个间接的继承接口。
其中ConfigurableApplicationContext从字面来看是具有配置功能的ApplicationContext,主要是为应用上下文提供配置能力
WebApplicationContext是具体web功能的ApplicationContext,他能获取ServletContext
ConfigurableWebApplicationContext是结合上面两个接口的功能,配置ServletContext以及一些其他的web应用配置
1.1.1.先上ApplicationContext接口本尊,关于其父接口此处不作详细说明了,有兴趣的可以自行研究
本接口新定义的方法主要有:
1.getId()获取context的id
2.getApplicationName()获取应用名称
3.getStartupDate()获取启动时间
4.getParent()获取父容器
5.getAutowireCapableBeanFactory()获取有自动装配能力的BeanFactory
public interface ApplicationContext extends EnvironmentCapable, ListableBeanFactory, HierarchicalBeanFactory, MessageSource, ApplicationEventPublisher, ResourcePatternResolver {
@Nullable
String getId();
String getApplicationName();
String getDisplayName();
long getStartupDate();
@Nullable
ApplicationContext getParent();
AutowireCapableBeanFactory getAutowireCapableBeanFactory() throws IllegalStateException;
}
1.1.2.接下来看ConfigurableApplicationContext,主要提供了几个配置应用上下文的方法
本接口新定义的方法主要有:
1.setId(String id)设置id
2.setParent(@Nullable ApplicationContext parent)设置父容器
3.setEnvironment(ConfigurableEnvironment environment)设置环境变量
4.ConfigurableEnvironment getEnvironment()获取环境变量,重写了父接口的方法,此处我理解是为了返回
ConfigurableEnvironment类型的环境变量,这样相当于扩展了Environment。
5.addBeanFactoryPostProcessor(BeanFactoryPostProcessor postProcessor)添加bean工厂后置处理器
6.addApplicationListener(ApplicationListener<?> listener)添加监听器
7.addProtocolResolver(ProtocolResolver resolver)添加协议解析器
8.refresh()刷新容器
9.registerShutdownHook()关闭容器,这是一种推荐的关闭方式
10.close()关闭
11.isActive()是否活动状态
12.getBeanFactory()获取BeanFactory
public interface ConfigurableApplicationContext extends ApplicationContext, Lifecycle, Closeable {
//常量的定义省略不作解释
void setId(String id);
void setParent(@Nullable ApplicationContext parent);
void setEnvironment(ConfigurableEnvironment environment);
@Override
ConfigurableEnvironment getEnvironment();
void addBeanFactoryPostProcessor(BeanFactoryPostProcessor postProcessor);
void addApplicationListener(ApplicationListener<?> listener);
void addProtocolResolver(ProtocolResolver resolver);
void refresh() throws BeansException, IllegalStateException;
void registerShutdownHook();
@Override
void close();
boolean isActive();
ConfigurableListableBeanFactory getBeanFactory() throws IllegalStateException;
}
1.2.ApplicationContext的实现类继承关系
ApplicationContext的实现类按是否可实例化分为:抽象实现类与具体实现类
按功能分类的话可分为:可刷新的与普通的,这里的可刷新是指刷新BeanFactory,每次刷新都会销毁原工厂,创建新工厂
1.2.1.先详细解读一下ApplicationContext的第一个抽象实现类AbstractApplicationContext,
此类中的实现了应用上下文的大部分主流程方法.
此抽象类的功能就是对所有接口的方法进行实现,大体的流程这里不作说明,前文已经阐述了
这里值得注意的地方就是在最后部分有三个抽象方法:
protected abstract void refreshBeanFactory()//刷新BeanFactory
protected abstract void closeBeanFactory()//关闭BeanFactory
public abstract ConfigurableListableBeanFactory getBeanFactory()//获取BeanFactory
他们的抽象化我个人认为是为了扩展,这些会在后面几个实现类中体现
public abstract class AbstractApplicationContext extends DefaultResourceLoader implements ConfigurableApplicationContext {
//详细源码不贴出来了
}
1.2.2.下面介绍普通的应用上下文GenericApplicationContext,这里的普通就是他在初始化的时候直接new了BeanFactory
1.构造方法,针对不同的用途:
GenericApplicationContext()//空参,自己new的BeanFactory
GenericApplicationContext(DefaultListableBeanFactory beanFactory)//传入一个BeanFactory
GenericApplicationContext(ApplicationContext parent)//传入一个父容器,子容器的BeanFactory还是自己new
GenericApplicationContext(DefaultListableBeanFactory beanFactory, ApplicationContext parent)//传入父容器与BeanFactory
2.实现了AbstractApplicationContext中的抽象方法
refreshBeanFactory()//无具体实现内容,只是替换了id
cancelRefresh()//重写增强方法,将id置为null
closeBeanFactory()//将id置为null,没有完全的关闭销毁
getBeanFactory()//直接返回
3.实现了BeanDefinitionRegistry接口
此接口的作用,顾名思义就是BeanDefinition的注册,所以GenericApplicationContext拥有了操作BeanDefinition的功能,也就完整了作为应用容器的能力
下面列举比较重要的方法:
registerBeanDefinition()//注册BeanDefinition,是调用BeanDefinition里面的方法,后面说BeanFactory的时候详细讲解
public class GenericApplicationContext extends AbstractApplicationContext implements BeanDefinitionRegistry {
//...
}
1.2.3.具有刷新功能的抽象应用上下文AbstractRefreshableApplicationContext
AbstractRefreshableApplicationContext最大的特点就说有刷新容器上
在其父类AbstractApplicationContext的refresh()方法被调用时,
会调用到refreshBeanFactory()方法,进而重新创建一个bean工厂。
相对于GenericApplicationContext中refreshBeanFactory()方法的实现,该类中增加了销毁原工厂,创建新工厂的功能
public abstract class AbstractRefreshableApplicationContext extends AbstractApplicationContext {
//1.判断context中是否已有BeanFactory
//2.有的话就销毁,关闭旧的BeanFactory
//3.创建新的BeanFactory
@Override
protected final void refreshBeanFactory() throws BeansException {
if (hasBeanFactory()) {
destroyBeans();
closeBeanFactory();
}
try {
DefaultListableBeanFactory beanFactory = createBeanFactory();
beanFactory.setSerializationId(getId());
customizeBeanFactory(beanFactory);
loadBeanDefinitions(beanFactory);
synchronized (this.beanFactoryMonitor) {
this.beanFactory = beanFactory;
}
}
catch (IOException ex) {
throw new ApplicationContextException("I/O error parsing bean definition source for " + getDisplayName(), ex);
}
}
}
1.2.4.其他实现类的用途
1.具有刷新能力的抽象ApplicationContext
AbstractRefreshableApplicationContext的子类
AbstractRefreshableConfigApplicationContext扩展配置功能
AbstractRefreshableWebApplicationContext扩展Web功能
AnnotationConfigWebApplicationContext WEB应用直接可以使用的基于注解的ApplicationContext
XmlWebApplicationContext WEB应用直接可以使用的基于XML配置的ApplicationContext
AbstractXmlApplicationContext 基于XML配置的ApplicationContext抽象类
ClassPathXmlApplicationContext 解析应用根目录的
FileSystemXmlApplicationContext 解析文件系统目录的
2.常规的ApplicationContext
GenericApplicationContext
GenericXmlApplicationContext 常规的基于xml解析的ApplicationContext
AnnotationConfigApplicationContext 基于注解配置的ApplicationContext
GenericWebApplicationContext 常规的web应用的ApplicationContext
推荐阅读
-
Spring源码解密之默认标签的解析
-
Spring源码解密之自定义标签与解析
-
基于spring+hibernate+JQuery开发之电子相册(附源码下载)
-
Spring源码解密之默认标签的解析
-
Spring源码解密之自定义标签与解析
-
基于spring+hibernate+JQuery开发之电子相册(附源码下载)
-
PHP网页游戏学习之Xnova(ogame)源码解读(六)
-
Springboot源码分析之Spring循环依赖揭秘
-
Spring5源码解析4-refresh方法之invokeBeanFactoryPostProcessors
-
Spring源码解析之ConfigurableApplicationContext