Spring源码系列四:AbstractApplicationContext

首先我们看看AbstractApplicationContext的继承体系:

Spring源码系列(四):AbstractApplicationContext_spring

从上图来看,AbstractApplicationContext实现了ConfigurableApplication接口,而ConfigurationApplication接口继承自ApplicationContext、Lifecycle和Closeable,ApplicationContext又扩展了BeanFactory的功能,归根到底这些都是在帮助我们管理Bean。之前介绍过ApplicationContext,这里就不再赘述,想要了解的可以看看之前的博客哦!

接下来就先讲讲ConfigurableApplicationContext。

ConfigurableApplicationContext介绍

通过最初的介绍可以发现ConfigurableApplicationContext接口实现了Lifecycle接口和Closeable接口,接下来首先看看这两个接口。

Lifecycle

该方法定义了启动/停止生命周期控制方法的通用接口,主要用于控制异步处理过程。

ApplicationContext会将start/stop信息传递给容器中所有实现了该接口的bean,以达到管理和控制JMX、任务调度等目的。

/*
这个接口并不意味着特定的自动启动语义
这个接口必须被组件(通常是Spring Context中定义的bean)和容器(也就是ApplicationContext自身)实现
容器将会传播启动/停止信号给每个容器中应用的所有组件
例如运行时停止/重启动场景

注意当前的生命周期接口仅支持顶层的单例bean
对于其他的组件来说,生命周期接口不会检测并且默认忽略
另外,请注意,扩展的SmartLifecycle接口提供了与应用程序上下文的启动和关闭阶段的复杂集成
*/
public interface Lifecycle {
/*
开启一个组件
如果组件已经在运行也不应该抛出异常
对于容器来说,这会将启动信号传递给应用的所有组件
*/
void start();
/*
通常以同步方式停止此组件,以便在返回此方法时完全停止该组件
请注意,此停止通知不能保证在销毁之前发出:在定期关闭时,Lifecycle Bean将首先在传播常规销毁回调之前收到停止通知;但是,在上下文生存期内的热刷新或中止刷新尝试时,将调用给定bean的destroy方法,而不预先考虑停止信号。
*/
void stop();
/*
检查组件是否正在运行
对于容器来说,只有容器应用的全部组件都在运行时才会返回true
*/
boolean isRunning();
}

Closeable

Closeable是可以关闭的数据的源或者目标,这是java的io接口

调用close方法是为了释放对象持有的资源(例如打开的文件)

public interface Closeable extends AutoCloseable {
/*
关闭流并且释放与它关联的系统资源
如果流已经被关闭,那么调用该方法没有任何影响
*/
public void close() throws IOException;
}

ConfigurableApplicationContext

首先看看方法概览:

Spring源码系列(四):AbstractApplicationContext_后端_02

/*
这个接口是被大多数但并非全部应用程序上下文实现的服务提供接口。除了ApplicationContext接口中的应用程序上下文客户端方法以外,还提供了配置应用程序上下文的工具。

这里封装了配置和生命周期方法,使ApplicationContext客户端对它们不可见,目前的方法只能由启动和关闭代码使用。
*/
public interface ConfigurableApplicationContext extends ApplicationContext, Lifecycle, Closeable {
/*
这个字符串中的任意字符都可以作为单个字符串值中多个上下文配置路径之间的分隔符
*/
String CONFIG_LOCATION_DELIMITERS = ",; \t\n";
/*
factory中ConversionService bean的名称,如果没有提供将才有默认的转换规则
*/
String CONVERSION_SERVICE_BEAN_NAME = "conversionService";
/*
factory中LoadTimeWeaver bean的名称,如果提供了这样的bean,
context将使用一个临时类加载器进行类型匹配,以允许LoadTimeWeaver处理所有实际的bean类
*/
String LOAD_TIME_WEAVER_BEAN_NAME = "loadTimeWeaver";
/*
factory中Environment bean的名称
*/
String ENVIRONMENT_BEAN_NAME = "environment";
/*
系统属性bean的名称
*/
String SYSTEM_PROPERTIES_BEAN_NAME = "systemProperties";
/*
系统环境bean的名称
*/
String SYSTEM_ENVIRONMENT_BEAN_NAME = "systemEnvironment";
/*
关闭钩子线程的名称
*/
String SHUTDOWN_HOOK_THREAD_NAME = "SpringContextShutdownHook";
/*
设置应用程序上下文的唯一ID
*/
void setId(String id);
/*
设置应用程序上下文的父Context
请注意,父类不应该被修改,只有在创建此类的对象时父级不可用时,才应在构造函数外部设置父级
*/
void setParent(@Nullable ApplicationContext parent);
/*
设置应用程序上下文的环境
*/
void setEnvironment(ConfigurableEnvironment environment);
/*
获得应用程序上下文的环境
*/
@Override
ConfigurableEnvironment getEnvironment();
/*
增加一个新的BeanFactoryPostProcessor,在任何bean definition被检查之前,
它将会在当前应用程序上下文刷新的时候将会应用于内部的bean工厂

在进行context配置期间调用
*/
void addBeanFactoryPostProcessor(BeanFactoryPostProcessor postProcessor);
/*
添加一个ApplicationListener,它将会被通知上下文事件
例如context刷新和关闭事件
注意,即使上下文没有启动,注册在这里的ApplicationListener也会被应用与刷新事件
或者在上下文已经激活的情况下,使用当前事件多播进行实时处理
*/
void addApplicationListener(ApplicationListener<?> listener);
/*
指定加载类路径下的资源和bean classs的类加载器
context类加载器将会被传递给内部的bean工厂
*/
void setClassLoader(ClassLoader classLoader);
/*
注册应用程序上下文中给定的协议解析器
允许额外的资源协议被处理
任何这样的解析器都将在这个上下文的标准解析规则之前被调用。
因此,它也可以覆盖任何默认规则
*/
void addProtocolResolver(ProtocolResolver resolver);
/*
加载或者刷新配置,这些配置可能来自基于Java注解的配置,或者xml文件,或者属性文件,或者关联的数据库等等

这是一个启动方法,如果它失败它应该销毁已经建立的单例,避免浪费资源
换句话说,调用这个方法之后,应用程序的全部单例或者没有任何单例别初始化
*/
void refresh() throws BeansException, IllegalStateException;
/*
注册JVM运行时的关闭钩子,在JVM关闭时关闭应用程序上下文,除非它已经关闭
这个方法可以多次调用,每个context实例仅注册一个关闭钩子
*/
void registerShutdownHook();
/*
关闭应用程序上下文,释放所有的资源,同时会销毁单例池中的所有bean
*/
@Override
void close();
/*
判断当前应用程序上下文是否在使用
判断它是否至少被刷新一次并且没有被关闭
*/
boolean isActive();
/*
返回当前应用程序上下文的内部bean工厂,可以用于访问指定的功能
不要用它来对bean工厂进行后期处理;单例之前已经实例化过了。
使用BeanFactoryPostProcessor在接触Bean之前拦截BeanFactory启动过程
*/
ConfigurableListableBeanFactory getBeanFactory() throws IllegalStateException;
}

通过上述源码的分析,我们可以发现ConfigurableApplicationContext是用来对ApplicationContext进行一系列配置的:

  • 设置context的唯一id(用于表示每个context),
  • 设置environment
  • 设置BeanFactoryPostProcessor
  • 注册应用程序监听器和关闭时的钩子函数
  • 刷新和关闭context,判断context是否处于活跃状态
  • 设置协议解析器
  • 获得应用程序上下文的内部bean工厂

这个接口就是帮助spring用来配置和管理应用程序上下问的。

ConfigurableApplication扩展于ApplicationContext,它新增了两个 主要的方法:refresh和close,让ApplicationContext具有启动、刷新和关闭应用上下文的能力。在应用上下文关闭的情况下调用refresh即可启动应用上下文,在已经启动的状态下条用refresh则可清除缓存并重新装载配置信息,而调用close则可关闭应用上下文。这些接口方法为容器的控制管理带来了便利,作为开发者我们不需要过多关心这些方法。

DefaultResourceLoader

除了实现ConfigurableApplicationContext接口以外,AbstractApplicationContext还继承自DefaultResourceLoader类,该类是ResourceLoader接口的实现。

首先看看它包含哪些字段:

Spring源码系列(四):AbstractApplicationContext_spring_03

接下来看看它的构造函数:

Spring源码系列(四):AbstractApplicationContext_应用程序_04

当我们不指定默认的类资源加载器时,会调用默认的类加载器进行初始化classLoader字段,否则就会使用我们传入的类加载器初始化classLoader字段。

Spring源码系列(四):AbstractApplicationContext_spring_05

使用上述的方法,我们也可以在创建完DefaultResourceLoader之后再设置类加载器,也可以获得当前类中使用的类加载器。

Spring源码系列(四):AbstractApplicationContext_java_06

最后,可以看看getResource方法。

  @Override
public Resource getResource(String location) {
Assert.notNull(location, "Location must not be null");
// 首先通过我们注册的协议解析器解析给定location资源,如果能够解析出来就直接返回
for (ProtocolResolver protocolResolver : getProtocolResolvers()) {
Resource resource = protocolResolver.resolve(location, this);
if (resource != null) {
return resource;
}
}
// 如果注册的协议解析器无法解析资源,就判断loaction的路径是否以"/"开头
// 如果是的话就调用getResourceByPath方法按照路径进行解析,
if (location.startsWith("/")) {
return getResourceByPath(location);
}
// 判断location是否以"classpath:"开头,如果是的话就通过类加载器去加载给定的资源
else if (location.startsWith(CLASSPATH_URL_PREFIX)) {
return new ClassPathResource(location.substring(CLASSPATH_URL_PREFIX.length()), getClassLoader());
}
// 否则就使用URL协议解析给定路径的资源
else {
try {
// Try to parse the location as a URL...
URL url = new URL(location);
return (ResourceUtils.isFileURL(url) ? new FileUrlResource(url) : new UrlResource(url));
}
catch (MalformedURLException ex) {
// No URL -> resolve as resource path.
return getResourceByPath(location);
}
}
}

通过上述的源码可以得知,DefaultResourceLoader主要就是注册了一些资源的解析协议,并且通过默认的类加载器或者指定的类加载器加载相应的资源。

这里为AbstractApplicationContext提供了加载资源的方法。

AbstractApplicationContext

接下来就来看看AbstractApplicationContext这个类,从其名字就能够看出这是一个抽象类。

这个类使用到了模板设计模式,定义了refresh()方法调用方法的顺序,但是这些被调用的某些方法是被其子类实现的。

看看Spring开发者在该类上的注释

/*
它是对ApplicationContext接口的抽象实现,不强制指定用于配置的存储类型(就是注解或者xml文件配置等的类型),只实现公共上下文功能。

它使用了模板设计模式,需要具体的子类去实现抽象方法

与纯BeanFactory不同,ApplicationContext用于检测在其内部bean工厂中定义的特殊bean:因此,他会自动注册在context中定义为bean的BeanFactoryPostProcessors、BeanPostProcessors和ApplicationListeners。

在context中MessageSource也可能作为bean被提供,其名字为"messageSource",否则,消息解析将会被委托给父类上下文。此外,在context中,对应用程序事件的广播由ApplicationEventMulticaster类型的"applicationEventMulticaster"的bean提供,否则,默认会使用SimpleApplicationEventMulticaster。

通过继承DefaultResourceLoader实现了资源的加载功能,主要作用:将非URL资源路径视为类路径资源(支持包含包路径的完整类路径资源名称),除非在子类重写getResourceByPath方法。
*/

字段

首先我们看看它都包含了哪些字段:

  /** 应用上下文的id,组成形式为:classname + '@' + 对象的hashCode*/
private String id = ObjectUtils.identityToString(this);

/** Display name. */
// 应用环境上下文的名称,和id的值相同,两者调用了同样的方法传递了同样的参数
private String displayName = ObjectUtils.identityToString(this);

/** Parent context. */
// 这个应用上下文的父context
@Nullable
private ApplicationContext parent;

/** Environment used by this context. */
// 当前上下文使用的Environment对象,用于设置激活环境中的哪些配置文件,查询系统的环境属性等
@Nullable
private ConfigurableEnvironment environment;

/** BeanFactoryPostProcessors to apply on refresh. */
// 存储在刷新应用程序上下文时使用的BeanFactoryPostProcessor
private final List<BeanFactoryPostProcessor> beanFactoryPostProcessors = new ArrayList<>();

/** System time in milliseconds when this context started. */
// context的启动时间,以毫秒为单位
private long startupDate;

/** Flag that indicates whether this context is currently active. */
// 标识当前上下文是否处于活跃状态
private final AtomicBoolean active = new AtomicBoolean();

/** Flag that indicates whether this context has been closed already. */
// 标识当前上下文是否已经被关闭
private final AtomicBoolean closed = new AtomicBoolean();

/** Synchronization monitor for the "refresh" and "destroy". */
// 刷新和关闭的同步监听器,类似于锁
private final Object startupShutdownMonitor = new Object();

/** Reference to the JVM shutdown hook, if registered. */
// JVM的关闭钩子
@Nullable
private Thread shutdownHook;

/** ResourcePatternResolver used by this context. */
// 该接口使用了策略模式来封装算法,调用其getResources方法来获取资源,但是方法是在其实现类实现的
private ResourcePatternResolver resourcePatternResolver;

/** LifecycleProcessor for managing the lifecycle of beans within this context. */
// 策略接口,管理应用程序上下文中bean的生命周期,用于通知context刷新和关闭,然后自动开启和关闭context包含的bean
@Nullable
private LifecycleProcessor lifecycleProcessor;

/** MessageSource we delegate our implementation of this interface to. */
// 用于国际化的策略接口,将接口的实现委派给它
@Nullable
private MessageSource messageSource;

/** Helper class used in event publishing. */
// 事件广播器,用来发布事件,将事件通知给监听器
@Nullable
private ApplicationEventMulticaster applicationEventMulticaster;

/** Statically specified listeners. */
// 存储应用程序监听器
private final Set<ApplicationListener<?>> applicationListeners = new LinkedHashSet<>();

/** Local listeners registered before refresh. */
// 存储刷新前注册的本地监听器
@Nullable
private Set<ApplicationListener<?>> earlyApplicationListeners;

/** ApplicationEvents published before the multicaster setup. */
// 存储事件
@Nullable
private Set<ApplicationEvent> earlyApplicationEvents;

这些字段主要作用:标识应用程序上下文,解析资源,管理bean的生命周期,进行事件的发布和监听,存储应用程序上下文的事件。

接下来我们省略一些简单的设置属性的方法,看几个关键的方法。

publishEvent()方法

首先来看看publishEvent()方法,该方法用于发布事件,调用相应的监听器来处理事件。

  protected void publishEvent(Object event, @Nullable ResolvableType eventType) {
Assert.notNull(event, "Event must not be null");

// Decorate event as an ApplicationEvent if necessary
// 如果有必要的话,就将event装饰成ApplicationEvent,这里使用了装饰者模式
ApplicationEvent applicationEvent;
// 如果event是ApplicationEvent类型的,就直接强制类型转换
if (event instanceof ApplicationEvent) {
applicationEvent = (ApplicationEvent) event;
}
// 否则就直接将event装饰成applicationEvent
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
// 如果earlyApplicationEvents不为空,说明广播器还未启动,需要先发布earlyApplicationEvents里的事件
if (this.earlyApplicationEvents != null) {
this.earlyApplicationEvents.add(applicationEvent);
}
else {
// 否则就调用applicationEventMulticaster进行事件的发布
// multicastEvent会查找事件对应的监听器,然后再处理这个事件
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);
}
}
}

总的来说,这个方法就是发布一些应用上下文的事件,然后监听器再对这些事件进行处理

从这里可以看出spring使用ApplicationEventMulticaster进行事件的发布,调用相关的监听器处理对应的事件

refresh()方法

这个方法主要用来从Java注解,或者xml文件中加载配置。也就是在这个阶段把我们的bean加入到了spring Ioc容器中。

这个方法相当重要。

@Override
public void refresh() throws BeansException, IllegalStateException {
synchronized (this.startupShutdownMonitor) {
// Prepare this context for refreshing.
prepareRefresh();

// Tell the subclass to refresh the internal bean factory.
// 获得ConfigurableListableBeanFactory接口的实现类,该方法是由子类实现的
ConfigurableListableBeanFactory beanFactory = obtainFreshBeanFactory();

// 设置了bean工厂的标准上下文特性,例如上下文的类加载器和后置处理器
prepareBeanFactory(beanFactory);

try {
/*
该方法由子类实现
当bean Factory初始化完成以后,改变应用程序上下文的内部bean Factory
此时,所有的bean定义将会被加载,但是没有bean被实例化
并且允许在指定的应用程序上下文实现中注册特殊的Bean后置处理器
*/
postProcessBeanFactory(beanFactory);

// Invoke factory processors registered as beans in the context.
/*
根据明确的顺序实例化并调用所有已注册的BeanFactoryPostProcessor
*/
invokeBeanFactoryPostProcessors(beanFactory);

// Register bean processors that intercept bean creation.
/*
实例化并注册拦截bean创建的BeanPostProcessor beans
*/
registerBeanPostProcessors(beanFactory);

// Initialize message source for this context.
/*
初始化当前上下文的消息源,用于国际化
*/
initMessageSource();

// Initialize event multicaster for this context.
/*
初始化当前上下文的事件发布器
*/
initApplicationEventMulticaster();

// Initialize other special beans in specific context subclasses.
/*
在指定的上下文子类中初始化其他一些指定的特殊bean
该方法是在子类中实现的
*/
onRefresh();

// Check for listener beans and register them.
/*
注册应用程序的事件监听器,并进行事件的发布
*/
registerListeners();

// Instantiate all remaining (non-lazy-init) singletons.
// 实例化所有非延迟加载的单例bean
finishBeanFactoryInitialization(beanFactory);

// Last step: publish corresponding event.
// 完成刷新操作,并进行相关事件的发布
finishRefresh();
}

catch (BeansException ex) {
if (logger.isWarnEnabled()) {
logger.warn("Exception encountered during context initialization - " +
"cancelling refresh attempt: " + ex);
}

// Destroy already created singletons to avoid dangling resources.
destroyBeans();

// Reset 'active' flag.
cancelRefresh(ex);

// Propagate exception to caller.
throw ex;
}

finally {
// Reset common introspection caches in Spring's core, since we
// might not ever need metadata for singleton beans anymore...
resetCommonCaches();
}
}
}

可以看出refresh方法执行了一系列的方法,我们来看看这些方法分别做了什么

prepareRefresh()方法

该方法主要设置了context的启动时间,并设置了context的close和active属性,用以标识该context已经启动了。

对一些属性进行了初始化和验证操作,并对事件监听器进行了一定的管理。

  protected void prepareRefresh() {
// Switch to active.
this.startupDate = System.currentTimeMillis();
this.closed.set(false);
this.active.set(true);

if (logger.isDebugEnabled()) {
if (logger.isTraceEnabled()) {
logger.trace("Refreshing " + this);
}
else {
logger.debug("Refreshing " + getDisplayName());
}
}

// Initialize any placeholder property sources in the context environment.
initPropertySources();

// Validate that all properties marked as required are resolvable:
// see ConfigurablePropertyResolver#setRequiredProperties
getEnvironment().validateRequiredProperties();

// 如果earlyApplicationListeners为null,就将applicationListeners的内容传递给它
if (this.earlyApplicationListeners == null) {
this.earlyApplicationListeners = new LinkedHashSet<>(this.applicationListeners);
}
else {
// 如果earlyApplicationListeners不为null
// 那就将applicationListeners清空,并将earlyApplicationListeners添加到applicationListeners
this.applicationListeners.clear();
this.applicationListeners.addAll(this.earlyApplicationListeners);
}

// 初始化earlyApplicationEvents,当广播可用时就发布事件
this.earlyApplicationEvents = new LinkedHashSet<>();
}

总结来说,这个方法就是启动了应用程序上下文,并对一些事件监听器进行了管理。为下面的方法做好了准备。

initMessageSource() & initApplicationEventMulticaster()方法

首先来看看initMessageSource方法:

  protected void initMessageSource() {
ConfigurableListableBeanFactory beanFactory = getBeanFactory();
// 判断beanFactory中是否存在名为"messageSource"的bean
if (beanFactory.containsLocalBean(MESSAGE_SOURCE_BEAN_NAME)) {
// 如果存在的话就直接从beanFactory中获取对应的bean
this.messageSource = beanFactory.getBean(MESSAGE_SOURCE_BEAN_NAME, MessageSource.class);
// Make MessageSource aware of parent MessageSource.
// 设置父类上下文的messageSource
if (this.parent != null && this.messageSource instanceof HierarchicalMessageSource) {
HierarchicalMessageSource hms = (HierarchicalMessageSource) this.messageSource;
if (hms.getParentMessageSource() == null) {
// Only set parent context as parent MessageSource if no parent MessageSource
// registered already.
hms.setParentMessageSource(getInternalParentMessageSource());
}
}
if (logger.isTraceEnabled()) {
logger.trace("Using MessageSource [" + this.messageSource + "]");
}
}
// 如果beanFactory不存在对应的bean,那么就直接创建DelegatingMessageSource对象,并插入beanFactory中
else {
// Use empty MessageSource to be able to accept getMessage calls.
DelegatingMessageSource dms = new DelegatingMessageSource();
dms.setParentMessageSource(getInternalParentMessageSource());
this.messageSource = dms;
beanFactory.registerSingleton(MESSAGE_SOURCE_BEAN_NAME, this.messageSource);
if (logger.isTraceEnabled()) {
logger.trace("No '" + MESSAGE_SOURCE_BEAN_NAME + "' bean, using [" + this.messageSource + "]");
}
}
}

从代码中我们可以看出该方法的大概作用:从beanFactory中取出名为"messageSource"的bean,然后再将这个bean赋值给messageSource属性。

如果beanFactory中不包含这个bean的话,那么就创建一个DelegatingMessageSource对象,并将其作为单例存入beanFactory中。

而initApplicationEventMulticaster方法也是这样的流程,先检查beanFactory中是否包含名为"applicationEventMulticaster"的bean,如果有的话就直接获取,没有的话就创建一个SimpleApplicationEventMulticaster对象加入到beanFactory中。

// 这里的流程和initMessageSource方法的流程一样!
protected void initApplicationEventMulticaster() {
ConfigurableListableBeanFactory beanFactory = getBeanFactory();
if (beanFactory.containsLocalBean(APPLICATION_EVENT_MULTICASTER_BEAN_NAME)) {
this.applicationEventMulticaster =
beanFactory.getBean(APPLICATION_EVENT_MULTICASTER_BEAN_NAME, ApplicationEventMulticaster.class);
if (logger.isTraceEnabled()) {
logger.trace("Using ApplicationEventMulticaster [" + this.applicationEventMulticaster + "]");
}
}
else {
this.applicationEventMulticaster = new SimpleApplicationEventMulticaster(beanFactory);
beanFactory.registerSingleton(APPLICATION_EVENT_MULTICASTER_BEAN_NAME, this.applicationEventMulticaster);
if (logger.isTraceEnabled()) {
logger.trace("No '" + APPLICATION_EVENT_MULTICASTER_BEAN_NAME + "' bean, using " +
"[" + this.applicationEventMulticaster.getClass().getSimpleName() + "]");
}
}
}

registerListeners()方法

该方法就是用来注册监听器,向applicationEventMulticaster属性中注册应用程序监听器,并发布要提前处理的事件

protected void registerListeners() {
// 首先注册applicationListeners中指定的应用程序监听器
for (ApplicationListener<?> listener : getApplicationListeners()) {
getApplicationEventMulticaster().addApplicationListener(listener);
}

// Do not initialize FactoryBeans here: We need to leave all regular beans
// uninitialized to let post-processors apply to them!
/*
不要在这里初始化FactoryBeans:我们需要将所有常规bean保持为未初始化状态,以便让后处理器应用于它们
这里只获得监听器对应的bean名称,通过bean名称进行注册
*/
String[] listenerBeanNames = getBeanNamesForType(ApplicationListener.class, true, false);
for (String listenerBeanName : listenerBeanNames) {
getApplicationEventMulticaster().addApplicationListenerBean(listenerBeanName);
}

/*
发布earlyApplicationEvents对应的事件
*/
Set<ApplicationEvent> earlyEventsToProcess = this.earlyApplicationEvents;
this.earlyApplicationEvents = null;
if (!CollectionUtils.isEmpty(earlyEventsToProcess)) {
for (ApplicationEvent earlyEvent : earlyEventsToProcess) {
getApplicationEventMulticaster().multicastEvent(earlyEvent);
}
}
}

finishBeanFactoryInitialization方法

该方法主要完成beanFactory的初始化操作,也是在这里加载了我们自己注册到spring中的bean

protected void finishBeanFactoryInitialization(ConfigurableListableBeanFactory beanFactory) {
// Initialize conversion service for this context.
if (beanFactory.containsBean(CONVERSION_SERVICE_BEAN_NAME) &&
beanFactory.isTypeMatch(CONVERSION_SERVICE_BEAN_NAME, ConversionService.class)) {
beanFactory.setConversionService(
beanFactory.getBean(CONVERSION_SERVICE_BEAN_NAME, ConversionService.class));
}

// Register a default embedded value resolver if no bean post-processor
// (such as a PropertyPlaceholderConfigurer bean) registered any before:
// at this point, primarily for resolution in annotation attribute values.
if (!beanFactory.hasEmbeddedValueResolver()) {
beanFactory.addEmbeddedValueResolver(strVal -> getEnvironment().resolvePlaceholders(strVal));
}

// Initialize LoadTimeWeaverAware beans early to allow for registering their transformers early.
String[] weaverAwareNames = beanFactory.getBeanNamesForType(LoadTimeWeaverAware.class, false, false);
for (String weaverAwareName : weaverAwareNames) {
getBean(weaverAwareName);
}

// Stop using the temporary ClassLoader for type matching.
beanFactory.setTempClassLoader(null);

// Allow for caching all bean definition metadata, not expecting further changes.
beanFactory.freezeConfiguration();

// Instantiate all remaining (non-lazy-init) singletons.
beanFactory.preInstantiateSingletons();
}

finishRefresh()方法

  protected void finishRefresh() {
// Clear context-level resource caches (such as ASM metadata from scanning).
// 清空上下文级别的资源缓存
clearResourceCaches();

// Initialize lifecycle processor for this context.
/*
初始化当前上下文的生命周期处理器
这里也是先检测beanFactory中是否包含名为"lifecycleProcessor"的bean
如果不包含的话会创建DefaultLifecycleProcessor对象加入到beanFactory中
*/
initLifecycleProcessor();

// Propagate refresh to lifecycle processor first.
// 首先将刷新消息传播到生命周期处理器
getLifecycleProcessor().onRefresh();

// 发布一些不可变的对象
publishEvent(new ContextRefreshedEvent(this));

// Participate in LiveBeansView MBean, if active.
LiveBeansView.registerApplicationContext(this);
}

总结

refresh方法主要就是刷新了上下文的状态,添加了部分的监听器,发布了在刷新之前存在的一些事件,此外,还完成了bean的加载,将bean加载到beanFactory中,让用户之后可以通过getBean方法获得对应的bean。

refresh方法是模板方法,这里使用到了模板设计模式,将刷新的流程规划好,但是具体的实现可以在子类中进行。当然,在AbstractApplicationContext中也实现了部分相关的方法。

close方法

该方法用于关闭context,但最终会调用doClose方法:

@Override
public void close() {
// 对该方法进行同步,避免销毁操作被影响
synchronized (this.startupShutdownMonitor) {
// 真正关闭context的方法
doClose();
// If we registered a JVM shutdown hook, we don't need it anymore now:
// We've already explicitly closed the context.
// 如果我们注册了JVM关闭钩子,那么在关闭时就可以移除这个钩子
if (this.shutdownHook != null) {
try {
Runtime.getRuntime().removeShutdownHook(this.shutdownHook);
}
catch (IllegalStateException ex) {
// ignore - VM is already shutting down
}
}
}
}

protected void doClose() {
// Check whether an actual close attempt is necessary...
// 判断当前context是否处于活跃状态,如果是的话,就使用cas操作将closed设置为true,否则直接退出
if (this.active.get() && this.closed.compareAndSet(false, true)) {
if (logger.isDebugEnabled()) {
logger.debug("Closing " + this);
}
// 取消LiveBeanView的注册
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.
// 停止所有生命周期bean,以避免单个销毁过程中的延迟
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.
// 销毁缓存的所有单例bean
destroyBeans();

// Close the state of this context itself.
// 关闭context的状态
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.
// 销毁所有的单例bean,并将监听器清空后,将active设置为false,证明context被正常关闭
this.active.set(false);
}
}

其他方法

getBean():获取beanFactory中对应的bean

getBeanProvider():获得ObjectProvider对象,该对象继承自ObjectFactory,可以通过其getObject获得需要的bean

containsBean():判断beanFactory中是否包含某个bean

isSingleton & isPrototype:判断单例还是原型

isTypeMatch(String name, ResolvableType typeToMatch):判断给定名称的bena的类型和给定的类型是否匹配

getType & getAliases:获取bean的类型 & 获得bean的别名

containsBeanDefinition & getBeanDefinitionCount:判断是否包含某个BeanDefinition & 获得beanFactory中BeanDefinition的数量

getBeanDefinitionNames:获得beanFactory中BeanDefinition的全部名称

getBeanNamesForType:通过类型获得bean的名称,有一系列的重载方法

getBeansOfType:获得与给定类型匹配的bean,key为bean的名称,value为bean的实例

getBeanNamesForAnnotation:获取给定被给定annotation注释的bean的名称

getBeansWithAnnotation:获取给定包含给定annotation的bean,key为bean的名称,value为bean的实例

findAnnotationOnBean:获取给定bean包含的annotation

getParentBeanFactory:获得当前context的父context

containsLocalBean:判断本地的bean工厂是否包含给定名称的bean

getInternalParentBeanFactory:如果实现了ConfigurableApplicationContext,则返回父上下文的内部bean工厂;否则,返回父上下文本身

getMessage:解析消息,交给具体的实现类去做

getMessageSource:获取messageSource

getInternalParentMessageSource:如果父上下文也是AbstractApplicationContext,则返回父上下文的内部消息源;否则,返回父上下文本身

getResources:获取给定路径的资源

start & stop & isRunning:启动组件,也就是bean & 关闭组件 & 判断组件是否正在运行

总结

AbstractApplicationContext主要有如下几点作用:

  • 对属性的getter和setter方法
  • 进行事件的发布,通过applicationEventMulticaster进行事件的发布。
  • 对应用程序上下文进行刷新,在刷新的过程中:改变了context的状态,初始化了messageSource和applicationEventMulticaster,注册了一系列的监听者,完成了spring中bean的创建等,refresh方法是重点。
  • 可以通过context获得对应beanFactory,然后通过这个bean工厂来查询bean工厂中缓存的各种bean,还可以判断bean的生命周期,通过类型获取对应的bean,获取其中的BeanDefinition
  • 注册了一系列的BeanFactoryPostProcessor,并在refresh()方法执行过程中通过调用PostProcessorRegistrationDelegate.invokeBeanFactoryPostProcessors执行了我们注册的BeanFactoryPostProcessor
  • 通过LifecycleProcessor对beans的生命周期进行管理

AbstractApplicationContext是一个抽象类,它使用了模板方法设计模式,定义了执行的流程,但是具体的实现还是交给了它的子类来做。并且AbstractApplicationContext也使用了组合的模式,它对BeanFactory的操作都是委托给DefaultListableBeanFactory实现的,而不是在自身去实现这么多的逻辑。

从这里学到了模板方法的设计模式,抽象类定义方法调用的流程,但是具体方法的实现是交给子类完成的。

Spring源码这个框架很复杂,虽然看了一遍AbstractApplicationContext的源码,了解了它都包含哪些属性和方法,但是对于为什么要包含这些属性和方法,以及属性和方法的作用的认知还是很浅,希望可以戒骄戒躁,逐步深入。

参考

[spring揭秘]

[精通Spring4.x 企业应用开发实战]