Spring学习笔记之启动

简介:

wKiom1nYl-jD_XwmAAAnevpU4QE930.png

今天,以ClassPathXmlApplicationContext为例来看一下,Spring启动的时候都做了什么

wKiom1nYmJqj4-piAAAawDSEZ4w307.png

wKioL1nYmEygSmIBAAA0VnytlHQ615.png

重点看refresh()方法

refresh()方法是在AbstractApplicationContext类中定义的

ClassPathXmlApplicationContext间接继承AbstractApplicationContext

wKiom1nYmbDgNsVXAAFEofaJepk297.png

这里面每一行代码的注释都写得很清楚我就不废话了,一行一行往下看

第1步、准备刷新上下文(PS:就不细看了)

第2步、获取BeanFactory


wKiom1nYm0WQhSkjAACSbf737qs538.png

AbstractApplicationContext中的refreshBeanFactory()方法是一个抽象方法,咱们看一下具体实现。具体实现实在AbstractRefreshableApplicationContext类中。

wKiom1nYm_iwkz4AAACcQ4U2Q50513.png

可以看到,如果Bean工厂存在,则销毁,然后重新创建,不存在,则新建。

wKiom1nYnIbQOfM3AADTazx-jy0444.png

可以看到,新创建的Bean工厂是new了一个DefaultListableBeanFactory。

有了Bean工厂以后,接下来加载Bean定义。

本示例中loadBeanDefinitions()方法是在AbstractXmlApplicationContext类中定义的。

AbstractXmlApplicationContext间接继承AbstractRefreshableApplicationContext,同时,也是ClassPathXmlApplicationContext的直接父类。

wKioL1nYncyiCJBUAADlQnWX4Eo104.png

至于,它到底是怎么加载,怎么解析的,这里就不细说了,很复杂

wKiom1nYnuGTHJ7pAABUqFAjoPw886.png

总之呢,到此为止,BeanFactory也获取到了,Bean定义也加载了。

接下来,回到refresh()

第3步、准备BeanFactory

wKiom1nYoQaRGSIgAAGSf_jilSM940.png

这里,对传入的BeanFactory做了一系列配置,比如,类加载器,表达式解析器,BeanPostProcessor。反正,到此为止,BeanFactory已经创建并配置完成,接下来第4步调用postProcessBeanFactory()方法,这个方法是为子类预留的,就是一个后置回调,允许子类在BeanFactory初始化之后做一些事情。

第5步、实例化并调用所有已经在BeanFactory中注册了的BeanFactoryPostProcessor

wKioL1nYo_fyLRYHAADdNnf55bI457.png

wKiom1nYpEXTa5UPAAEbDTDFdLE722.png

wKiom1nYpEWD9JucAAENZEdtfvc687.png


这里补充一点,DefaultListableBeanFactory是实现了BeanDefinitionRegistry接口的。

wKioL1nYpPeSirYsAAArPfK9pk8993.png

wKiom1nYpUXQZFAoAAF40_jdBys489.png

第6步、实例化并且调用所有已经注册的BeanPostProcessor(PS:注意,是BeanPostProcessor,而不是BeanFactoryPostProcessor,BeanFactoryPostProcessor是在上一步中完成的。从这里我们也可以看出BeanFactoryPostProcessor和BeanPostProcessor的执行顺序。)

wKioL1nYqYbiTKZvAAA-V052zNw988.png

wKioL1nYqROhKqjKAAFG9bzV0WY696.png

wKiom1nYqWHiLO8jAAFC4XMVOns865.png

这里,从Bean定义中找到所有BeanPostProcessor类型的定义然后注册他们

第7步、初始化Message Resource

第8步、初始化时间广播器

第9步、初始化子类中其它的Bean,这里为子类留了一个口子

第10步、注册监听器

第11步、实例化所有的单例的非懒加载的Bean(PS:就是scope=singleton,并且lazy-init=false的Bean)

wKiom1nYrpvQ9mM_AAFSZAtjMFs815.png

接下来,看看DefaultListableBeanFactory是怎么实现的

wKioL1nY5W7QpmmnAAF7o1H4Hxk728.png

wKiom1nY5dXgxC1lAABdiW2UOpg907.png


这里初始化所有非懒加载的单例Bean

重点看getBean()方法

wKioL1nYs-iQE7yoAAAj0dnnmeY329.png

接着往下看doGetBean()

wKiom1nYtIqSGtl4AAETlLVK2gM832.png

看到有一个createBean方法

wKioL1nYuBmBKXmyAAE48Hzlaac182.png

wKioL1nY8a3Cq4EIAALGkN9DhNA811.png

wKiom1nYuZHQO6EgAAGusHyCZsE035.png

wKiom1nY8zHgs9aGAAIkFFKW_AY728.png

wKioL1nY8uPBJtAdAACSE6W0Uok714.png

前面,费了那么大的劲就是做一些校验啊之类的,最终获得了RootBeanDefinition,有了这个东西之后就可以实例化了。

在上面的createBeanInstance方法中,

(1)如果这个类不是public的话,抛异常

(2)这个Bean的定义中有工厂方法,则使用它自带的工厂方法实例化

(3)如果需要自动装配,就用构造器装配实例化

(4)如果都不是,就用普通的方式实例化,其实就是用默认的构造器实例化

wKioL1nYu9CwCdXoAADQ7NhHuC0966.png

实例化之前,这里要获取实例化的策略。

那么,有哪些策略呢?

wKiom1nYvYmjbP9aAAAkELzRTHE322.png

wKiom1nYvYnwn75EAAAycONNf5I487.png

wKioL1nYvTuCUDobAAEENUJAF3c292.png


这里,我们可以清楚的看到,默认的策略是Cglib

用Cglib返回的是代理对象

另外,还有一种就是普通的用默认构造方法实例化,这种返回的是真实对象。

接下来,还有最后一步

第12步、初始化LifecycleProcessor,并调用其onRefresh()方法,然后发布ContextRefreshedEvent事件


到此为止,AbstractApplicationContext的refresh()方法算是讲完了。

下面总结一下:

第1步、准备刷新

第2步、加载Bean定义,并获取BeanFactory,这里获取的是DefaultListableBeanFactory

第3步、配置BeanFactory,包括配置类加载器、配置BeanPostProcessor

第4步、调用postProcessBeanFactory()方法,这个方法是给子类预留的

第5步、实例化并调用所有注册的BeanFactoryPostProcessor

第6步、实例化并调用所有注册的BeanPostProcessor

第7步、初始化message resource

第8步、初始化事件广播器

第9步、调用onRefresh()方法,这是一个模板方法,是给子类预留的

第10步、注册监听器

第11步、完成BeanFactory的初始化,并且实例化所有的非延迟加载的单例(scope=singleton,lazy-init=false)Bean

第12步、初始化LifecycleProcessor,并调用其onRefresh()方法,然后发布ContextRefreshedEvent事件


到此结束!!!

最后,补充两点:

第一点是onRefresh()方法

wKiom1nYwmbT7WSrAABJZofMre0376.png

第二点是,当第一次调用getBean()方法时会触发依赖注入,从上面的第11步中我们可以看到,大部分Bean在Spring启动的时候就已经完成了依赖注入。注入是在AbstractAutowireCapableBeanFactory类的populateBean方法完成的。

第三点是,Spring对Bean的依赖关系提供了两种方式:

(1)显式方式:通过BeanDefinition中的属性和构造方法,即通过构造方法的形式将依赖的Bean传入进来

(2)自动装配(autowiring):容器会自动使用反射查找属性的类型和名称,然后基于属性的类型或者名称来自动匹配容器中管理的Bean,从而自动地完成依赖注入。

wKiom1nY7h_So14EAAECPoCv__I843.png

本文转自   手不要乱摸  51CTO博客,原文链接:http://blog.51cto.com/5880861/1970641

相关文章
|
2天前
|
前端开发 Java 开发者
Spring生态学习路径与源码深度探讨
【11月更文挑战第13天】Spring框架作为Java企业级开发中的核心框架,其丰富的生态系统和强大的功能吸引了无数开发者的关注。学习Spring生态不仅仅是掌握Spring Framework本身,更需要深入理解其周边组件和工具,以及源码的底层实现逻辑。本文将从Spring生态的学习路径入手,详细探讨如何系统地学习Spring,并深入解析各个重点的底层实现逻辑。
22 9
|
22天前
|
前端开发 Java 数据库
SpringBoot学习
【10月更文挑战第7天】Spring学习
33 9
|
23天前
|
XML Java 数据格式
Spring学习
【10月更文挑战第6天】Spring学习
19 1
|
28天前
|
Java 测试技术 开发者
springboot学习四:Spring Boot profile多环境配置、devtools热部署
这篇文章主要介绍了如何在Spring Boot中进行多环境配置以及如何整合DevTools实现热部署,以提高开发效率。
52 2
|
28天前
|
前端开发 Java 程序员
springboot 学习十五:Spring Boot 优雅的集成Swagger2、Knife4j
这篇文章是关于如何在Spring Boot项目中集成Swagger2和Knife4j来生成和美化API接口文档的详细教程。
49 1
|
28天前
|
Java API Spring
springboot学习七:Spring Boot2.x 拦截器基础入门&实战项目场景实现
这篇文章是关于Spring Boot 2.x中拦截器的入门教程和实战项目场景实现的详细指南。
19 0
springboot学习七:Spring Boot2.x 拦截器基础入门&实战项目场景实现
|
28天前
|
Java API Spring
springboot学习六:Spring Boot2.x 过滤器基础入门&实战项目场景实现
这篇文章是关于Spring Boot 2.x中过滤器的基础知识和实战项目应用的教程。
21 0
springboot学习六:Spring Boot2.x 过滤器基础入门&实战项目场景实现
|
28天前
|
Java 关系型数据库 MySQL
springboot学习五:springboot整合Mybatis 连接 mysql数据库
这篇文章是关于如何使用Spring Boot整合MyBatis来连接MySQL数据库,并进行基本的增删改查操作的教程。
48 0
springboot学习五:springboot整合Mybatis 连接 mysql数据库
|
28天前
|
Java 关系型数据库 MySQL
springboot学习四:springboot链接mysql数据库,使用JdbcTemplate 操作mysql
这篇文章是关于如何使用Spring Boot框架通过JdbcTemplate操作MySQL数据库的教程。
20 0
springboot学习四:springboot链接mysql数据库,使用JdbcTemplate 操作mysql
|
28天前
|
Java 测试技术 Spring
springboot学习三:Spring Boot 配置文件语法、静态工具类读取配置文件、静态工具类读取配置文件
这篇文章介绍了Spring Boot中配置文件的语法、如何读取配置文件以及如何通过静态工具类读取配置文件。
41 0
springboot学习三:Spring Boot 配置文件语法、静态工具类读取配置文件、静态工具类读取配置文件
下一篇
无影云桌面