深入理解Spring:Spring
目录
1.1、什么是 Spring Framework
1.2、Spring的8类模块
1.3、Spring用到哪些设计模式
1.4、Spring异常处理机制
1.5、Spring自动装配
2、Spring循环依赖
2.1、什么是循环依赖,什么情况出现
2.2、如何解决循环依赖
2.2.1、Spring自己的三级缓存解决
2.2.2、为什么使用三级缓存而不是二级缓存
2.2.3、为什么不只使用一级缓存
2.2.4、@Lazy注解解决
3、Spring事物
3.1、什么是事物
3.2、Spring中事物的实现/管理方式
3.2、Spring中事物的隔离级别(5个)
3.3、Spring事物的传播机制/行为
1、Spring介绍
1.1、什么是 Spring Framework
就是一个框架,简称Spring。提供一系列功能和特性,例如依赖注入、控制反转、面向切面编程、事物管理、数据访问、MVC等。
1.2、Spring的8类模块
(1)核心模块(Spring Core):
- Spring Beans: 提供IOC和DI服务,其他模块都依赖它;
- Spring Core: 核心类库,所有功能都依赖该类库;
- Spring Context: 是BeanFactory的扩展,提供更多功能如国际化、资源管理
- SpEL:表达式语言,例如@、#、{}、AOP切面表达式、XML的<>等
(2)数据存储模块:Spring JDBC、ORM等
(3)Web模块:WebSocket、MVC等
(4)Spring AOP模块:面向切面编程
(5)Test测试模块:提供对单元测试、集成测试、端到端测试的支持
(6)Instrumentation模块:Java代理API,用于监控和管理JVM虚拟机上的应用程序
(7)Messaging模块:消息模块
(8)Aspects模块:Aspects提供更高级面向切面编程的框架,可以和其他模块集成
1.3、Spring用到哪些设计模式
-
工厂设计模式 : Spring使用工厂模式通过
BeanFactory
、ApplicationContext
创建 bean 对象。 -
代理设计模式 : Spring AOP 功能的实现。
-
单例设计模式 : Spring 中的 Bean 默认都是单例的。
-
模板方法模式 : Spring 中
jdbcTemplate
、hibernateTemplate
等以 Template 。 -
策略模式 : Resource资源获取实现类,针对不同的资源实现不同的资源获取策略,如UrlResource、ClassPathResource
-
适配器模式 :Spring MVC 中用到了适配器模式适配
Controller
。
1.4、Spring异常处理机制
主要集中在Spring MVC模块中,用于处理Web应用程序中的异常情况。 异常分为编译时异常和运行时异常,编译时异常我们 try-cache 进行捕获后自行处理,而运行时异常是不可预期的。
(1)全局异常处理器
(2)自定义异常处理
(3)@ExceptionHandler等注解捕获异常处理
1.5、Spring自动装配
参考: 深入理解Spring:Bean---4、bean自动装配几种方式
2、Spring循环依赖
2.1、什么是循环依赖,什么情况出现
类与类之间的依赖关系形成了闭环。循环依赖问题在Spring中有以下三种情况:
(1)通过构造方法注入时产生循环依赖;
(2)通过Setter方法注入且是 多例 模式下产生循环依赖;
(3)通过Setter方法注入且是单例模式下产生循环依赖---已解决(只有这种被解决了)
其他2种都会异常,因为:
第一种在new对象的时候会堵塞住;例如Bean A-->Bean B -->Bean C Spring先创建C,接着创建B(将C注入B),最后创建A(将B注入A),当存在循环依赖时Spring无法决定先创建哪个Bean,就会报错。该方式经常发生循环依赖。
第二种每一次在getBean()的时候都会产生一个新的Bean,如此反复下去就会有无数个Bean产生,最终导致OOM;
2.2、如何解决循环依赖
2.2.1、Spring自己的三级缓存解决
通过二级缓存和三级缓存解决,三级缓存是重点。核心思想是在对象实例化之后,依赖注入之前,Spring提前暴露 Bean实例的引用也就是代理对象 在第三集缓存中进行存储。
2.2.2、为什么使用三级缓存而不是二级缓存
- 一级缓存(singletonObjects)存放已经创建并初始化完的Bean实例;
- 二级缓存(earlySingletonObjects)存放已经创建但未初始化的Bean实例;
- 三级缓存(singletonFactories)存放用于创建Bean的代理对象ObjectFactory,该缓存只对内使用,Spring框架内部逻辑使用该缓存。
当循环依赖存在时,两个Bean都存在二级缓存中等待对方创建完成,将导致死锁的发生。三级缓存允许在循环依赖时暂时存储已经创建但未初始化的Bean实例,并且通过ObjectFactory代理对象工厂来延迟创建Bean的实例,这样可以避免二级缓存的死锁问题。
触发解决循环依赖时Spring从三级缓存获取代理对象ObjectFactory并使用他创建Bean实例,提前暴露Bean对象的引用(实例化之后,依赖注入之前),然后将该实例放入以及缓存中,并最终初始化完成
(三个缓存是彼此互斥的,一个Bean只会存在一个地方,读取顺序为一、二、三)
2.2.3、为什么不只使用一级缓存
一级缓存设置存放创建和初始化完整的Bean对象,如果存在完整和不完整的则会丢失存储,违反了设计原则
2.2.4、@Lazy注解解决
主要解决构造函数相互注入的循环依赖。前面的是Spring自动解决单例模式下Settter()方法注入的循环依赖,而构造方法造成的无法自动解决。
使用方法:A类和B类都是通过构造器注入的,可在A或B构造函数形参加@Lazy注解实现延迟加载
实现原理:当实例化对象时发现参数或者属性有@Lazy注解修饰,就不直接创建所依赖的对象了而是用动态代理创建一个代理类,这样就不是直接依赖而是依赖代理类了(例如A a=new A(B))。
3、Spring事物
3.1、什么是事物
Spring事物其实就是数据库的事物,Spring自己没事物,它只提供统一事物管理接口,具体事物由不同数据库自己实现,redo log: 数据库事物提交、undo log:数据库事物回滚。是一组操作要么全部完成要么全部不完成
3.2、Spring中事物的实现/管理方式
(1)编程式事物:在代码中硬编码(不推荐使用);
(2)声明式事物:在配置文件中配置(推荐使用,建立在AOP之上)——分为两种
- 基于XML的声明式事物;
- 基于注解(@Transactiona)的声明式事物。
(本质是通过AOP对方法前后进行拦截,将事物处理功能编织到拦截方法中,在目标方法之前启动一个事物,在执行完目标方法之后根据执行情况提交或者回滚事物)
3.2、Spring中事物的隔离级别(5个)
- 默认;
- 最低隔离级别(脏读、幻读、不可重复读)——读取未提;
- Oracle默认(幻读、不可重复读)——读取已提交;
- MySQL默认——可重复读(幻读);
- 最高隔离级别——可串行化
3.3、Spring事物的传播机制/行为
定义了在一个事务方法调用另一个事务方法时,新方法如何参与现有事务的规则。
这些传播行为可以通过 @Transactional 注解的属性来指定:
(1)required(默认):如果当前存在事务,则加入该事务,如果没有事务则新建一个事务
(2)required_new:无论当前是否存在事务,都会开启一个新的事务,如果已存在事务则将当前事务挂起。
(3)supports:如果当前存在事务,则加入该事务,如果没有事务则以非事务的方式执行
(4)no_supported:以非事务的方式执行操作,如果当前存在事务,则将其挂起
(5)never:要求当前不存在事务,如果存在则抛出异常
参考资料:《Spring技术内幕》
CSDN-Ada助手: 哇, 你的文章质量真不错,值得学习!不过这么高质量的文章, 还值得进一步提升, 以下的改进点你可以参考下: (1)使用更多的站内链接;(2)增加除了各种控件外,文章正文的字数;(3)提升标题与正文的相关性。
CSDN-Ada助手: TCP/IP 是什么协议?它的作用是什么?
CSDN-Ada助手: 哇, 你的文章质量真不错,值得学习!不过这么高质量的文章, 还值得进一步提升, 以下的改进点你可以参考下: (1)提升标题与正文的相关性;(2)使用更多的站内链接;(3)增加除了各种控件外,文章正文的字数。
CSDN-Ada助手: 哇, 你的文章质量真不错,值得学习!不过这么高质量的文章, 还值得进一步提升, 以下的改进点你可以参考下: (1)提升标题与正文的相关性;(2)使用更多的站内链接。
CSDN-Ada助手: Spark SQL 和 Hive 的比较,它们各自的优点和适用场景是什么?