上一篇介绍了如何下载spring源码,编译,及修改源码+注解的使用
spring容器的基本使用及xml配置属性的说明;
这篇文章来介绍下spring容器时如何加载解析xml配置到spring容器中的
首先从测试代码中看到
package com.wsj.spring;
import com.wsj.spring.bean.LookUpSayHello;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
public class MyTest {
public static void main(String[] args) {
ApplicationContext app=new ClassPathXmlApplicationContext("test.xml");
LookUpSayHello bean = app.getBean(LookUpSayHello.class);
bean.sayHello();
}
}
使用ClassPathXmlApplicationContext加载xml文件,下面跟进去,最终调到这个构造方法
/**
* 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);
//这里可以根据不同的子类实现
// 根据提供的路径,处理成配置文件数组(以分号、逗号、空格、tab、换行符分割)
setConfigLocations(configLocations);
if (refresh) {
/**
* 这里简单说下为什么是 refresh(),而不是 init() 这种名字的方法。
* 因为 ApplicationContext 建立起来以后,其实我们是可以通过调用 refresh() 这个方法重建的,这样会将原来的 ApplicationContext 销毁,
* 然后再重新执行一次初始化操作。
*/
refresh();// 核心方法
}
}
点击进入refresh()方法,会看到跳转到父类(其实时爷爷的爷爷类)
AbstractApplicationContext中,
@Override
public void refresh() throws BeansException, IllegalStateException {
// 来个锁,不然 refresh() 还没结束,你又来个启动或销毁容器的操作,那不就乱套了嘛
synchronized (this.startupShutdownMonitor) {
// Prepare this context for refreshing.
// 准备工作,记录下容器的启动时间、标记“已启动”状态、处理配置文件中的占位符
prepareRefresh();
// Tell the subclass to refresh the internal bean factory.
// 这步比较关键,这步完成后,配置文件就会解析成一个个Bean定义(BeanDefinition),注册到 BeanFactory 中,
// 当然,这里说的 Bean 还没有初始化,只是配置信息都提取出来了,
// 注册也只是将这些信息都保存到了注册中心(说到底核心是一个 beanName-> beanDefinition 的 map)
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);
//完成BeanFactoryPostProcessors 和BeanDefinitionRegistryPostProcessor的实例化,执行相应的postProcessor方法
// Invoke factory processors registered as beans in the context.
invokeBeanFactoryPostProcessors(beanFactory);
//实例化所有beanPostProcessors实例到容器中
// Register bean processors that intercept bean creation.
registerBeanPostProcessors(beanFactory);
//国际化代码
// Initialize message source for this context.
initMessageSource();
//spring事件代码
// Initialize event multicaster for this context.
initApplicationEventMulticaster();
//可以自定义的onRefresh()
// Initialize other special beans in specific context subclasses.
onRefresh();
//事件的监听
// Check for listener beans and register them.
registerListeners();
//初始化单实例bean。spring ioc的核心代码入口
// Instantiate all remaining (non-lazy-init) singletons.
finishBeanFactoryInitialization(beanFactory);
//完成容器的刷新
// Last step: publish corresponding event.
finishRefresh();
}
catch (BeansException ex) {
if (logger.isWarnEnabl