Spring框架
Spring 是什么?
- Spring 是一个开源的轻量级应用程序框架
- 提供一系列工具和库,用于简化企业级应用程序的开发
- Spring 框架的核心思想是通过依赖注入和面向切面编程来实现模块化设计
Spring 特性?
- 依赖注入 (DI):容器管理对象之间的依赖关系
- 面向切面编程 (AOP):将横跨多个模块的横切关注点,如日志、事务管理从主要业务逻辑分离
- 控制反转 (IoC):容器负责管理应用程序中的对象,对象的创建交给容器
- 面向接口编程:通过接口定义组件
- 灵活的数据访问:Spring 提供对不同数据访问技术的支持,如 JDBC、ORM 等
- 事务管理:Spring 提供声明式的事务管理
- 模块化:Spring 框架分为多个模块,可以根据需要选择性集成模块
Spring 模块
- Spring Core Container:包含核心容器的基本功能,如 BeanFactory 和 ApplicationContext,用于实现控制反转 IoC 和依赖注入 DI
- Spring AOP:提供面向切面编程的支持,如实现日志、事务等
- Spring Data Access:提供对不同数据访问技术的支持
- Spring Web:提供与 Web 相关的功能,如 Spring MVC 框架
- Spring Security:提供身份验证和授权的功能
- Spring Boot:用于简化 Spring 应用程序的搭建和部署,提供自动部署
- Spring Cloud:用于构建分布式系统的微服务架构
Spring 注解
- @Component:标记一个类为 Spring 组件,让 Spring 容器可以自动扫描并将其实例化为 Bean
- @Controller:标记一个类为 Spring MVC 控制器,处理 HTTP 请求并响应
- @RequestMapping:用于在 Spring MVC 控制器中映射 HTTP 请求
- @ResponseBody:用于将方法返回值直接作为 HTTP 响应体返回
- @Service:标记一个类为业务逻辑层的服务类
- @Repository:标记一个类为数据访问类的仓库类
- @Autowired:用于自动装配 Bean,通过类型匹配自动注入依赖
- @Value:用于注入属性值
- @Configuration:标记一个类为配置类
- @Transactional:用于声明式开启事务
Spring 缓存实现方式
缓存的实现方式 – 注解方式
Spring 注解缓存
Spring Cache 利用 Spring AOP 的动态代理技术,即当客户端尝试调用方法时,获取的是代理的引用
常用的三个注解标签
- @Cacheable
- @CachePut
- @CacheEvict
用户自定义注解缓存
@HotelCacheable、@HotelCacheEvict
Spring 的设计模式
- 单例模式:Spring 默认将 Bean 定义为单例,在应用程序的生命周期内,同一个 Bean 实例只会存在一个
- 工厂模式:Sping 使用工厂模式来创建和管理 Bean 实例
- 模版方法模式:Spring 的 Jdbc Template 等模版类实现了模版方法模式
- 代理模式:Spring AOP 的实现基于代理模式,Spring 可以使用动态代理在不改变原始代码类情况下,添加额外的横切关注点
- 观察者模式:Spring 的事件驱动机制基于观察者模式,应用程序中的事件可以触发监听器的响应
- 策略模式:Spring 的事务管理机制基于策略模式,允许选择不同的事务管理策略
什么是 IoC?
- IoC,控制反转,是一种设计原则
- 将对象的创建和依赖关系的管理交给容器处理
- 开发者只需要定义对象之间的依赖关系
什么是 DI?
- DI,依赖注入,是控制反转的一种具体实现方式
- 通过将对象的依赖关系注入到对象中,而不是在对象内部创建,实现解耦
Spring IoC 的实现机制吗?
Spring 的 控制反转 IoC 机制通过容器来实现
- 配置:使用配置文件或注解定义组件 Bean 的信息
- 加载:Spring 容器读取配置文件,根据信息创建对象并实例化
- 依赖注入:Spring 容器解析 Bean 定义中的依赖关系,将所需的依赖注入到对象
- 使用:从容器中获取已经创建和初始化的 Bean 实例
- 销毁:在 Bean 不需要时,Spring 容器会销毁 Bean 并清理
BeanFactory 和 ApplicantContext?
BeanFactory 是 Spring 容器的基本接口,提供基本的控制反转 IoC 功能
- Bean 实例化和管理
- 依赖注入
- 基本生命周期管理
ApplicationContext 是 BeanFactory 的扩展,提供更多的功能和特性,更为常用
- 国际化支持:可以根据不同的语言和地区加载对应的资源
- 自动装配:支持自动装配,根据注解或配置自动解析依赖
- AOP 支持:提供对面对切面编程的支持
- 消息机制:支持异步消息传递,可以发送和接收信息
Spring 容器启动阶段
- 加载配置:Spring 容器读取配置文件和注解
- 实例化 Bean 定义:容器解析配置文件,将 Bean 定义转换为内部数据结构
- 创建 Bean 实例:根据 Bean 定义的信息,实例化 Bean 对象
- 依赖注入:容器将依赖关系注入到 Bean 中
- Bean 初始化:在实例化和依赖注入后,容器会调用 Bean 的初始化方法进行初始化
- 预处理其他功能:容器可能会处理一些其他的功能,例如 AOP 代理的创建、事件的发布
- 容器就绪:容器完成所有的初始化步骤,可以提供 Bean 实例给应用程序
Bean 定义和依赖定义的方式?
- 配置文件
- 注解
依赖注入的方式?
- 构造方法注入
- Setter 注入
- 接口注入:在目标类实现接口,在接口中定义一个方法实现注入
- 自动装配:使用@Autowired 注解在字段或方法上进行自动装配
Spring 自动装配?
- by Type:根据类型自动匹配
- by Name:根据名称进行自动匹配
- by Constructor:根据构造函数自动装配
Spring 中 Bean 的作用域?
- Singleton(单例):在整个应用程序中,只创建一个 Bean 实例
- Prototype(原型): 每次请求获取 Bean 时,都会创建一个新的 Bean 实例
- Session(会话): 在每个用户会话中创建一个 Bean 实例,同一个用户的多次请求会共享同一个 Bean 实例
Spring 中的单例 Bean 会存在线程安全问题吗?
- 会,默认情况下,单例 Bean 是所有线程共享的
- 可以使用 synchronized 关键字或 ThreadLocal 等线程同步机制来保护共享状态
循环依赖?
- 应用程序中的一组对象之间存在相互依赖关系,形成闭环,对象不能正确的初始化
三级缓存?
- 单例对象缓存:Spring 容器最终存放已完全初始化的 Bean 实例的缓存
- 早期单例对象缓存:存放被提前暴露但尚未完全初始化的 Bean 实例
- 单例对象工厂缓存:存放用于早期 Bean 实例的工厂对象
解决循环依赖的过程
- 当 Spring 容器发现需要处理循环依赖的 Bean 时,会尝试从第一级缓存中查找是否已经有已经完全初始化的 Bean 实例
- 如果没有找到,会创建一个早期 Bean 实例,放入第二级缓存;
同时,创建一个工厂对象并放入第三级缓存 - Spring 继续初始化其他 Bean,如果发现依赖于早期 Bean 实例,Spring 会从第二级缓存中获取早期 Bean 实例,并将其注入
- 当循环依赖的 Bean 初始化完成后,将其放入第一级缓存,以便后续获取
为什么要三级缓存?⼆级不⾏吗?
- 二级缓存可以处理大部分的循环依赖情况,但不能解决通过构造函数注入的循环依赖问题
- 构造函数循环依赖可能导致递归创建 Bean 实例的问题,三级缓存可以有效地防止这种递归
@Autowired 的实现原理?
@Autowired 是 Spring 框架中用于依赖注入的注解
- Spring 容器扫描和注册标记有 Component 注解的类,将其创建成 Bean
- 当需要注入依赖时,Spring 会通过反射机制检查目标位置是否标记了@Autowired 注解
- 如果标记了,Spring 会在容器中寻找匹配的 Bean
- 找到 Bean 后,将其注入到目标位置
说说什么是 AOP?
- AOP,面向切面编程
- 将横切关注点,如日志、事务等从业务逻辑中分离出来,使代码更加清晰
- 可以通过 AOP 在方法调用前后添加日志记录、事务管理等通用功能,而不需要重复编写相同的代码
Spring 事务的种类?
- 编程式事务管理:通过编写代码来显式控制事务的开始、提交、回滚等操作
- 声明式事务管理:在配置文件或注解声明事务的属性,通过 Spring AOP 技术自动处理事务的操作
声明式事务在哪些情况下会失效?
- 内部方法调用
- 同类方法调用
- 非 public 方法
- 使用异步方法
Spring 的事务隔离级别?
- 默认:数据库本身的默认隔离级别
- 读未提交:事务可以读取到其他未提交事务的数据
- 读已提交:事务只能读取到已提交事务的数据
- 可重复读:保证在一个事务中多次读取同一数据时,数据一致
- 串行化:每个事务独立运行,不受到其他事务影响