由于平时项目中都会用到spring,但是一般都是已经配好了,我们直接使用即可,如果对源码感兴趣的童鞋可以关注下我的博客,后面会有相应的更新。这段时间有点时间,就研究了下spring的源码,打算在近期详细的归纳一下spring容器是怎么运行管理bean的整个周期。
我们简单的拿出一个spring容器初始化的代码 这里我们拿出的是基于xml的方式 基于注解的也大同小异(后续有空也可以分享)
package com.test.main;
import com.test.seivice.CarService;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
public class test {
public static void main(String[] args) {
ApplicationContext applicationContext = new ClassPathXmlApplicationContext("classpath*:game.xml");
CarService testDao = (CarService) applicationContext.getBean("test");
System.out.println(testDao);
}
}
AplicationContext applicationContext = new ClassPathXmlApplicationContext("classpath*:game.xml"); 简单的一行代码就实现了spring 容器初始化的整个过程,这也就是我们开始研究的入口
我们点进 ClassPathXmlApplicationContext方法里面
public ClassPathXmlApplicationContext(String configLocation) throws BeansException {
this(new String[] {configLocation}, true, null);
}
这是一个有参构造函数 我们继续点进去this方法
public ClassPathXmlApplicationContext(
String[] configLocations, boolean refresh, @Nullable ApplicationContext parent)
throws BeansException {
// 这个地方 我们传进来的parent对象为空 一路断点进去 发现parent始终为空 我们尚且不关注
super(parent);
// 将配置文件路径设置给AbstractRefreshableConfigApplicationContext 的configLocations的属性
setConfigLocations(configLocations);
// 由上面的参数传进refresh为true 下面我们就进入refresh方法 spring初始化全程
if (refresh) {
refresh();
}
}
由上面的注释 我们得知refresh()方法是贯穿spring整个初始化的方法
@Override
public void refresh() throws BeansException, IllegalStateException {
//加锁 防止 fresh还没结束 就又进入改方法 导致容器初始化错乱
synchronized (this.startupShutdownMonitor) {
// Prepare this context for refreshing.
//准备工作 初始化spring状态 使spring处于运行状态
prepareRefresh();
// Tell the subclass to refresh the internal bean factory.
//这一步主要作用是将配置文件定义解析成beanDefine 注册到beanFactory中
//但是这里的bean并没有初始化出来 只是提取配置信息 定义相关的属性
//将这些信息保存到beanDefineMap中(beanName->beanDefine)对应的map
//我们将深入进去 仔细看看源码
ConfigurableListableBeanFactory beanFactory = obtainFreshBeanFactory();
// Prepare the bean factory for use in this context.
//设置BeanFactory的类加载器,添加几个BeanPostProcessor 手动注册几个特殊的bean
prepareBeanFactory(beanFactory);
try {
// Allows post-processing of the bean factory in context subclasses.
//重要
postProcessBeanFactory(beanFactory);
// Invoke factory processors registered as beans in the context.
// 重要 在spring的环境中执行已经被注册的factory processors
// 设置执行自定义的ProcessBeanFactory 和 spring内部的定义的
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.
// 初始化所有的singleton beans 到目前为止 我们已经完成了beanFactory的创建
// 如果没有设置懒加载 spring会为我们初始化所有的bean
finishBeanFactoryInitialization(beanFactory);
// Last step: publish corresponding event.
finishRefresh();
} catch (BeansException 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()方法中的12个方法,这个方法也是注解或者xml解析必须经过的方法。
建议读者下载spring源码 这样方便于注释 断点调式,下面一章我们来介绍下 prepareRefresh()方法