前言
Spring 是分层的 full-stack(全栈) 轻量级开源框架,以 IoC 和 AOP 为内核,提供了展现层 SpringMVC 和业务层事务管理等众多的企业级应⽤技术,还能整合开源世界众多著名的第三⽅框架和类库,已经成为使⽤最多的 Java EE 企业应⽤开源框架。因此无论在以后面试还是工作学习中,都是很重要的,学习知识可能最开始我们只是知道怎么用,但在熟练使用之后,我们需要去看一下源码是如何实现的,体会框架的思想并学习,提升自己的编程思想与能力,因此本文就从源码阶段介绍一下spring的ioc执行流程。欢迎大家多多指教!
一、源码阅读的技巧
- 好处:提⾼培养代码架构思维、深⼊理解框架
- 原则
定焦原则:抓主线
宏观原则:站在上帝视⻆,关注源码结构和业务流程(淡化具体某⾏代码的编写细节不然会迷失在源码中,跳不出来,开始奔溃!) - 读源码的⽅法和技巧
A. 断点(观察调⽤栈)
B. 反调(Find Usages)
C. 经验(spring框架中doXXX,做具体处理的地⽅
二、IOC中关键的接口和类
1.BeanFactory
Spring 提供了很多的容器,其中 BeanFactory 是顶层容器(根容器),不能被实例化(它是接口),它定义了所有 IoC 容器 必须遵从的⼀套原则,具体的容器实现可以增加额外的功能,⽐如我们常⽤到的ApplicationContext,其下更具体的实现如 ClassPathXmlApplicationContext 包含了解析 xml 等⼀系列的内容,AnnotationConfigApplicationContext 则是包含了注解解析等⼀系列的内容。Spring IoC 容器继承体系⾮常聪明,需要使⽤哪个层次⽤哪个层次即可,不必使⽤功能⼤⽽全的。
在idea中想要查看某个类或者接口的层级关系十分简单,只需要选中类ctrl+alt+u就能显示,比如ClassPathXmlApplicationContext ,从下图中我们可以看出他并不只是继承或者实现某一个接口或者类,这就验证了Spring IoC 容器继承体系⾮常聪明,我们不需要使用全而强大的全功能,而是将所有功能按照某规则分出来,需要什么就继承什么,大大减少使用的难度。
2.Bean⽣命周期关键时机点
通过之前我们在导入源码时写的测试类,开始断点调试。通过下面的调用栈 我们就可以分析出程序的执行流程。最关键的就是refresh()这个方法。
三、IOC总流程分析
@Override
public void refresh() throws BeansException, IllegalStateException {
// 对象锁加锁 Object startupShutdownMonitor = new Object()
synchronized (this.startupShutdownMonitor) {
// Prepare this context for refreshing.
/*刷新之前的预处理
表示在真正做refresh操作之前需要准备的事情
设置Spring容器的启动时间
开启活跃状态 撤销关闭状态
验证环境信息里一些必须存在的属性等*/
prepareRefresh();
// Tell the subclass to refresh the internal bean factory.
// 获取BeanFactory :默认实现是 DefaultListableBeanFactory
// 加载BeanDefition 并注册到 BeanDefitionRegistry
// 关键步骤
ConfigurableListableBeanFactory beanFactory = obtainFreshBeanFactory();
// Prepare the bean factory for use in this context.
// BeanFactory的预准备工作(前置处理)(BeanFactory进行设置 比如context的类加载器等)
prepareBeanFactory(beanFactory);
try {
// Allows post-processing of the bean factory in context subclasses.
// BeanFactory的准备工作完成之后 进行的后置处理工作
postProcessBeanFactory(beanFactory);
// Invoke factory processors registered as beans in the context.
// 实例化实现了BeanFactoryPostProcessor接口的bean,并调用接口方法
invokeBeanFactoryPostProcessors(beanFactory);
// Register bean processors that intercept bean creation.
// 注册BeanPostProcessor(bean的后置处理),在创建bean的前后等执行
registerBeanPostProcessors(beanFactory);
// Initialize message source for this context.
// 初始化MessageSource组件(做国际化功能:消息绑定和消息解析)
initMessageSource();
// Initialize event multicaster for this context.
// 初始化事件派发器
initApplicationEventMulticaster();
// Initialize other special beans in specific context subclasses.
// 子类重写这个方法,在容器刷新的时候可以自定义逻辑:如创建tomcat jetty等web服务器
onRefresh();
// Check for listener beans and register them.
// 注册应用的监听器。就是注册实现了ApplicationListener接口的监听器bean
registerListeners();
// Instantiate all remaining (non-lazy-init) singletons.
// 初始化所有剩下的非懒加载的单例bean
// 初始化创建非懒加载方式的单例bean的实例(属性未设置)
// 填充属性
// 初始化方法调用(比如调用afterPropertiesSet方法,init-method方法)
// 调用beanPostProcessor(后置处理器)对实例bean进行后置处理
finishBeanFactoryInitialization(beanFactory);
// Last step: publish corresponding event.
// 完成context的刷新。主要调用LifecycleProcessor的onRefresh()方法,并且发布事件(contextRefreshEvent)
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.
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();
}
}
}
总结
spring 容器初始化最重要的方法就是 refresh() 方法是所有的入口方法。然后就是刷新之前的预处理,比如设置容器启动时间,活跃状态等等,然后就是BeanFacotry的注册,初始化,后置处理等等,在到bean的初始化 前后置处理和将初始化的bean放入SingletonObjects池中。后续会详细解析beanFactory的初始化和bean的初始化和如何通过三级缓存来解决单例通过set注入的bean的循环依赖问题!