关于之前的文章我们都是围绕spring的低级容器beanFactory展开,我们都知道spring的容器有两种,一种是beanFactory,俗称低级容器,在实际的开发中我们常用的xmlBeanFactory,当然低级的容器是无法满足日常的开发,那么ApplicationContext高级容器诞生了,在低级容器的基础上进行了拓展,如:事件的发布bean的生命周期的管理和多资源加载等,我们常用的是ClassPathXmlApplicationContext 以及fileSystemXmlApplicationContext等,在接下来的篇章中,我们将学习ApplicationContext的东西,关于它有以下的几个功能:
- 继承于MessageSource,为我们提供了提供国际化的标准访问策略.
- 继承ApplicationEventPublisher ,提供强大的事件机制.
- 扩展 ResourceLoader,可以用来加载多个 Resource,可以灵活访问不同的资源.
- 对 Web 应用的支持
我们来看ApplicationContext的家族图:
简单的来看一下家族图的成员:
- BeanFactory:spring管理bean的顶级接口,俗称基本容器,在该容器下有两个子接口分别是HierarchicalBeanFactory和ListableBeanFactory.
- HierarchicalBeanFactory:是一个具有层级关系的BeanFactory,其中包含一个很重要的属性为parentBeanFactory.
- ListableBeanFactory:是以枚举的方式列举当前beanFactory中所有的bean对象.
- ApplicationEventPublisher:是一个封装事件发布的接口.
- ResourceLoader:是spring用来加载资源的顶级接口,主要是从给定的资源中加载文件.
- MessageSource:是一个解析message的顶级策略接口,在平时的开发中我们几乎用不到.
- EnvironmentCapable:用于获取当前容器的上下文环境.
在实际的开发中我们很少用到ApplicationContext,一般会用它的实现类,具体有二种直接实现类型,分别是:
- WebApplicationContext
public interface WebApplicationContext extends ApplicationContext {
ServletContext getServletContext();
}
该接口中只有一个方法,其主要的作用是获取当前servlet的上下文信息.
- ConfigurableApplicationContext
''''''
public interface ConfigurableApplicationContext extends ApplicationContext, Lifecycle, Closeable {
/**
* 给applicationContext设置唯一id
* @param id
*/
void setId(String id);
/**
* 给applicationContext设置parent
* 父类不应该被修改,如果创建的对象不可用时,则应该在构造函数外部设置它
* @param parent
*/
void setParent(@Nullable ApplicationContext parent);
/**
* 设置environment
* @param environment
*/
void setEnvironment(ConfigurableEnvironment environment);
/**
* 获取environment
*/
ConfigurableEnvironment getEnvironment();
/**
* 给applicationContext添加BeanFactoryPostProcessor
* @param postProcessor
*/
void addBeanFactoryPostProcessor(BeanFactoryPostProcessor postProcessor);
/**
* 给applicationContext添加ApplicationListener
* @param listener
*/
void addApplicationListener(ApplicationListener<?> listener);
/**
* 给applicationContext添加ProtocolResolver
* @param resolver
*/
void addProtocolResolver(ProtocolResolver resolver);
/**
* 加载或者刷新配置方法(重要)
* @throws BeansException
* @throws IllegalStateException
*/
void refresh() throws BeansException, IllegalStateException;
/**
* 注册shutdown hook
*/
void registerShutdownHook();
/**
* 关闭ApplicationContext
*/
void close();
/**
* 判断ApplicationContext是否处于激活状态
* @return
*/
boolean isActive();
/**
* 获取当前上下文的BeanFactory
* @return
* @throws IllegalStateException
*/
ConfigurableListableBeanFactory getBeanFactory() throws IllegalStateException;
}
从ConfigurableApplicationContext中可以看出,提供的好多方法都是给ApplicationContext进行相关的配置过程.同时我们还看到ConfigurableApplicationContext实现了Lifecycle和Closeable接口.
- 其中Lifecycle是用来管理当前context的生命周期进行管理,于此提供了#start()和#stop()等
- Closeable : 是JDK提供的一个标准释放资源的组件
ConfigurableWebApplicationContext
在applicationContext的子类中,ConfigurableWebApplicationContext是WebApplicationContext和ConfigurableApplicationContext的共有的子接口,其主要的作用是针对WebApplicationContext容器的可配置 和可管理的一个接口,我们来看该接口的代码:
public interface ConfigurableWebApplicationContext extends WebApplicationContext, ConfigurableApplicationContext {
void setServletContext(@Nullable ServletContext servletContext);
void setServletConfig(@Nullable ServletConfig servletConfig);
ServletConfig getServletConfig();
void setNamespace(@Nullable String namespace);
String getNamespace();
void setConfigLocation(String configLocation);
void setConfigLocations(String... configLocations);
String[] getConfigLocations();
}
上述就是ConfigurableWebApplicationContext中的方法,一些方法是共有的,方简单易懂,大家知道就可以了,接着我们来看APPlicationContext中的另外一个常用方法ClassPathXmlApplicationContext,该方法是从当前容器的classPath下读取我们的配置文件,所以我们的配置文件一定要放在resource文件夹下:
ClassPathXmlApplicationContext
接下来我们来看一下常用的接口
- MessageSource
public interface MessageSource {
//获取message
@Nullable
String getMessage(String code, @Nullable Object[] args, @Nullable String defaultMessage, Locale locale);
String getMessage(String code, @Nullable Object[] args, Locale locale) throws NoSuchMessageException;
String getMessage(MessageSourceResolvable resolvable, Locale locale) throws NoSuchMessageException;
}
我们可以看到的是在MessageSource主要是定义了获取message的策略方法#getMessage(...),该接口的直接实现类是AbstractApplicationContext类,我们来看一下代码:
/** MessageSource we delegate our implementation of this interface to. */
@Nullable
private MessageSource messageSource;
//---------------------------------------------------------------------
// Implementation of MessageSource interface
//---------------------------------------------------------------------
@Override
public String getMessage(String code, @Nullable Object[] args, @Nullable String defaultMessage, Locale locale) {
return getMessageSource().getMessage(code, args, defaultMessage, 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);
}
原来真正的实现逻辑是在AbstractMessageSource类中
- ApplicationEventPublisher
我们知道ApplicationEventPublisher是spring用来处理事件发布的功能接口,该接口提供了一个#publishEvent(Object event, ...)方法用来通知应用程序中注册的所有的监听器,该方法同样也是在我们的AbstractApplicationContext类中实现,接下来我们来看代码实现:
@Override
public void publishEvent(ApplicationEvent event) {
publishEvent(event, null);
}
//给所有的监听器发布事件
protected void publishEvent(Object event, @Nullable ResolvableType eventType) {
Assert.notNull(event, "Event must not be null");
// Decorate event as an ApplicationEvent if necessary
//事件类型
ApplicationEvent applicationEvent;
if (event instanceof ApplicationEvent) {
applicationEvent = (ApplicationEvent) event;
}
else {
applicationEvent = new PayloadApplicationEvent<>(this, event);
if (eventType == null) {
eventType = ((PayloadApplicationEvent<?>) applicationEvent).getResolvableType();
}
}
// Multicast right now if possible - or lazily once the multicaster is initialized
if (this.earlyApplicationEvents != null) {
this.earlyApplicationEvents.add(applicationEvent);
}
else {
getApplicationEventMulticaster().multicastEvent(applicationEvent, eventType);
}
// Publish event via parent context as well...
if (this.parent != null) {
if (this.parent instanceof AbstractApplicationContext) {
((AbstractApplicationContext) this.parent).publishEvent(event, eventType);
}
else {
this.parent.publishEvent(event);
}
}
}
- 主要是针对不同的事件类型进行不同的处理
- ResourcePatternResolver
ResourcePatternResolver主要是继承接口ResourceLoader,其主要的作用是将我们的location解析为Resource对象的策略接口,其中提供了一个很重要的方法#getResources(String locationPattern)方法,在AbstractApplicationContext类中有具体的实现过程,来看代码:
/** ResourcePatternResolver used by this context. */
private ResourcePatternResolver resourcePatternResolver;
//---------------------------------------------------------------------
// Implementation of ResourcePatternResolver interface
//---------------------------------------------------------------------
@Override
public Resource[] getResources(String locationPattern) throws IOException {
return this.resourcePatternResolver.getResources(locationPattern);
}
这里就不在深究了,其实关于更深的实现过程是在PathMatchingResourcePatternResolver来完成,该类是ResourcePatternResolver的实现类
- EnvironmentCapable
public interface EnvironmentCapable {
/**
* Return the {@link Environment} associated with this component.
*/
Environment getEnvironment();
}
该接口中只有一个# getEnvironment()的方法,其主要是用来获取当前spring的上下文环境实例Environment.我们来看一下实现的过程,代码如下:
/**
* 该方法主要的作用是从当前配置文件中获取当前容器的上下文
* @return
*/
@Override
public ConfigurableEnvironment getEnvironment() {
//如果默认的为null,需要初始化
if (this.environment == null) {
this.environment = createEnvironment();
}
return this.environment;
}
/**
* 创建一个新的StandardEnvironment
* @return
*/
protected ConfigurableEnvironment createEnvironment() {
return new StandardEnvironment();
}
其中我们发现最后是创建一个StandardEnvironment的实体,该类主要是表示适用于非 WEB 应用的 Environment.
- Lifecycle
该接口提供了管理bean的生命周期的方法,在AbstractApplicationContext方法中有具体的实现过程,我们来看代码:
//---------------------------------------------------------------------
// Implementation of Lifecycle interface
//---------------------------------------------------------------------
/** LifecycleProcessor for managing the lifecycle of beans within this context. */
@Nullable
private LifecycleProcessor lifecycleProcessor;
@Override
public void start() {
getLifecycleProcessor().start();
publishEvent(new ContextStartedEvent(this));
}
@Override
public void stop() {
getLifecycleProcessor().stop();
publishEvent(new ContextStoppedEvent(this));
}
@Override
public boolean isRunning() {
return (this.lifecycleProcessor != null && this.lifecycleProcessor.isRunning());
}
在实现类中提供了start以及stop方法,分别通过不同的事件来处理如ContextStartedEvent和ContextStoppedEvent事件.
- Closable
该接口主要的作用是释放和关闭资源,给我们提供了#close()方法.
public void close() {
synchronized (this.startupShutdownMonitor) {
doClose();
// If we registered a JVM shutdown hook, we don't need it anymore now:
// We've already explicitly closed the context.
if (this.shutdownHook != null) {
try {
Runtime.getRuntime().removeShutdownHook(this.shutdownHook);
}
catch (IllegalStateException ex) {
// ignore - VM is already shutting down
}
}
}
}
这里我们发现调用了#doClose()的方法进行逻辑的处理,来看代码:
protected void doClose() {
// Check whether an actual close attempt is necessary...
if (this.active.get() && this.closed.compareAndSet(false, true)) {
if (logger.isDebugEnabled()) {
logger.debug("Closing " + this);
}
LiveBeansView.unregisterApplicationContext(this);
try {
// Publish shutdown event.
publishEvent(new ContextClosedEvent(this));
}
catch (Throwable ex) {
logger.warn("Exception thrown from ApplicationListener handling ContextClosedEvent", ex);
}
// Stop all Lifecycle beans, to avoid delays during individual destruction.
if (this.lifecycleProcessor != null) {
try {
this.lifecycleProcessor.onClose();
}
catch (Throwable ex) {
logger.warn("Exception thrown from LifecycleProcessor on context close", ex);
}
}
// Destroy all cached singletons in the context's BeanFactory.
destroyBeans();
// Close the state of this context itself.
closeBeanFactory();
// Let subclasses do some final clean-up if they wish...
onClose();
// Reset local application listeners to pre-refresh state.
if (this.earlyApplicationListeners != null) {
this.applicationListeners.clear();
this.applicationListeners.addAll(this.earlyApplicationListeners);
}
// Switch to inactive.
this.active.set(false);
}
}
- InitializingBean
InitializingBean主要是提供了bean的初始化方式,在该接口中只有afterPropertiesSet()方法,如果bean实现了了该接口,那么
就通过该方法来实现bean的初始化过程
public void afterPropertiesSet() {
if (!isActive()) {
refresh();
}
}
该方法位于AbstractRefreshableConfigApplicationContext类中,代码中的refresh()方法是整个applicationContext容器的核心方法,详解我们后面来说.
- BeanNameAware
该接口我们之前也有所了解,在我们初始化bean之前调用各种Aware接口来设置对应的xxxAware属性,其中这里的BeanNameAware就是其中的一个
/**
* Sets the id of this context to the bean name by default,
* for cases where the context instance is itself defined as a bean.
*/
@Override
public void setBeanName(String name) {
if (!this.setIdCalled) {
super.setId(name);
setDisplayName("ApplicationContext '" + name + "'");
}
}
- 总结
该篇主要讲了spring的applicationContext的结构,以及我们了解了applicationContext的众多核心接口,在下篇我们来讲一个很重的refash()方法...