1.入口
public static void main(String[] args) {
ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext("spring.xml");
}
2.ClassPathXmlApplicationContext类图分析一下:
3.详细解析
/**
* 读取一个配置文件的构造方法
*/
public ClassPathXmlApplicationContext(String configLocation) throws BeansException {
this(new String[] {configLocation}, true, null);
}
/**
* 构造方法
* @param configLocations 配置文件列表
* @param refresh 是否刷新
* @param parent 父容器
*/
public ClassPathXmlApplicationContext(
String[] configLocations, boolean refresh, @Nullable ApplicationContext parent)
throws BeansException {
super(parent); //调用父类构造方法,传入parent 这里为null
setConfigLocations(configLocations);
if (refresh) {
refresh();
}
}
3.1 super方法详解
向上追溯
public AbstractXmlApplicationContext(@Nullable ApplicationContext parent) {
super(parent);
}
//===================================================================================
public AbstractRefreshableConfigApplicationContext(@Nullable ApplicationContext parent) {
super(parent);
}
//===================================================================================
public AbstractRefreshableApplicationContext(@Nullable ApplicationContext parent) {
super(parent);
}
//===================================================================================
public AbstractApplicationContext(@Nullable ApplicationContext parent) {
this();
setParent(parent);
}
//===================================================================================
public AbstractApplicationContext() {
this.resourcePatternResolver = getResourcePatternResolver();
}
protected ResourcePatternResolver getResourcePatternResolver() {
return new PathMatchingResourcePatternResolver(this);
}
/**
* 设置parent
*/
@Override
public void setParent(@Nullable ApplicationContext parent) {
this.parent = parent; //设置parent
if (parent != null) { //为空则不做处理
Environment parentEnvironment = parent.getEnvironment();
if (parentEnvironment instanceof ConfigurableEnvironment) {
getEnvironment().merge((ConfigurableEnvironment) parentEnvironment);
}
}
}
总结:
1.将AbstractApplicationContext中resourcePatternResolver属性初始化成PathMatchingResourcePatternResolver对象实例
2.将父容器parent置空
3.2 setConfigLocations方法详解
/**
* 将路径赋值给configLocations.
*/
public void setConfigLocations(@Nullable String... locations) {
if (locations != null) {
Assert.noNullElements(locations, "Config locations must not be null");//校验数组中的值,不能未null
this.configLocations = new String[locations.length];
// 1.遍历解析locations
for (int i = 0; i < locations.length; i++) {
// 2.解析给定路径,必要时用相应的环境属性值替换占位符
this.configLocations[i] = resolvePath(locations[i]).trim();
}
}
else {
this.configLocations = null;
}
}
3.2.1 Assert.noNullElements
public static void noNullElements(@Nullable Object[] array, String message) {
if (array != null) {
for (Object element : array) {
if (element == null) {
throw new IllegalArgumentException(message);
}
}
}
}
3.2.2 resolvePath
/**
* 解析给定路径,必要时用相应的环境属性值替换占位符
*/
protected String resolvePath(String path) {
// 1.getEnvironment:获取环境属性
// 2.resolveRequiredPlaceholders: 解析给定路径,必要时用相应的环境属性值替换占位符,例如${path}
return getEnvironment().resolveRequiredPlaceholders(path);
}
3.3refresh方法详解
@Override
public void refresh() throws BeansException, IllegalStateException {
//startupShutdownMonitor对象在spring环境刷新和销毁的时候都会用到,确保刷新和销毁不会同时执行
synchronized (this.startupShutdownMonitor) {
// 准备工作,记录下容器的启动时间、标记“已启动”状态、处理配置文件中的占位符
prepareRefresh();
/*
* 用于获得一个新的 BeanFactory
* 该方法会解析所有 Spring 配置文件(通常我们会放在 resources 目录下),将所有 Spring 配置文件中的 bean 定义封装成 BeanDefinition,加载到 BeanFactory 中。
* 常见的,如果解析到<context:component-scan base-package="com.joonwhee.open" /> 注解时,会扫描 base-package 指定的目录,
* 将该目录下使用指定注解(@Controller、@Service、@Component、@Repository)的 bean 定义也同样封装成 BeanDefinition,加载到 BeanFactory 中。
* 上面提到的“加载到 BeanFactory 中”的内容主要指的是以下3个缓存:
* beanDefinitionNames缓存:所有被加载到 BeanFactory 中的 bean 的 beanName 集合。
* beanDefinitionMap缓存:所有被加载到 BeanFactory 中的 bean 的 beanName 和 BeanDefinition 映射。
* aliasMap缓存:所有被加载到 BeanFactory 中的 bean 的 beanName 和别名映射。
*/
ConfigurableListableBeanFactory beanFactory = obtainFreshBeanFactory();
/*
* 配置 beanFactory 的标准上下文特征,例如上下文的 ClassLoader、后置处理器等。这个方法会注册3个默认环境
* bean:environment、systemProperties 和 systemEnvironment,
* 注册 2 个 bean 后置处理器:ApplicationContextAwareProcessor 和 ApplicationListenerDetector。
*/
prepareBeanFactory(beanFactory);
try {
/* 允许子类对 BeanFactory 进行后续处理,默认实现为空,留给子类实现。 */
postProcessBeanFactory(beanFactory);
// 激活BeanFactory的处理器
/*
* 实例化和调用所有 BeanFactoryPostProcessor,包括其子类 BeanDefinitionRegistryPostProcessor。
* BeanFactoryPostProcessor 接口是 Spring 初始化 BeanFactory 时对外暴露的扩展点,Spring IoC 容器允许
* BeanFactoryPostProcessor 在容器实例化任何 bean 之前读取 bean 的定义,并可以修改它。
*
* BeanDefinitionRegistryPostProcessor 继承自 BeanFactoryPostProcessor,比 BeanFactoryPostProcessor 具有更高的优先级,
* 主要用来在常规的 BeanFactoryPostProcessor 激活之前注册一些 bean 定义。特别是,
* 你可以通过 BeanDefinitionRegistryPostProcessor来注册一些常规的 BeanFactoryPostProcessor,
* 因为此时所有常规的 BeanFactoryPostProcessor 都还没开始被处理。
*
* 注:这边的 “常规 BeanFactoryPostProcessor” 主要用来跟 BeanDefinitionRegistryPostProcessor 区分。
*/
invokeBeanFactoryPostProcessors(beanFactory);
// 注册拦截Bean创建的Bean处理器
/*
* 注册所有的 BeanPostProcessor,将所有实现了 BeanPostProcessor 接口的类加载到 BeanFactory 中。
* BeanPostProcessor 接口是 Spring 初始化 bean 时对外暴露的扩展点,
* Spring IoC 容器允许 BeanPostProcessor 在容器初始化 bean 的前后,添加自己的逻辑处理。
* 在这边只是注册到 BeanFactory 中,具体调用是在 bean 初始化的时候。
*
* 具体的:在所有 bean 实例化时,执行初始化方法前会调用所有 BeanPostProcessor 的 postProcessBeforeInitialization 方法,
* 执行初始化方法后会调用所有 BeanPostProcessor 的 postProcessAfterInitialization 方法。
*/
registerBeanPostProcessors(beanFactory);
// 为上下文初始化Message源(初始化消息资源 MessageSource)
initMessageSource();
// 初始化应用消息广播器(初始化应用的事件广播器 ApplicationEventMulticaster)
initApplicationEventMulticaster();
// 该方法为模板方法,提供给子类扩展实现,可以重写以添加特定于上下文的刷新工作,默认实现为空。
onRefresh();
// 查找Listeners bean,注册到消息广播器中(注册监听器)
registerListeners();
// 初始化剩下的单实例
/*
* 该方法会实例化所有剩余的非懒加载单例 bean。
* 除了一些内部的 bean、实现了 BeanFactoryPostProcessor 接口的 bean、实现了BeanPostProcessor 接口的 bean,
* 其他的非懒加载单例 bean 都会在这个方法中被实例化,并且 BeanPostProcessor 的触发也是在这个方法中。
*/
finishBeanFactoryInitialization(beanFactory);
// 完成刷新过程,通知生命周期处理器
/* 完成此上下文的刷新,主要是推送上下文刷新完毕事件(ContextRefreshedEvent )到监听器 */
finishRefresh();
}
catch (BeansException ex) {
if (logger.isWarnEnabled()) {
logger.warn("Exception encountered during context initialization - " +
"cancelling refresh attempt: " + ex);
}
// 刷新失败后的处理,主要是将一些保存环境信息的集合做清理
destroyBeans();
// applicationContext是否已经激活的标志,设置为false
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();
}
}
}
详细每个方法的解析下次再说