文章目录
前言
本文以Web项目中创建的Spring容器为切入点,记述WebApplicationContext的初始化过程。 Spring版本4.3.18.RELEASE。一、初始化入口
在基于Servlet+Spring的Web项目开发中,若未指定WebApplicationContext的实现类,将以XmlWebApplicationContext作为Spring容器的默认实现类。在Spring的ContextLoaderListener#contextInitialized或DispatcherServlet#init方法中,创建XmlWebApplicationContext实例后,都会调用#refresh方法来对Spring容器进行初始化。
抽象类AbstractApplicationContext#refresh方法,是Spring ApplicationContext的初始化入口。
二、#refresh方法简介
#refresh方法来org.springframework.context.ConfigurableApplicationContext接口。
ConfigurableApplicationContext接口
ConfigurableApplicationContext接口对ApplicationContext接口进行了扩展,提供了更多的配置ApplicationContext的方法。
接口定义源码如下:
/**
* SPI interface to be implemented by most if not all application contexts.
* Provides facilities to configure an application context in addition
* to the application context client methods in the
* {@link org.springframework.context.ApplicationContext} interface.
*
* <p>Configuration and lifecycle methods are encapsulated here to avoid
* making them obvious to ApplicationContext client code. The present
* methods should only be used by startup and shutdown code.
*
* @author Juergen Hoeller
* @author Chris Beams
* @since 03.11.2003
*/
public interface ConfigurableApplicationContext extends ApplicationContext, Lifecycle, Closeable {
...
}
#refresh方法
#refresh方法是ApplicationContext的启动方法,用于加载或刷新ApplicationContext配置。
#refresh源码如下:
/**
* 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;
三、初始化过程
3.1 默认WebApplicationContext实现类-XmlWebApplicationContext
以XmlWebApplicationContext为例,分析#refresh方法的具体实现。
XmlWebApplicationContext的部分类图展示如下,关系较为复杂。

3.2 #refresh实现概览
在XmlWebApplicationContext的抽象父类AbstractApplicationContext中,对#refresh方法提供了模板实现。
AbstractApplicationContext#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方法包含以下几部分:
- 最外层通过synchronized(this.startupShutdownMonitor)使得容器的#refresh、#destroy是个同步操作;
- try代码块是ApplicationContext的初始化相关操作;
- 若执行过程中抛出异常,则执行catch代码块,来销毁已创建的单例bean;
- finally代码块来重置Spring中的缓存。
#refresh方法主要步骤:
- #obtainFreshBeanFactory:创建beanFactory,根据配置文件加载BeanDefinition到beanFactory;
- #invokeBeanFactoryPostProcessors:实例化、执行BeanFactoryPostProcessor,对beanFactory进行全局处理。
- #registerBeanPostProcessors:实例化BeanFactory中的BeanPostProcessor;
- #initMessageSource:注册MessageSource实例到beanFactory,用于系统国际化配置;
- #initApplicationEventMulticaster:注册ApplicationEventMulticaster实例到beanFactory;
- #registerListeners:将beanFactory中ApplicationListener关联到ApplicationEventMulticaster,并将earlyApplicationEvents推送给监听器;
- #finishBeanFactoryInitialization:初始化所有剩余的非延迟加载的单例bean;
- #finishRefresh:回调容器生命周期方法;广播ContextRefreshedEvent事件,表示ApplicationContext初始化或刷新完成;
3.3 初始化过程中的常见扩展点
| 组件 | 功能描述 | 典型实现 |
|---|---|---|
| 命名空间 | 命名空间能封装功能模块,解决命名冲突问题。 | http://www.springframework.org/schema/beans |
| BeanFactoryPostProcessor | Spring容器BeanFactory的后处理器,用于对容器中的BeanDefinition做全局化的修改 或 向BeanFactory中增加额外的BeanDefinition信息 | PropertyPlaceholderConfigurer |
| BeanPostProcessor | Bean后处理器,用于修改bean实例、处理bean注解信息等 | ApplicationContextAwareProcessor |
| 事件机制 | 事件机制是典型的观察者模式实现,可以用于不同组件之间解耦,实现不同组件的异步通信 | 在#finishRefresh方法中,将广播ContextRefreshedEvent事件,通知DispatcherServlet配置Servlet |
| Bean生命周期 | 在Bean的整个生命周期中,通过不同回调接口,更加精细地控制Bean的创建过程。 | |
| 容器生命周期 | 容器生命周期主要指SmartLifeCycle接口,可以在容器启动、关闭时执行特定的业务逻辑。 |
本文详细探讨了Spring容器的初始化过程,重点解析了#refresh方法,它是ApplicationContext的初始化入口。从Servlet的ContextLoaderListener或DispatcherServlet出发,通过调用XmlWebApplicationContext的#refresh方法启动初始化。该方法涉及beanFactory的创建、BeanFactoryPostProcessor和BeanPostProcessor的注册、MessageSource和ApplicationEventMulticaster的初始化,以及单例bean的初始化等关键步骤。

546

被折叠的 条评论
为什么被折叠?



