实例化一个spring容器(ClassPathXmlApplicationContext)
ClassPathXmlApplicationContext的构造方法如下:
/**
* Create a new ClassPathXmlApplicationContext, loading the definitions
* from the given XML file and automatically refreshing the context.
* @param configLocation resource location
* @throws BeansException if context creation failed
*/
public ClassPathXmlApplicationContext(String configLocation) throws BeansException {
this(new String[] {configLocation}, true, null);
}
/**
* Create a new ClassPathXmlApplicationContext with the given parent,
* loading the definitions from the given XML files.
* @param configLocations array of resource locations
* @param refresh whether to automatically refresh the context,
* loading all bean definitions and creating all singletons.
* Alternatively, call refresh manually after further configuring the context.
* @param parent the parent context
* @throws BeansException if context creation failed
* @see #refresh()
*/
public ClassPathXmlApplicationContext(
String[] configLocations, boolean refresh, @Nullable ApplicationContext parent)
throws BeansException {
super(parent);
// 保存配置文件定位信息到configLocations中,即[consumer.xml]
setConfigLocations(configLocations);
if (refresh) {
// 初始化容器
refresh();
}
}
实现一个ClassPathXmlApplicationContext上下文环境主要做了三件事
- 调用父类的构造方法(AbstractApplicationContext)
- 设置配置文件地址
- 初始化容器
首先我们来看其父类的构造方法:
/**
* Create a new AbstractApplicationContext with no parent.
*/
public AbstractApplicationContext() {
this.resourcePatternResolver = getResourcePatternResolver();
}
/**
* Create a new AbstractApplicationContext with the given parent context.
* @param parent the parent context
*/
public AbstractApplicationContext(@Nullable ApplicationContext parent) {
this();
setParent(parent);
}
protected ResourcePatternResolver getResourcePatternResolver() {
return new PathMatchingResourcePatternResolver(this);
}
public PathMatchingResourcePatternResolver(ResourceLoader resourceLoader) {
Assert.notNull(resourceLoader, "ResourceLoader must not be null");
this.resourceLoader = resourceLoader;
}
可以发现,在其父类的构造方法中主要设置了资源的加载器以及解析器。
接下来对配置文件进行设置,这个方法是在AbstractRefreshableConfigApplicationContext类中实现的:
@Nullable
// 配置文件的地址信息会保存到这里
private String[] configLocations;
/**
* Set the config locations for this application context.
* <p>If not set, the implementation may use a default as appropriate.
*/
public void setConfigLocations(@Nullable String... locations) {
if (locations != null) {
Assert.noNullElements(locations, "Config locations must not be null");
this.configLocations = new String[locations.length];
for (int i = 0; i < locations.length; i++) {0
// 将配置文件路径信息保存到configLocation中s
this.configLocations[i] = resolvePath(locations[i]).trim();
}
}
else {
this.configLocations = null;
}
}
最后就是初始化容器的方法了,此方法在AbstractApplicationContext类中实现:
@Override
public void refresh() throws BeansException, IllegalStateException {
synchronized (this.startupShutdownMonitor) {
// 准备工作,记录下容器的启动时间、标记“已启动”状态、处理配置文件中的占位符
// Prepare this context for refreshing.
prepareRefresh();
// 这里会将配置文件中的Bean以BeanDefinition的形式注册到容器中(obtain:得到)
// Tell the subclass to refresh the internal bean factory.
ConfigurableListableBeanFactory beanFactory = obtainFreshBeanFactory();
// 配置bean工厂(设置类加载器,时间处理器等)
// Prepare the bean factory for use in this context.
prepareBeanFactory(beanFactory);
try {
// Allows post-processing of the bean factory in context subclasses.
// 允许子类对bean工厂做一些后处理
postProcessBeanFactory(beanFactory);
// Invoke factory processors registered as beans in the context.
// 调用注册在上线文中beanfactory的后处理方法
invokeBeanFactoryPostProcessors(beanFactory);
// Register bean processors that intercept bean creation.
// 注册bean的后置处理器
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实例化之前初始化一些特殊的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.
// 销毁bean
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()方法中做的事情就比较多了,包括初始化容器状态,解析注册bean定义,配置bean工程,对后置处理器进行调用或者注册,实例化bean等,接下来我将逐个对这些方法进行源码的分析。