这篇文章是阅读《Spring技术内幕》和《SpringIoC容器源码分析》后的个人笔记。
Spring 是渐进式的工具,并不具有很强的侵入性,它的模块也划分得很合理,即使你的应用不是 web 应用,或者之前完全没有使用到 Spring,而你就想用 Spring 的依赖注入这个功能,其实完全是可以的,它的引入不会对其他的组件产生冲突。
启动过程分析
ClassPathXmlApplicationContext 的构造方法中的核心方法refresh()。
之所以方法名是refresh,是因为ApplicationContext 建立起来以后,其实我们是可以通过调用 refresh() 这个方法重建的,refresh() 会将原来的 ApplicationContext 销毁,然后再重新执行一次初始化操作。
refresh()调用的一些方法
1.准备工作
prepareRefresh():记录启动时间、校验配置文件等。
2.初始化 BeanFactory、加载 Bean、注册 Bean
obtainFreshBeanFactory()->
refreshBeanFactory()->
createBeanFactory()
customizeBeanFactory() 配置是否允许 BeanDefinition 覆盖、是否允许循环引用。
loadBeanDefinitions()->loadBeanDefinitions(beanDefinitionReader) 加载配置->doRegisterBeanDefinitions() 解析 Bean 定义->parseBeanDefinitions()->
parseDefaultElement()->processBeanDefinition() 解析 bean 标签->
parseBeanDefinitionElement()->parseBeanDefinitionElement() 根据配置创建 BeanDefinition 实例,转换为 BeanDefinitionHolder
registerBeanDefinition()->registerBeanDefinition()将 BeanDefinition 放到beanDefinitionMap中
- Resource定位:指的是BeanDefinition的资源定位,它由ResourceLoader通过统一的Resource接口来完成。
- BeanDefinition的载入:把用户定义好的Bean表示成IoC容器内部的数据结构,而这个容器内部的数据结构就是BeanDefinition。
- BeanDefinition的注册:通过调用BeanDefinitionRegistry接口的实现来完成的。这个注册过程是把载入过程中解析得到的BeanDefinition向IoC容器进行注册。
Note
这里的 BeanDefinition 就是我们所说的 Spring 的 Bean,我们自己定义的各个 Bean 其实会转换成一个个 BeanDefinition 存在于 Spring 的 BeanFactory 中。
到这里已经初始化了 Bean 容器, 配置也相应的转换为了一个个 BeanDefinition,然后注册了各个 BeanDefinition 到注册中心,并且发送了注册事件。
3.准备 Bean 容器
prepareBeanFactory() 设置 BeanFactory 的类加载器,添加几个 BeanPostProcessor,Spring 在把我们在 xml 配置的 bean 都注册以后,手动注册几个特殊的 bean,如environment,systemProperties等。
4.初始化所有的 singleton beans(lazy-init 的除外)
单例的、没有设置懒加载,那么 Spring 会在接下来初始化所有的 singleton beans。
finishBeanFactoryInitialization()->preInstantiateSingletons()->getBean()
已经初始化过了就从容器中直接返回,否则就先初始化再返回。
->createBean()->doCreateBean()->
createBeanInstance() 创建 Bean 实例
populateBean() bean 属性注入
initializeBean() BeanPostProcessor 的两个回调都发生在这边,只不过中间处理了 init-method
Note
-
ApplicationContext 继承自 BeanFactory,
但是它不应该被理解为 BeanFactory 的实现类,
而是说其内部持有一个实例化的 BeanFactory(DefaultListableBeanFactory)。 -
Bean 在代码层面上可以认为是 BeanDefinition 的实例。BeanDefinition 中保存了我们的 Bean 信息,比如这个 Bean 指向的是哪个类、是否是单例的、是否懒加载、这个 Bean 依赖了哪些 Bean 等等。
-
depends-on:用来确定bean定义中依赖关系不明确或者没有直接依赖关系时,指定bean在初始化或销毁时的明确顺序。