1:类图
从类图中可以看出来主要的父接口以及提供的能力如下:
类名 | 作用 |
---|---|
BeanFactory | 比较基础和简单的bean容器,主要通过getBean(xxx)的API提供了获取bean的操作,通过isPrototype,isSingleton等方法判断是原型bean,还是单例bean,通过containerBean(xxx)判断是否包含某bean的能力。 |
HierarchicalBeanFactory | 是BeanFactory的子接口,提供了通过getParentBeanFactory(xxx)方法获取父容器的操作,正是名字中Hierarchical层级的由来 |
ListableBeanFactory | 提供了列举bean,即获取bean列表的能力,如通过getBeansOfType(xxx)获取某类型的bean的集合,getBeanNamesForType(xxx),获取某类型的bean的名称的集合 |
ApplicationEventPublisher | 函数式接口,用于向事件监听器发布事件 |
ResourceLoader | 资源获取接口,如获取xml文件,jar,jar中的class,基于http的远端文件等各种资源,具体可以参考:https://blog.csdn.net/wang0907/article/details/113913888 |
ResourcePatternResolver | ResourceLoader的子类,提供了批量获取资源的操作,具体可以参考:https://blog.csdn.net/wang0907/article/details/113913888 |
MessageSource | 解析message的策略接口,用于实现i18n |
EnvironmentCapable | 函数式接口,通过getEnvironment方法定义获取Environment的操作,关于Environment可以参考:https://blog.csdn.net/wang0907/article/details/116232260 |
2:ApplicationContext子接口
ApplicationContext的子接口主要有2个,一个是WebApplicationContext
,另一个是ConfigurableApplicationContext
,我们来分别看下这两个接口提供的能力。
2.1:WebApplicationContext
该接口只有一个方法getServletContext
,用来获取Servlet的上下文对象,另外还定义了一些web相关的一些常量,源码如下:
public interface WebApplicationContext extends ApplicationContext {
// 用于定义root应用程序上线文的key,web容器启动成功后保存在servletcontext中使用的key,如果是启动失败的话,这里保存的是失败的原因
String ROOT_WEB_APPLICATION_CONTEXT_ATTRIBUTE = WebApplicationContext.class.getName() + ".ROOT";
// 定义bean的Request级别的作用域,即一个请求一个bean
// 作为singleton和prototype作用域的补充
String SCOPE_REQUEST = "request";
// 定义bean的session级别的作用域,即一个会话一个bean
// 作为singleton,prototype作用域的补充
String SCOPE_SESSION = "session";
// 定义bean的application级别的作用域
String SCOPE_APPLICATION = "application";
// 定义ServletContext,即servlet上线文对象在容器中的
// bean名称
String SERVLET_CONTEXT_BEAN_NAME = "servletContext";
String CONTEXT_PARAMETERS_BEAN_NAME = "contextParameters";
String CONTEXT_ATTRIBUTES_BEAN_NAME = "contextAttributes";
// 返回servlet 标准API中的当前应用程序对应的ServletContext对象
@Nullable
ServletContext getServletContext();
}
2.2:ConfigurableApplicationContext
从名字中的Configurable
就可以知道,该类是扩展ApplicationContext,提供了相关配置的能力
,下面我们通过源码看下到底是提供了哪些可配置项:
public interface ConfigurableApplicationContext extends ApplicationContext, Lifecycle, Closeable {
// 定义configlocation多个时可用的分隔符
String CONFIG_LOCATION_DELIMITERS = ",; \t\n";
// 设置容器中ConversionService属性类型转换API的bean名称
String CONVERSION_SERVICE_BEAN_NAME = "conversionService";
// 设置在bean工厂容器中Environment的bean名称
// 关于Environment可以参考:https://blog.csdn.net/wang0907/article/details/116232260
String ENVIRONMENT_BEAN_NAME = "environment";
// 设置应用程序上下文的唯一ID
void setId(String id);
// 设置父容器
void setParent(@Nullable ApplicationContext parent);
/**
* Set the {@code Environment} for this application context.
* @param environment the new environment
* @since 3.1
*/
// 设置Environment
// 关于Environment可以参考:https://blog.csdn.net/wang0907/article/details/116232260
void setEnvironment(ConfigurableEnvironment environment);
// 获取应用程序的Environment
@Override
ConfigurableEnvironment getEnvironment();
// 添加BeanFactoryPostProcessor,在refresh时,bean definition
// 被解析为bean之前注册到容器中,在生成bean之前会被应用可以用来
// 修改bean定义信息,关于BeanFactoryPostProcessor,可以参考
// https://blog.csdn.net/wang0907/article/details/115440135
// https://blog.csdn.net/wang0907/article/details/115443697
// https://blog.csdn.net/wang0907/article/details/115483144
void addBeanFactoryPostProcessor(BeanFactoryPostProcessor postProcessor);
// 注册应用程序监听器,在context进行refresh时,或者是context进行
// 关闭时会被应用,或者其他
void addApplicationListener(ApplicationListener<?> listener);
// 注册协议解析器
void addProtocolResolver(ProtocolResolver resolver);
// 加载或者是刷新配置->生成bean定义->生成bean
// 以及应用相关的beanpostprocessor,这是一个启动方法,如果是启动失败的话,应该负责销毁已经创建的单例bean
// ,换句话说就是,要么所有的单例bean都完成了注册,要么是所有的单例bean
// 都没有完成注册,如果是初始化失败则抛出BeanException
// 如果是进行了多次的初始化则抛IllegalStateException,因为refresh只
// 支持一次
void refresh() throws BeansException, IllegalStateException;
// 注册虚拟机关闭钩子
void registerShutdownHook();
// 关闭应用程序上线文,是方法所有的资源和锁,销毁所有缓存的单例bean,
// 本方法可以多次调用,后续的调用直接忽略,而不会抛出异常
@Override
void close();
// 获取应用程序环境是否是激活状态的,即refresh方法调用完毕
// 但是close方法还没有被调用
boolean isActive();
ConfigurableListableBeanFactory getBeanFactory() throws IllegalStateException;
}
其中的Lifecycle接口
,是spring定义的context生命周期管理的接口,定义了start
和stop
方法来启动和停止组件,Closable
接口是jdk中定义的接口,代表该资源是可关闭的,比如配合该接口可以使用try-with-resource
语法糖等。
2.3:ConfigurableWebApplication
这是WebApplicationContext和ConfigurableApplicationContext的公共的子接口,拥有了这两个接口的能力,提供了一个可配置configurable
,可管理生命周期
,可关闭closable
的接口,看下源码:
public interface ConfigurableWebApplicationContext extends WebApplicationContext, ConfigurableApplicationContext {
// 设置servletcontext
void setServletContext(@Nullable ServletContext servletContext);
// 设置和获取servletconfig
void setServletConfig(@Nullable ServletConfig servletConfig);
@Nullable
ServletConfig getServletConfig();
// 设置和获取config location(s)
void setConfigLocation(String configLocation);
void setConfigLocations(String... configLocations);
@Nullable
String[] getConfigLocations();
}
对于ApplicationContext,如基于xml配置文件的ClassPathXmlAppplicationContext
,基于注解的AnnotationConfigApplicationContext
等,下面我们以ClassPathXmlApplicationContext为例,来看下。
3:ClassPathXmlApplicationContext
我们先来看下类图,然后再依次分析每个类和接口的作用。
3.1:类图
我们以ApplicationContext这条主线来看下主要的的层级结构:
AbstractApplicationContext
AbstractRefreshableApplicationContext
AbstractRefreshableConfigApplicationContext
AbstractXmlApplicationContext
ClassPathXmlApplicationContext
接着再来看下其它的接口:
BeanFactory:bean容器的顶层接口,提供了基础的bean的管理
MessageSource:消息message相关,实现国际化
ResourceLoader:资源加载,参考:https://blog.csdn.net/wang0907/article/details/113913888
ApplicationEventPublisher:事件发布
Lifecycle:管理生命周期
Closable:关闭,释放资源
InitializingBean:自定义初始化,调用完毕populateBean方法设置属性后调用
BeanNameAware:感知bean名称
EnvironmentCapable:系统Environment相关,properties,profiles
3.2:MessageSource
源码如下:
// 解析消息的策略接口,支持参数化和国际化诸如此类的消息,spring为生产环境
// 提供了2个开箱即用的是实现类,ResourceBundleMessageResouce,
// ReloadableResouceBundleMessage
public interface MessageSource {
// 解析消息。如果根据code没有获取到消息则返回默认消息
@Nullable
String getMessage(String code, @Nullable Object[] args, @Nullable String defaultMessage, Locale locale);
// 解析消息,如果是根据code没有获取到,则抛出NoSuchMessageException
String getMessage(String code, @Nullable Object[] args, Locale locale) throws NoSuchMessageException;
// 通过自定义的消息解析器解析消息
String getMessage(MessageSourceResolvable resolvable, Locale locale) throws NoSuchMessageException;
}
在AbstractApplicationContext中提供了getMessage(xxx)
的具体的实现,源码如下:
org.springframework.context.support.AbstractApplicationContext#getMessage(java.lang.String, java.lang.Object[], java.util.Locale)
public String getMessage(String code, @Nullable Object[] args, Locale locale) throws NoSuchMessageException {
// <20210504 1923>
return getMessageSource().getMessage(code, args, locale);
}
<20210504 1923>
处getMessageSource.getMessage(xx)
执行的方法在AbstractMessageSource
中,具体源码我没看,大概贴在这里吧。
org.springframework.context.support.AbstractMessageSource#getMessage(java.lang.String, java.lang.Object[], java.util.Locale)
public final String getMessage(String code, @Nullable Object[] args, Locale locale) throws NoSuchMessageException {
String msg = getMessageInternal(code, args, locale);
if (msg != null) {
return msg;
}
String fallback = getDefaultMessage(code);
if (fallback != null) {
return fallback;
}
throw new NoSuchMessageException(code, locale);
}
3.3:ResourcePatternResolver
提供了路径批量转换为Resource的策略接口,最终的实现了是PathMatchingResoucePatternResolver
,接口定义如下:
// 将路径模式(如ant风格的模式)转换为一组Resource对象。是ResourceLoader
// 的扩展接口,扩展为支持多个资源的同时获取,而不用循环多次获取,
// PathMatchingResourcePatternResolver是其常用的实现类
// 路径模式可以形如:/WEB-INF/*-context.xml,同时该接口鼓励
// 使用形如classpath*:来匹配classpath下多个资源
public interface ResourcePatternResolver extends ResourceLoader {
// 在classpath下单次加载多个资源文件的"假的classpath前缀",内部会
// 按照真正支持的classpath方式进行处理和获取资源
String CLASSPATH_ALL_URL_PREFIX = "classpath*:";
// 通过模式路径获取一组Resouce对象
Resource[] getResources(String locationPattern) throws IOException;
}
3.4:EnvironmentCapable
有能力提供Environment
的接口类,通过方法getEnvironment(xxx)
方法返回Environment,接口源码如下:
// 表明拥有一个Environment引用的接口。
public interface EnvironmentCapable {
// 返回Environment组件
Environment getEnvironment();
}
实现在AbstractApplicationContext
中,源码如下:
org.springframework.context.support.AbstractApplicationContext#getEnvironment
public ConfigurableEnvironment getEnvironment() {
if (this.environment == null) {
this.environment = createEnvironment();
}
return this.environment;
}
org.springframework.context.support.AbstractApplicationContext#createEnvironment
protected ConfigurableEnvironment createEnvironment() {
return new StandardEnvironment();
}
3.5:Lifecycle
生命周期声明的接口,源码如下:
public interface Lifecycle {
// 启动组件,注意如果组件已经启动了也不应该抛出异常
void start();
// 停止组件
void stop();
// 检查组件是否在运行中
boolean isRunning();
}
看下AbstractApplicationContext
中提供的具体实现:
// 管理context中bean的生命周期的类
@Nullable
private LifecycleProcessor lifecycleProcessor;
@Override
public void start() {
getLifecycleProcessor().start();
// 启动后,发布ContextStartEvent
publishEvent(new ContextStartedEvent(this));
}
@Override
public void stop() {
getLifecycleProcessor().stop();
// 停止后发布ContextStoppedEvent
publishEvent(new ContextStoppedEvent(this));
}
@Override
public boolean isRunning() {
return (this.lifecycleProcessor != null && this.lifecycleProcessor.isRunning());
}
3.6:Closable
用于释放资源和进行其它清理的工作的接口,源码如下:
// 该接口代表是可以关闭的,通过调用close()方法来释放持有的资源(如文件句柄)
public interface Closeable extends AutoCloseable {
// 通过该方法关闭对象关联的资源,如果是已经关闭,则该方法的调用没有任何效果
public void close() throws IOException;
}
在AbstractApplicationContext中的实现如下:
org.springframework.context.support.AbstractApplicationContext#close
// 关闭应用程序上下文,销毁bean工厂中所有的bean,最终委托方法doClose执行
// 具体的关闭过程。如果是注册了虚拟机关闭钩子,如果是不在需要的话同样会将其移除
@Override
public void close() {
synchronized (this.startupShutdownMonitor) {
// <20210505 1453>
doClose();
// 如果注册了虚拟机关闭钩子,则将其移除
// 关于虚拟机关闭钩子可参考:https://blog.csdn.net/wang0907/article/details/116419006
if (this.shutdownHook != null) {
try {
Runtime.getRuntime().removeShutdownHook(this.shutdownHook);
}
catch (IllegalStateException ex) {
}
}
}
}
<20210505 1453>
处源码如下:
org.springframework.context.support.AbstractApplicationContext#doClose
// 真正执行上线文关闭的方法。发布ContextClosedEvent事件,并销毁bean工厂中
// 所有的单例bean。会被close方法调用,或者是被虚拟机关闭钩子调用(如果有的话)
protected void doClose() {
// 检测状态
if (this.active.get() && this.closed.compareAndSet(false, true)) {
...snip...
try {
// 发布ContextClosedEvent
publishEvent(new ContextClosedEvent(this));
}
catch (Throwable ex) {
...snip...
}
...snip...
// 销毁bean工厂中缓存的所有单例bean
destroyBeans();
// 关闭bean工厂
closeBeanFactory();
// 留给子类的模板方法,以便子类有需要关闭的资源
onClose();
// 修改bean工厂的状态为未激活
this.active.set(false);
}
}
3.7:InitializingBean
该方法在属性设置完毕后会被调用,只有一个方法afterPropertiesSet
,源码如下:
org.springframework.beans.factory.InitializingBean
// bean如果是实现了该接口,会在所有的属性设置完毕后被调用一次,可以执行
// 定制化的初始化工作,或者是仅仅对强制的属性做检查。但是这种是侵入式
// 的编程方式了,如果是不想这样,也可以通过配置init-method的方式来实现
public interface InitializingBean {
// 当bean工厂设置当前bean的属性完毕后调用的方法
void afterPropertiesSet() throws Exception;
}
在ApplicationContext体系中的实现类是AbstractRefreshableConfigApplicationContext
,源码如下:
org.springframework.context.support.AbstractRefreshableConfigApplicationContext#afterPropertiesSet
@Override
publicvoid afterPropertiesSet() {
if (!isActive()) {
// <20210505 1517>
refresh();
}
}
<20210505 1517>
关于refresh方法参考这里。
3.8:BeanNameAware
用于设置bean名称,在AbstractRefreshableConfigApplicationContext
中提供具体实现,源码如下:
org.springframework.context.support.AbstractRefreshableConfigApplicationContext#setBeanName
@Override
public void setBeanName(String name) {
if (!this.setIdCalled) {
super.setId(name);
setDisplayName("ApplicationContext '" + name + "'");
}
}