此文是学习spring源码一些体会,记录下来,哪里有不对的地方,希望批评指正!
1.Spring是什么
Spring 是一款开源的轻量级 Java 开发框架,旨在提高开发人员的开发效率以及系统的可维护性。
Spring 框架指的都是 Spring Framework,它是很多模块的集合,使用这些模块可以很方便地协助我们进行开发,可以很方便地对数据库进行访问、可以很方便地集成第三方组件(电子邮件,任务,调度,缓存等等)、对单元测试支持比较好、支持 RESTful Java 应用程序的开发。
使用 Spring 进行开发各种配置过于麻烦比如开启某些 Spring 特性时,需要用 XML 或 Java 进行显式配置。于是,Spring Boot 诞生了。Spring Boot 旨在简化 Spring 开发(减少配置文件,开箱即用!)。Spring Boot 只是简化了配置,如果你需要构建 MVC 架构的 Web 程序,你还是需要使用 Spring MVC 作为 MVC 框架,只是说 Spring Boot 帮你简化了 Spring MVC 的很多配置,真正做到开箱即用!
Spring设计目标:Spring为开发者提供一个一站式轻量级应用开发平台;
Spring设计理念:在JavaEE开发中,支持POJO和JavaBean开发方式,使应用面向接口开发,充分支持OO(面向对象)设计方法;Spring通过IoC容器实现对象耦合关系的管理,并实现依赖反转,将对象之间的依赖关系交给IoC容器,实现解耦;
Spring框架的核心:IoC容器和AOP模块。通过IoC容器管理POJO对象以及他们之间的耦合关系;通过AOP以动态非侵入的方式增强服务。
Core Container
Spring 框架的核心模块,也可以说是基础模块,主要提供 IoC 依赖注入功能的支持。Spring 其他所有的功能基本都需要依赖于该模块,我们从上面那张 Spring 各个模块的依赖关系图就可以看出来。
- spring-core:Spring 框架基本的核心工具类。
- spring-beans:提供对 bean 的创建、配置和管理等功能的支持。
- spring-context:提供对国际化、事件传播、资源加载等功能的支持。
- spring-expression:提供对表达式语言(Spring Expression Language) SpEL 的支持,只依赖于 core 模块,不依赖于其他模块,可以单独使用。
AOP
- spring-aspects:该模块为与 AspectJ 的集成提供支持。
- spring-aop:提供了面向切面的编程实现。
- spring-instrument:提供了为 JVM 添加代理(agent)的功能。 具体来讲,它为 Tomcat 提供了一个织入代理,能够为 Tomcat 传递类文 件,就像这些文件是被类加载器加载的一样。没有理解也没关系,这个模块的使用场景非常有限。
Data Access/Integration
- spring-jdbc:提供了对数据库访问的抽象 JDBC。不同的数据库都有自己独立的 API 用于操作数据库,而 Java 程序只需要和 JDBC API 交互,这样就屏蔽了数据库的影响。
- spring-tx:提供对事务的支持。
- spring-orm: 提供对 Hibernate、JPA 、iBatis 等 ORM 框架的支持。
- spring-oxm:提供一个抽象层支撑 OXM(Object-to-XML-Mapping),例如:JAXB、Castor、XMLBeans、JiBX 和 XStream 等。
- spring-jms: 消息服务。自 Spring Framework 4.1 以后,它还提供了对 spring-messaging 模块的继承。
Spring Web
- spring-web:对 Web 功能的实现提供一些最基础的支持。
- spring-webmvc: 提供对 Spring MVC 的实现。
- spring-websocket: 提供了对 WebSocket 的支持,WebSocket 可以让客户端和服务端进行双向通信。
- spring-webflux:提供对 WebFlux 的支持。WebFlux 是 Spring Framework 5.0 中引入的新的响应式框架。与 Spring MVC 不同,它不需要 Servlet API,是完全异步。
Messaging
spring-messaging是从 Spring4.0 开始新加入的一个模块,主要职责是为 Spring 框架集成一些基础的报文传送应用。
Spring Test
Spring 团队提倡测试驱动开发(TDD)。有了控制反转 (IoC)的帮助,单元测试和集成测试变得更简单。
Spring 的测试模块对 JUnit(单元测试框架)、TestNG(类似 JUnit)、Mockito(主要用来 Mock 对象)、PowerMock(解决 Mockito 的问题比如无法模拟 final, static, private 方法)等等常用的测试框架支持的都比较好。
2.Bean执行流程图
3.核心组件
3.1.核心组件接口-BeanFactory
3.2.核心组件接口-Resource
3.3.核心组件接口-BeanDefinition
3.4.核心组件接口-ApplicationContext
3.5.核心组件接口-Aware
4.手写 spring
思路:绿色为扩展点
1、指定配置文件
2、解析配置文件,拿到扫描路径
3、初始化前做点什么
4、使用放射技术,利用无参构造器,创建对象
5、初始化后做点什么
6、实现 BeanNameAware、BeanPostProcessor、InitializingBean等回调接口
7、保存到集合对象中(Map)
8、使用对象(从集合中获取),调用方法执行业务逻辑
简化流程如下:
扩展流程如下:
手写代码:
https://gitee.com/zrbfree/rick-spring.git
5.Bean & 人
人的一生需要经过社会千百次锤炼,才能百炼成钢!
Bean需要经过Spring增强,才能更加牛逼!
1、Bean容器使用Java 反射API创建Bean的实例,孩子出生了。
2、Person声明了属性no、name,它们会被设置,相当于注册身份证号和姓名。如果属性本身是Bean,则将对其进行解析和设置。
3、Person类实现了BeanNameAware接口,通过传递Bean的名称来调用setBeanName()方法,相当于起个学名。
4、Person类实现了BeanFactoryAware接口,通过传递BeanFactory对象的实例来调用setBeanFactory()方法,就像是选了一个学校。
5、PersonBean实现了BeanPostProcessor接口,在初始化之前调用用
postProcessBeforeInitialization()方法,相当于入学报名。
6、PersonBean类实现了InitializingBean接口,在设置了配置文件中定义的所有Bean属性后,调用afterPropertiesSet()方法,就像是入学登记。
7、配置文件中的Bean定义包含init-method属性,该属性的值将解析为Person类中的方法名称,初始化的时候会调用这个方法,成长不是走个流程,还需要自己不断努力。
8、Bean Factory对象如果附加了Bean 后置处理器,就会调用
postProcessAfterInitialization()方法,毕业了,总得拿个证。
9、Person类实现了DisposableBean接口,则当Application不再需要Bean引用时,将调用destroy()方法,简单说,就是人挂了。
10、配置文件中的Person Bean定义包含destroy-method属性,所以会调用Person类中的相应方法定义,相当于选好地儿,埋了。
实例化:
第 1 步,实例化一个 Bean 对象
属性赋值:
第 2 步,为 Bean 设置相关属性和依赖
初始化:
初始化的阶段的步骤比较多,5、6步是真正的初始化,第 3、4 步为在初始化前执行,第 7 步在初始化后执行,初始化完成之后,Bean就可以被使用了
销毁:
第 8~10步,第8步其实也可以算到销毁阶段,但不是真正意义上的销毁,而是先在使用前注册了销毁的相关调用接口,为了后面第9、10步真正销毁 Bean 时再执行相应的方法
一:获取社会资源/Aware接口:Aware接口的作用是让Bean能拿到容器的一些资源,例如BeanNameAware可以拿到BeanName。就好像上学之前,要取一个学名——不知道多少人上学之前不知道自己大名叫什么,是吧?狗蛋吧。
二:必备各种手续和证/后处理器:在Bean的生命周期里,会有一些后处理器,它们的作用就是进行一些前置和后置的处理,就像上学之前,需要登记学籍,上学之后,会拿到毕业证。
三:个人选择/生命周期接口:人可能无法选择如何出生,但也许可以选择如何活着和如何死去,InitializingBean和DisposableBean 接口就是用来定义初始化方法和销毁方法的。
四:主观能动/配置生命周期方法:环境影响人,人也在影响环境,成长的时候认真努力,衰亡的时候也可以豁达乐观。可以通过配置文件,自定义初始化和销毁方法。
6.源码调试
源码12 大步骤方法
7.常见问题
7.1、循环依赖-三级缓存
容器对象:
DefaultSingletonBeanRegistry ---> singletonObjects,earlySingletonObjects,singletonFactories
循环依赖情况:spring只能解决单实例存在的循环依赖引用问题,如存在以下四种情况问题,需要人为干预才可以:
- 多实例的Setter注入导致的循环依赖,需要把Bean改成单例
- 构造器注入导致的循环依赖,可以通过@Lazy注解解决
- DependsOn导致的循环依赖,找到注解循环依赖的地方,迫使他不再循环依赖(代码架构设计)
- 单例的代理对象Setter注入导致的循环依赖:
- 可以使用@Lazy注解。
- 可以使用@DependsOn注解指定加载先后关系。
本质操作:把bean的是实例化和bean的属性赋值(依赖注入)进行分离,采用一级缓存存储完整的Bean实例,采用二级缓存存储不完整的Bean实例,通过不完成的Bean实例作为突破口,解决循环依赖问题。第三级缓存主要是解决代理对象的循环依赖问题
从系统设计角度去考虑模块间依赖关系,避免换循环依赖问题的产生!
// 一级缓存 完全被初始化好的Bean,可以直接拿来使用
private final Map<String, Object> singletonObjects = new ConcurrentHashMap<>(256);
// 二级缓存 原始的Bean对象,还没有进行赋值,没有做依赖注入
private final Map<String, Object> earlySingletonObjects = new HashMap<>(16);
// 三级缓存 Bean工厂对象,生成原始Bean对象,放入到二级缓存中
private final Map<String, ObjectFactory<?>> singletonFactories = new HashMap<>(16);