昔闻洞庭水,今上岳阳楼。
1 前言
在日常 web 开发中 Spring 是经常使用的开发框架,在前文中已经分享了Springboot 启动流程分析,其中涉及自动装配的原理即启动流程尚未涉及,在本文中将继续分享 Spring 启动流程的关键点,一共涉及12个关键的技术点。自动装配指的是 Spring 容器自动将相互依赖的 bean 建立联系的过程,开发者无需再 xml 或者 java 配置中显示地指定所有依赖, Spring 通过特定规则自动寻找并注入所需要的依赖。
2 refresh 核心流程
刷新上下文 refreshContext(context) -> refresh() 是 Spring 框架容器启动的核心,最终调用 AbstractApplicationContext.refresh() 方法,在 tomcat 容器中通过上下文 ServletWebServerApplicationContext 来实现。

-
1 准备刷新
prepareRefresh, 设置容器启动的时间,初始化配置,以及配置信息。在springboot环境准备中,已经获取到了systemEnvironment和systemProperties对象,这里通过initServletPropertySources方法添加servletContextInitParams和servletConfigInitParams属性。接下来通过validateRequiredProperties进行配置信息必填项校验,比如数据库连接账户密码,redis 连接等信息。 最后会设置系统的监听器和初始化既完成环境准备。 -
2
obtainFreshBeanFactory获取BeanFactory。在Spring Web开发中使用ClassPathXmlApplicationContext容器,会使用refreshBeanFactroy方法重新构造BeanFactory,读取xml配置文件构建BeanDefinition。在springboot开发中由于采用了ServletWebServerApplicationContext作为容器,已经加载了配置信息构造了BeanFactory,这里并不执行任何动作。 -
3 准备容器
prepareBeanFactory配置标准特性,这里会注册类加载器、配置文件处理器,表达式解析器(ClassLoader、PropertyEditRegister、BeanExpressionResolver)。此外还会加载ApplicationContextAwareProcessor和ApplicationListenerDetector两个后置处理器,前者是用来解析 Aware 接口,后者用来处理自定义监听器的注册和销毁。接下来会将 beanFactory 和 ApplicationContext 对象注册到特殊对象池resolvableDependencies(注册非标准Bean定义的依赖项的机制,是在DefaultListableBeanFactory中)。最后会将environment和systemProperties注册到单例池中,即singletonObjects(其在DefaultSingletonBeanRegistry中定义,它的子类是DefaultListableBeanFactory)。 -
4
postProcessBeanFactory这里会对BeanFactory进行额外的配置和修改,这里主要定义了包括request、session在内的Servlet相关作用域以及注册ServletRequest、HttpSession、ServletResponse对象到单例池中。 -
5
invokeBeanFactoryPostProcessors这里主要是调用Bean的后置处理器。其中最主要的是加载后置处理器ConfigurationClassPostProcessor,它的作用是加载所有@configuration的配置类,同时检索所有的Bean扫描路径ComponentScans, 通过ClassPathBeanDefinitionScanner.doScan扫描每个类,并将其封装成BeanDefinition对象放在Bean定义池beanDefinitionMap中。 同时也会通过processImports方法将@Import @Bean的方法加入到Bean定义池中。 -
6
registerBeanPostProcessors检索容器中的所有后置处理器BeanPostProcessor,会按照优先级(PriorityOrdered Ordered)进行排序,并将排序好的后置处理器注册到beanPostProcessors中。后置处理器会在Bean初始化之前和之后执行相应的逻辑。 -
7
initMessageSource初始化messageSource对象。这个步骤是为了实现提示信息的国际化而使用,可以在resources中自定义message.properties信息进行覆盖,实现多语言的切换配置。 -
8
initApplicationEventMulticaster初始化消息广播器applicationEventMulticaster。 有了这个配置就可以通过publishEvent方法进行事件发布。 -
9
onRefresh构建并启动web服务器。如果是spring需要使用tomcat进行启动,对于springboot来讲,需要查找实现了ServletWebServerFactory这个接口的应用服务器Bean, 默认也是内置的tomcat。 接下来通过createWebServer方法构造一个Tomcat对象,通过start方法进行启动,这样容器内部的web服务器就启动了。 -
10
registerListeners查找容器中的所有监听器并注册到第8步的消息广播器中。 -
11
finishBeanFactoryInitialization通过该方法可以生产所有业务代码中的Bean信息,整体分为构造对象、填充属性、初始化、使用、销毁等5个步骤。生产完成的对象会放置在单例池singletonObjects中。 -
12
finishRefresh构造并注册生命周期管理器LifecycleProcessor, 同时调用所有实现了该接口的类,在开始时调用start方法,在容器关闭时调用stop方法。最后发布一个容器刷新完成的事件ContextRefreshedEvent,这个自动装配的流程就完成了。
3 Bean 构建
在 2.11 finishBeanFactoryInitialization 中,实例化所有非懒加载的单例 bean。这是一个非常重要的步骤。
- 1 首先会遍历所有的
Bean定义,即BeanDefinitionNames对象。 - 2 对于所有符合条件的
Bean(单例、非抽象、非懒加载),通过getBean() -> doGetBean() -> createBean() -> doCreateBean(),最终通过createBeanInstance方法,通过反射方式创建bean对象。 - 3 在
doCreateBean()中,自动装配即填充属性 (populateBean) 发生:AutowiredAnnotationBeanPostProcessor在这里工作,注入依赖。 - 4 然后执行初始化回调 (
initializeBean - @PostConstruct, InitializingBean.afterPropertiesSet, init-method)。这里还会有实现Aware接口和实现了后置处理器的逻辑。
这里只是简单介绍其核心内容,其中还会涉及到大家知道的三级缓存,以及循环依赖的问题,在后续文章中会详细解读。
4 关键节点
通过分析以上的启动流程,我们可以根据业务需要,自定义事件监听器替代简单的异步场景、后置处理器用于对 Bean 进行修改或者添加属性。也可以自定义实现 webServer 的构建,按照自己的业务需要构建 tomcat。
了解了自动装配的原理,我们可以根据业务需要,实现自己的 starter。其中最核心的方法就是自动装配的原理: SpringFactoriesLoader.loadFactoryNames(EnableAutoConfiguration.class, classLoader) 从所有依赖的 META-INF/spring.factories文件中加载并注册。
5 总结
在本文中主要讲述了自动装配原理即 IOC 创建流程,在掌握了 spring 自动装配的原理之后,在业务开发中遇到需要对 spring 进行扩展的场景中,能够从容应对,得心应手,能够更好的完成任务,做到胸有成竹。