北屋教程网

专注编程知识分享,从入门到精通的编程学习平台

1.大白话 Spring

此文是学习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);

控制面板
您好,欢迎到访网站!
  查看权限
网站分类
最新留言