先来看下XmlWebApplicationContext类UML图
从上图可以看出,XmlWebApplicationContext实现了ConfigurableApplicationContext接口和WebApplicationContext接口.
在上一篇文章中说到通过XmlWebApplicationContext.refresh()方法来完成Spring上下文初始化配置工作,而refresh()方法是在ConfigurableApplicationContext接口中定义的.
/**
* Load or refresh the persistent representation of the configuration,
* which might an XML file, properties file, or relational database schema.
* <p>As this is a startup method, it should destroy already created singletons
* if it fails, to avoid dangling resources. In other words, after invocation
* of that method, either all or no singletons at all should be instantiated.
* @throws BeansException if the bean factory could not be initialized
* @throws IllegalStateException if already initialized and multiple refresh
* attempts are not supported
*/
void refresh() throws BeansException, IllegalStateException;
ConfigurableApplicationContext
该接口扩展了ApplicationContext接口同时扩展了Lifecycle, Closeable两个接口,对应实现方法在AbsctractApplicationContext抽象类中完成.
- addApplicationListener 添加应用监听器
- addBeanFactoryPostProcessor 添加bean工厂处理器
- close() 重新定义了Closeable中的close()方法定义
- setId(String) 对当前ApplicationContext指定一个ID
- registerShutdownHook()对JVM Runtime注册一个关闭钩子线程,当JVM正常关闭时会先执行该线程然后再关闭JVM,可以查看AbstractApplicationContext中的实现方法,代码如下:
/**
* Register a shutdown hook with the JVM runtime, closing this context
* on JVM shutdown unless it has already been closed at that time.
* <p>Delegates to {@code doClose()} for the actual closing procedure.
* @see Runtime#addShutdownHook
* @see #close()
* @see #doClose()
*/
@Override
public void registerShutdownHook() {
if (this.shutdownHook == null) {
// No shutdown hook registered yet.
this.shutdownHook = new Thread() {
@Override
public void run() {
synchronized (startupShutdownMonitor) {
doClose();
}
}
};
Runtime.getRuntime().addShutdownHook(this.shutdownHook);
}
}
上面代码功能主要是在JVM关闭时调用doClose()方法来完成Spring清理工作,可以查看close()方法,里面工作也是调用doClose()来完成Spring清理工作
/**
* Close this application context, destroying all beans in its bean factory.
* <p>Delegates to {@code doClose()} for the actual closing procedure.
* Also removes a JVM shutdown hook, if registered, as it's not needed anymore.
* @see #doClose()
* @see #registerShutdownHook()
*/
@Override
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
}
}
}
}
在close()方法中,首先调用doClose()来完成清理工作,在清理完成后删除之前注册的shutdownHook,如果该处不移除钩子则在JVM关闭时会再执行一次清理工作.
getBeanFactory() 该方法用来获取内部BeanFactory,具体实现是在AbstractRefreshableApplicationContext中来完成,从AbstractRefreshableApplicationContext源代码可以看出,getBeanFactory()其实返回的是一个DefaultListableBeanFactory对象.另外通过该方法注释可以看出getBeanFactory()仅仅只能在isActive()返回true的时候调用,否则会抛出异常,也就是说在refresh()和close()之间调用,在refresh()之前和close()后调用都会抛出异常.
AbstractApplicationContext
public abstract class AbstractApplicationContext extends DefaultResourceLoader
implements ConfigurableApplicationContext, DisposableBean
下面主要看下该类的refresh()实现方法,代码如下:
@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 beanFactory = obtainFreshBeanFactory();
// Prepare the bean factory for use in this context.
prepareBeanFactory(beanFactory);
try {
// Allows post-processing of the bean factory in context subclasses.
postProcessBeanFactory(beanFactory);
// Invoke factory processors registered as beans in the context.
invokeBeanFactoryPostProcessors(beanFactory);
// Register bean processors that intercept bean creation.
registerBeanPostProcessors(beanFactory);
// Initialize message source for this context.
initMessageSource();
// Initialize event multicaster for this context.
initApplicationEventMulticaster();
// Initialize other special beans in specific context subclasses.
onRefresh();
// Check for listener beans and register them.
registerListeners();
// Instantiate all remaining (non-lazy-init) singletons.
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()方法主要初始化属性资源并验证系统环境中的属性配置.
- ConfigurableListableBeanFactory beanFactory = obtainFreshBeanFactory();这里创建了内置BeanFactory, obtainFreshBeanFactory()源码如下:
/**
* Tell the subclass to refresh the internal bean factory.
* @return the fresh BeanFactory instance
* @see #refreshBeanFactory()
* @see #getBeanFactory()
*/
protected ConfigurableListableBeanFactory obtainFreshBeanFactory() {
refreshBeanFactory();
ConfigurableListableBeanFactory beanFactory = getBeanFactory();
if (logger.isDebugEnabled()) {
logger.debug("Bean factory for " + getDisplayName() + ": " + beanFactory);
}
return beanFactory;
}
在obtainFreshBeanFactory()方法内部首先调用refreshBeanFactory()方法来初始化配置BeanFactory,该方法在AbstractApplicationContext类中定义为抽象方法,就像注释说明一样该方法在子类中实现.而实现该方法的类为AbstractRefreshableApplicationContext,同样该类实现了上面提到的ConfigurableApplicationContext接口中定义的getBeanFactory()方法,getBeanFactory()返回的既是refreshBeanFactory()方法创建的DefaultListableBeanFactory对象.refreshBeanFactory()方法源代码如下:
/**
* This implementation performs an actual refresh of this context's underlying
* bean factory, shutting down the previous bean factory (if any) and
* initializing a fresh bean factory for the next phase of the context's lifecycle.
*/
@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);
}
}
在该方法中,首先判断当前beanFactory是否存在,如果存在则将之前对象销毁,然后调用createBeanFactory()创建DefaultListableBeanFactory,创建完成之后将当前ApplicationContext的ID赋给该DefaultListableBeanFactory,同时调用loadBeanDefinitions(DefaultListableBeanFactory beanFactory)方法开始真正初始化配置工作,而loadBeanDefinitions方法在AbstractRefreshableApplicationContext类中定义为抽象方法,具体是在XmlWebApplicationContext中实现.
下面返回AbstractApplicationContext类的refresh()方法:
- prepareBeanFactory(beanFactory);该方法主要用来完成BeanFactory预处理工作.比如设置BeanClassLoader,以及设置BeanExpressionResolver来完成SPEL表达式的处理(即处理bean中的”#{…}”表达式).