spring 是java技术系列公认的最优秀的源码,甚至没有之一 。。。那么我们平时在用到spring框架大部分都是会使用注解或者配置的方式。。但是具体其中的原理也都是似懂非懂,包括本人在内,之前只会使用一些spring的注解或者配置方式,又或者是会使用spring的扩展机制来做一些高级功能,,,学习原理最好的方式还是来读懂并且调试spring源码最直接。。。同时对于我们以后去读其他开源代码也有巨大帮助,,,小编觉得spring源码的思想被很多开源代码所采纳。。故可举一反三。。。本文将简单介绍spring启动的十六个步骤,,后续的文章会介绍每一个模块的作用
1.要有耐心,,我们可以先弄懂spring大概的生命周期。。然后针对每一个步骤逐个突破,,,
2.有些部分,可能你看到会有疑惑,没有关系,小编觉得要硬着头皮看下去,因为可能你看到后面某个点,对前面的就理解了。
3.我们尽量在学习源码的时候加上我们自己的注释,,,这样有利于我们之后再去理解,复习。。。
4.如果在阅读过程中有不理解的,可以debug 来调试,这样直观且容易记住过程。。。
通常我们启动一个spring容器有两种方式,,
第一种是传统的spring启动方式-利用web.xml来启动容器。。
如:
ContextLoaderListener 是实现了 javax.servlet.ServletContextListener 接口的服务器端程序,随 web 应用的启动而启动,只初始化一次,随 web 应用的停止而销毁。在web应用启动的时候会调用 contextInitialized 方法,停止的时候会调用 contextDestroyed 方法。
第二种就是springboot的启动方式如下:
我们点击new AnnotationConfigApplicationContext源码可以发现这三步:
在构造AnnotationConfigApplicationContext时,会先调用父类GenericApplicationContext的构造方法,GenericApplicationContext会初始化一个beanFactory,默认值为DefaultListableBeanFactory,如下:
从中我们可以看出,这个方法就是new 一个DefaultListableBeanFactory,然后会在里面存一个beanDefinitionMap,根据名字可以看出,它放置的是一些关于注解的默认的后置处理器的beandefinition...
AnnotationConfigApplicationContext的类结构图
重点关注ConfigurationClassPostProcessor和AutowiredAnnotationBeanPostProcessor。
RootBeanDefinition的类结构图
在生成scanner的过程中,主要会注册几个默认的includeFilters:
重点关注AnnotationTypeFilter(Component.class),它是用来判断一个类是不是应该被Spring扫描到的
debug 发现:
从代码中可以看到,,是将我自己的mainconfig这个类的beandefiniton注册到bean工厂中。。。
最终我们来到了refresh方法,如下:
为刷新准备新的上下文环境,设置其启动日期和活动标志以及执行一些属性的初始化。主要是一些准备工作,不是很重要的方法,可以先不关注。
用于获得一个新的 BeanFactory。
该方法会解析所有 Spring 配置文件(通常我们会放在 resources 目录下),将所有 Spring 配置文件中的 bean 定义封装成 BeanDefinition,加载到 BeanFactory 中。常见的,如果解析到
这里 如果是xml中配置的bean,那么对应的beandefinition就是GenericBeanDefinition 而使用scan扫描到的注解的类对应的beandefinition就是 AnnotatedGenericBeanDefinition,AnnotatedGenericBeanDefinition 是GenericBeanDefinition 的扩展。。
从这里我们可以看出注解是xml的扩展机制。。。
上面提到的“加载到 BeanFactory 中”的内容主要指的是以下3个缓存:
beanDefinitionNames缓存:所有被加载到 BeanFactory 中的 bean 的 beanName 集合。
beanDefinitionMap缓存:所有被加载到 BeanFactory 中的 bean 的 beanName 和 BeanDefinition 映射。
aliasMap缓存:所有被加载到 BeanFactory 中的 bean 的 beanName 和别名映射。
配置 beanFactory 的标准上下文,例如上下文的 ClassLoader、后置处理器等。这个方法会注册3个默认环境 bean:environment、systemProperties 和 systemEnvironment,注册 2 个 bean 后置处理器:ApplicationContextAwareProcessor 和 ApplicationListenerDetector
这个方法允许子类对 BeanFactory 进行后续处理,默认实现为空,留给子类实现。
这里只截取了一部分代码。。。。
实例化和调用所有 BeanFactoryPostProcessor,包括其子类 BeanDefinitionRegistryPostProcessor。
BeanFactoryPostProcessor 接口是 Spring 初始化 BeanFactory 时对外暴露的扩展点,Spring IoC 容器允许 BeanFactoryPostProcessor 在容器实例化任何 bean 之前读取 bean 的定义,并可以修改它。
BeanDefinitionRegistryPostProcessor 继承自 BeanFactoryPostProcessor,比 BeanFactoryPostProcessor 具有更高的优先级,主要用来在常规的 BeanFactoryPostProcessor 激活之前注册一些 bean 定义。特别是,你可以通过 BeanDefinitionRegistryPostProcessor 来注册一些常规的 BeanFactoryPostProcessor,因为此时所有常规的 BeanFactoryPostProcessor 都还没开始被处理。
这里的 “常规 BeanFactoryPostProcessor” 主要用来跟 BeanDefinitionRegistryPostProcessor 区分。
注册所有的 BeanPostProcessor,将所有实现了 BeanPostProcessor 接口的类加载到 BeanFactory 中。
BeanPostProcessor 接口是 Spring 初始化 bean 时对外暴露的扩展点,Spring IoC 容器允许 BeanPostProcessor 在容器初始化 bean 的前后,添加自己的逻辑处理。在这边只是注册到 BeanFactory 中,具体调用是在 bean 初始化的时候。
具体的:在所有 bean 实例化时,执行初始化方法前会调用所有 BeanPostProcessor 的 postProcessBeforeInitialization 方法,执行初始化方法后会调用所有 BeanPostProcessor 的 postProcessAfterInitialization 方法。
初始化消息资源 MessageSource。
初始化应用的事件广播器 ApplicationEventMulticaster 用来保存第十四步的listener
该方法为模板方法,提供给子类扩展实现,可以重写以添加特定于上下文的刷新工作,默认实现为空。
注册监听器。
这一步非常重要,,,也是spring的核心源码。。。。
该方法会实例化所有剩余的非懒加载单例 bean。除了一些内部的 bean、实现了 BeanFactoryPostProcessor 接口的 bean、实现了 BeanPostProcessor 接口的 bean,其他的非懒加载单例 bean 都会在这个方法中被实例化,并且 BeanPostProcessor 的触发也是在这个方法中。
1、遍历所有被加载到缓存中的 beanName,触发所有剩余的非懒加载单例 bean 的实例化。
2、首先通过 beanName 尝试从缓存中获取,如果存在则跳过实例化过程;否则,进行 bean 的实例化。
3、根据 BeanDefinition,使用构造函数创建 bean 实例。
4、根据 BeanDefinition,进行 bean 实例属性填充。
5、执行 bean 实例的初始化。
5.1、触发 Aware 方法。
5.2、触发 BeanPostProcessor 的 postProcessBeforeInitialization 方法。
5.3、如果 bean 实现了 InitializingBean 接口,则触发 afterPropertiesSet() 方法。
5.4、如果 bean 设置了 init-method 属性,则触发 init-method 指定的方法。
5.5、触发 BeanPostProcessor 的 postProcessAfterInitialization 方法。
6、将创建好的 bean 实例放到缓存中,用于之后使用。
完成此上下文的刷新,主要是推送上下文刷新完毕事件(ContextRefreshedEvent )到监听器。
到此为止,,spring容器所有的启动过程已介绍完毕。。。。后续小编会逐个突破每一部分的源码。。。