1. spring 启动流程概览
在前面 demo 的
main()
方法中,有这么一行:
ApplicationContext context =
new AnnotationConfigApplicationContext("org.springframework.learn.demo01");
复制代码
这短短的一行就是spring的整个启动流程了。上面的代码中,声明了一个
ApplicationContext
类型的对象
context
,右边使用其子类
AnnotationConfigApplicationContext
实例化,并在构造方法中传入了包名
org.springframework.learn.demo01
,这个包名就表明了接下来要扫描哪些包。
这里我们接触到了spring的第一个组件:
ApplicationContext
,关于
ApplicationContext
的分析,可以参考我的文章spring组件(一):ApplicationContext。
进入到
AnnotationConfigApplicationContext
,代码如下:
AnnotationConfigApplicationContext#AnnotationConfigApplicationContext(String...)
public AnnotationConfigApplicationContext(String... basePackages) {
// 1. 调用无参构造函数,会先调用父类GenericApplicationContext的构造函数
// 2. 父类的构造函数里面就是初始化DefaultListableBeanFactory,并且赋值给beanFactory
// 3. 本类的构造函数里面,初始化了一个读取器:AnnotatedBeanDefinitionReader read,
// 一个扫描器ClassPathBeanDefinitionScanner scanner
// 4. 这个scanner,就是下面 scan(basePackages) 调用的对象
this();
//对传入的包进行扫描,扫描完成后,会得到一个 BeanDefinition 的集合
scan(basePackages);
//启动spring,在这里完成spring容器的初始化操作,
//包括bean的实例化、属性注入,将bean保存到spring容器中等
refresh();
}
复制代码
这个类就三行,相关操作都已在代码中注释了,这里稍微再总结下,这段代码主要做了三件事:
- 调用无参构造,进行属性初始化
- 进行包扫描,得到BeanDefinition
- 启用spring容器。
接着,我们再来看看spring启动流程中,做了哪些事:
AbstractApplicationContext#refresh
public void refresh() throws BeansException, IllegalStateException {
// 使用synchronized是为了避免refresh() 还没结束,再次发起启动或者销毁容器引起的冲突
synchronized (this.startupShutdownMonitor) {
// 做一些准备工作,记录容器的启动时间、标记“已启动”状态、检查环境变量等
prepareRefresh();
// 初始化BeanFactory容器、注册BeanDefinition, 最终获得了DefaultListableBeanFactory
ConfigurableListableBeanFactory beanFactory = obtainFreshBeanFactory();
// 还是一些准备工作:
// 1. 设置了一个类加载器
// 2. 设置了bean表达式解析器
// 3. 添加了属性编辑器的支持
// 4. 添加了一个后置处理器:ApplicationContextAwareProcessor
// 5. 设置了一些忽略自动装配的接口
// 6. 设置了一些允许自动装配的接口,并且进行了赋值操作
// 7. 在容器中还没有XX的bean的时候,帮我们注册beanName为XX的singleton bean
prepareBeanFactory(beanFactory);
try {
// Spring的一个扩展点. 如果有Bean实现了BeanFactoryPostProcessor接口,
// 那么在容器初始化以后,Spring 会负责调用里面的 postProcessBeanFactory 方法。
// 具体的子类可以在这步的时候添加特殊的 BeanFactoryPostProcessor 的实现类,来做些事
postProcessBeanFactory(beanFactory);
// 调用BeanFactoryPostProcessor各个实现类的postProcessBeanFactory(factory) 方法
invokeBeanFactoryPostProcessors(beanFactory);
// 扩展点,注册 BeanPostProcessor 的实现类,注意不是BeanFactoryPostProcessor
registerBeanPostProcessors(beanFactory);
// 初始化当前 ApplicationContext 的 MessageSource,用在国际化操作中
initMessageSource();
// 这个方法主要为初始化当前 ApplicationContext 的事件广播器
initApplicationEventMulticaster();
// 这也是spring的一个扩展点
onRefresh();
// Check for listener beans and register them.
// 注册事件监听器
registerListeners();
// 初始化所有的 singleton beans
finishBeanFactoryInitialization(beanFactory);
// 完成启动,
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.
// 重置 'active' 状态
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();
}
}
}
复制代码
这个方法虽然代码不多,但包含了spring bean的整个创建过程,每个方法做了些什么,在代码中都有注释,这里就不赘述了。
实际上,
refresh()
涵盖了spring整个创建bean的流程,在后面的文章中,我们也将重点展开这里面的方法来分析,在现阶段只需要大致了解这些方法做了什么事即可。
整个流程总结如下:
2. spring启动中
beanFactory
的变化
本文中的源码解读就到这里了,接下来我们来看看,spring启动中
beanFactory
有些什么变化。
beanFactory
是spring的重要组件之一,直译为spring bean工厂,是spring生产bean与保存bean的地方,关于
beanFactory
的详细分析,可以查看spring BeanFactory分析。
我们将断点打在
AnnotationConfigApplicationContext#AnnotationConfigApplicationContext(String...)
的
this()
方法上,然后运行demo01的
main()
方法:
此时的变量中,并没有
beanFactory
,我们自己添加
beanFactory
到调度窗口的变量列表中:
这样就能看到对应的值了:
可以看到,此时的
beanFactory
为null,表明
beanFactory
并未实例化,我们继续运行:
当运行完
this()
后,发现
beanFactory
已经有值了,类型为
DefaultListableBeanFactory
。但是,在查看
beanFactory
对象时,发现
beanFactory
的属性太多了,我们应该重点关注啥呢?
我们这部分主要关注spring bean的创建,因此只需要关注
beanFactory
的两个属性就可以了:
- beanDefinitionMap:存放beanDefinition的map.
- singletonObjects:存放spring bean的map,spring bean创建后都存放在这里,也即直观上理解的
spring 容器
.
BeanDefinition
是spring重要组件之一,为‘spring bean的描述’,简单来说,就是说明了一个spring bean应该如何创建。关于
BeanDefinition
的详细分析,可以查看spring BeanDefinition分析。
我们手动添加变量,如下:
可以看到,此时的
beanDefinitionMap
中已经有4个对象了,显然是在
this()
方法中添加的,关于这块我们后面会分析。
接着运行,发现
beanDefinitionMap
又多了两个:
这里的
beanObj1
与
beanObj2
就是我们自己的类了,由此可以判断出**spring就是在
AnnotationConfigApplicationContext#scan
方法中对包进行扫描的**。
接下来,代码执行进入
AbstractApplicationContext#refresh
方法,我们一行行运行下去,发现运行到
prepareBeanFactory(beanFactory);
时,
singletonObjects
中第一次出现了对象:
可以看到,这里出现了3个类,基本都跟系统、环境相关,如
environment
是spring当前使用的环境(
profile
),
systemProperties
当前系统的属性(操作系统、操作系统版本等)。
继续往下运行,发现代码运行到
invokeBeanFactoryPostProcessors(beanFactory)
时,又多了4个类:
关于这几个类的作用,我们后面的文章中会分析,这里先不必管。继续往下运行,发现在
registerBeanPostProcessors(beanFactory);
中,又多了一个对象:
org.springframework.context.annotation.internalAutowiredAnnotationProcessor
复制代码
这里我们依旧不用管这个对象,接着运行下去,可以看到在运行
initMessageSource()
时,又多了一个对象:
messageSource -> {DelegatingMessageSource@1847} "Empty MessageSource"
复制代码
显然,这个对象是用来处理国际化问题的,不过由于demo01中并没有用到国际化,所以这里显示
Empty MessageSource
。继续运行,发现运行到
initApplicationEventMulticaster();
时,又多了一个对象:
applicationEventMulticaster -> {SimpleApplicationEventMulticaster@1869}
复制代码
显然,这个对象是用来处理
ApplicationContext
的广播事件的,我们的demo中并没有用到,暂时不必理会。继续下去,发现在运行完
finishBeanFactoryInitialization(beanFactory);
,
singletonObjects
中终于出现了我们期待的对象:
由此可见,对象就是在该方法中创建的。
总结
- spring 包的描述:
AnnotationConfigApplicationContext#scan
- spring bean的创建:
AbstractApplicationContext#finishBeanFactoryInitialization
版权归原作者 JAVA序码 所有, 如有侵权,请联系我们删除。