当前位置: 首页 > news >正文

常用框架知识

Spring

Spring IOC

IoC(Inversion of Control:控制反转) 是一种设计思想,而不是一个具体的技术实现。IoC 的思想就是将原本在程序中手动创建对象的控制权,交由 Spring 框架来管理。

为什么叫控制反转?

  • 控制:指的是对象创建(实例化、管理)的权力
  • 反转:控制权交给外部环境(Spring 框架、IoC 容器)

@Autowired和@Resource的区别

  • @Autowired 是 Spring 提供的注解,@Resource 是 JDK 提供的注解。
  • Autowired 默认的注入方式为byType(根据类型进行匹配),@Resource默认注入方式为 byName(根据名称进行匹配)。
  • 当一个接口存在多个实现类的情况下,@Autowired@Resource都需要通过名称才能正确匹配到对应的 Bean。Autowired 可以通过 @Qualifier 注解来显式指定名称,@Resource可以通过 name 属性来显式指定名称。
  • @Autowired 支持在构造函数、方法、字段和参数上使用。@Resource 主要用于字段和方法上的注入,不支持在构造函数或参数上使用。

注入Bean的方式

  • 属性注入​​:@Autowired注解直接注入字段(最常用,但易忽视依赖可见性)。
  • ​Setter注入​​:通过Setter方法赋值(灵活性高,支持可选依赖)。
  • ​构造器注入​​:通过构造函数赋值(推荐,保证依赖不可变且避免空指针,lombok中使用@RequiredArgsConstructor 注解实现,属性添加final声明

Bean的作用域

  • singleton : IoC 容器中只有唯一的 bean 实例。Spring 中的 bean 默认都是单例的,是对单例设计模式的应用。
  • prototype : 每次获取都会创建一个新的 bean 实例。也就是说,连续 getBean() 两次,得到的是不同的 Bean 实例。
  • request (仅 Web 应用可用): 每一次 HTTP 请求都会产生一个新的 bean(请求 bean),该 bean 仅在当前 HTTP request 内有效。
  • session (仅 Web 应用可用) : 每一次来自新 session 的 HTTP 请求都会产生一个新的 bean(会话 bean),该 bean 仅在当前 HTTP session 内有效。
  • application/global-session (仅 Web 应用可用):每个 Web 应用在启动时创建一个 Bean(应用 Bean),该 bean 仅在当前应用启动时间内有效。
  • websocket (仅 Web 应用可用):每一次 WebSocket 会话产生一个新的 bean。

Bean是线程安全的吗

Spring Bean 的线程安全性​​取决于其作用域(Scope)和内部状态设计​

​单例 Bean(Singleton,默认作用域)
  •  非线程安全​​:所有线程共享同一实例,若包含​​可变成员变量​​(如计数器、缓存对象),多线程并发修改会导致数据竞争
@Service
public class CounterService {private int count = 0; // 共享状态,线程不安全public void increment() { count++; }
}
  • 线程安全场景​​:​​无状态 Bean​​(无成员变量或仅含不可变对象)
// 定义了一个用户服务,它仅包含业务逻辑而不保存任何状态。
@Component
public class UserService {public User findUserById(Long id) {//...}//...
}
​原型 Bean(Prototype)
  •  通常线程安全​​:每次请求创建新实例,普通成员变量​​线程隔离
  • 例外情况​​:若包含​​静态变量​​,仍会共享导致不安全

解决线程安全问题的方案​

  1. 避免可变成员变量: 尽量设计 Bean 为无状态。
  2. 使用ThreadLocal: 将可变成员变量保存在 ThreadLocal 中,确保线程独立。
  3. 使用同步机制: 利用 synchronizedReentrantLock 来进行同步控制,确保线程安全

Bean的生命周期

Spring Bean的生命周期4个阶段

  1. 通过反射实例化对象
  2. 通过PopulationBean方法进行属性赋值
  3. 初始化
  4. 销毁

1. 创建 Bean 的实例:Bean 容器首先会找到配置文件中的 Bean 定义(XML/注解/Java Config),然后使用 Java 反射 API来创建Bean 的实例。

2. Bean 属性赋值/填充:通过Setter字段注入@Autowired)或构造器注入填充属性,解析@Value注入配置值。

3. Bean 初始化:

  • Aware接口回调​​:注入容器基础设施信息。
    • BeanNameAware → BeanFactoryAware → ApplicationContextAware(顺序固定)。
  • ​初始化方法执行​​(按顺序调用):
    1. @PostConstruct​(JSR-250注解)
    2. InitializingBean.afterPropertiesSet()
    3. ​自定义init-method​(XML或@Bean(initMethod))。
  • ​BeanPostProcessor增强​​:
    • ​前置处理​​(postProcessBeforeInitialization):如@PostConstruct的解析。
    • ​后置处理​​(postProcessAfterInitialization):如AOP代理对象的生成(AbstractAutoProxyCreator)。

4.销毁 Bean:销毁并不是说要立马把 Bean 给销毁掉,而是把 Bean 的销毁方法先记录下来,将来需要销毁 Bean 或者销毁容器的时候,就调用这些方法去释放 Bean 所持有的资源。

  • 如果 Bean 实现了 DisposableBean 接口,执行 destroy() 方法。
  • 如果 Bean 在配置文件中的定义包含 destroy-method 属性,执行指定的 Bean 销毁方法。或者,也可以直接通过@PreDestroy 注解标记 Bean 销毁之前执行的方法。

Spring如何解决循环依赖

spring靠三级缓存解决循环依赖问题。

Bean的生命周期是:实例化 -> 属性赋值 -> 初始化 -> 销毁。循环依赖发生在属性赋值阶段。

  • 一级缓存Map<String, Object> singletonObjects,成品对象单例池,用于保存实例化、属性赋值(注入)、初始化完成的 bean 实例。

  • 二级缓存Map<String, Object> earlySingletonObjects,早期曝光对象,用于保存实例化完成的 bean 实例。

  • 三级缓存Map<String, ObjectFactory<?>> singletonFactories,早期曝光对象工厂,用于保存 bean 创建工厂,以便于后面扩展有机会创建代理对象。

解决循环依赖过程

1. ​​创建 Bean A​

  • 实例化 A(调用构造器) → 将 A 的 ObjectFactory 存入三级缓存(singletonFactories)。

​​2. 填充 A 的属性时发现依赖 B​

  • 触发创建 Bean B → 实例化 B → 将 B 的 ObjectFactory 存入三级缓存。

3. ​​填充 B 的属性时发现依赖 A​

  • 从一级缓存查找 A(未找到)→ 从二级缓存查找(未找到)→ ​​从三级缓存获取 A 的 ObjectFactory​ → 生成 A 的早期引用 → 将 A 的引用存入二级缓存(earlySingletonObjects)→ 注入 B。

4. ​​完成 B 的初始化​

  • B 完成属性填充和初始化 → 将 B 放入一级缓存(singletonObjects)→ 删除二/三级缓存中的 B。

5. ​​完成 A 的初始化​

  • A 获取完整的 B 引用 → A 完成属性填充和初始化 → 将 A 放入一级缓存 → 删除二/三级缓存中的 A。

只用两级缓存够吗? 在没有 AOP 的情况下,确实可以只使用一级和二级缓存来解决循环依赖问题。但是,当涉及到 AOP 时,三级缓存就显得非常重要了,因为它确保了即使在 Bean 的创建过程中有多次对早期引用的请求,也始终只返回同一个代理对象,从而避免了同一个 Bean 有多个代理对象的问题。(如果没有三级缓存,那么二级缓存存的是)

在 Spring 的三级缓存机制中,​​缓存存储的对象类型与代理层级无关​​。以下以 Proxy3 → Proxy2 → Proxy1 → 原始对象 的多级代理链为例,结合三级缓存的作用分析存储内容:

  • 三级缓存:​​只会存储原始对象的 ObjectFactory 工厂​​(与代理层级无关)
  • 二级缓存:​首次从三级缓存生成的早期引用​​(即 Proxy1),而非每个层级的代理对象
    • 存储的是 ​​半成品 Bean​​(可能为原始对象或单层代理),而非完整代理链。
    • 对于多级代理链,​​二级缓存仅存 Proxy1​,后续代理层级(如 Proxy2/Proxy3)尚未生成
  • 一级缓存:​完整代理链的顶层代理对象​​(即 Proxy3),而非所有代理层级或原始对象

    •  Bean 初始化完成后(@PostConstruct 执行完毕),通过 BeanPostProcessor 生成剩余代理层级,最终形成 Proxy3 并存入一级缓存。

FactoryBean和BeanFactory区别

BeanFactory​

Spring 的 ​​IoC 容器根接口​​,管理所有 Bean 的生命周期(创建、依赖注入、销毁)

FactoryBean

一个​​特殊的 Bean 接口​​,本身是一个 Bean,但生产另一个对象,用于封装复杂对象的创建逻辑,例如:

  • MyBatis 的 SqlSessionFactoryBean实现了FactoryBean<SqlSessionFactory>
  • Spring AOP 的 ProxyFactoryBean

Spring AOP

Spring AOP 就是基于动态代理的,如果要代理的对象,实现了某个接口,那么 Spring AOP 会使用 JDK Proxy,去创建代理对象,而对于没有实现接口的对象,就无法使用 JDK Proxy 去进行代理了,这时候 Spring AOP 会使用 Cglib 生成一个被代理对象的子类来作为代理。

Aop通知顺序

正常流程:

@Around开始 → @Before → 目标方法 → @AfterReturning → @After → @Around结束

异常流程:

@Around始 → @Before → 目标方法 → @AfterThrowing → @After → @Around终

​Spring 版本差异​​:

  • ​Spring 4​​:@After 在 @AfterReturning 之前执行(现已过时)。
  • ​Spring 5.2.7+​​:调整为 @AfterReturning → @After(正常流程)或 @AfterThrowing → @After(异常流程)

Aop通知类型

  • Before(前置通知):目标对象的方法调用之前触发
  • After (后置通知):目标对象的方法调用之后触发
  • AfterReturning(返回通知):目标对象的方法调用完成,在返回结果值之后触发
  • AfterThrowing(异常通知):目标对象的方法运行中抛出 / 触发异常后触发。AfterReturning 和 AfterThrowing 两者互斥。如果方法调用成功无异常,则会有返回值;如果方法抛出了异常,则不会有返回值。
  • Around (环绕通知):编程式控制目标对象的方法调用。环绕通知是所有通知类型中可操作范围最大的一种,因为它可以直接拿到目标对象,以及要执行的方法,所以环绕通知可以任意的在目标对象的方法调用前后搞事,甚至不调用目标对象的方法

Spring MVC工作流程

核心组件

  • DispatcherServlet核心的中央处理器,负责接收请求、分发,并给予客户端响应。
  • HandlerMapping处理器映射器,根据 URL 去匹配查找能处理的 Handler ,并会将请求涉及到的拦截器和 Handler 一起封装。
  • HandlerAdapter处理器适配器,根据 HandlerMapping 找到的 Handler ,适配执行对应的 Handler
  • Handler请求处理器,处理实际请求的处理器。
  • ViewResolver视图解析器,根据 Handler 返回的逻辑视图 / 视图,解析并渲染真正的视图,并传递给 DispatcherServlet 响应客户端

视图阶段(JSP)流程

前后端分离阶段流程

Spring事务

Spring支持两种事务管理方式:

  • 编程式事务:在代码中硬编码(在分布式系统中推荐使用) : 通过 TransactionTemplate或者 TransactionManager 手动管理事务,事务范围过大会出现事务未提交导致超时,因此事务要比锁的粒度更小。
  • 声明式事务:在 XML 配置文件中配置或者直接基于注解(单体应用或者简单业务系统推荐使用) : 实际是通过 AOP 实现(基于@Transactional 的全注解方式使用最多)

事务的传播行为

REQUIRED(默认)​
  • ​特点​​:若当前存在事务则加入,否则创建新事务。
  • ​场景​​:常规业务方法(如订单创建),保证多个操作原子性。
  • ​注意​​:嵌套方法异常会导致整个事务回滚。
​SUPPORTS​
  • ​特点​​:当前有事务则加入,没有则以非事务方式执行。
  • ​场景​​:查询操作(如数据查询),可兼容事务但无需强制。

​MANDATORY​

  • ​特点​​:强制要求当前必须存在事务,否则抛出异常。
  • ​场景​​:核心业务(如支付验证),确保方法在事务中执行。
​REQUIRES_NEW​
  • ​特点​​:无论当前有无事务,都创建独立新事务;若存在事务则挂起。
  • ​场景​​:日志记录、审计等需独立提交的操作。
  • ​注意​​:新事务与父事务完全隔离,互不影响提交/回滚。
​NOT_SUPPORTED​
  • ​特点​​:强制非事务执行,若当前存在事务则挂起。
  • ​场景​​:耗时操作(如大数据统计),避免事务开销。
​NEVER​
  • ​特点​​:必须在非事务环境中执行,否则抛出异常。
  • ​场景​​:严格非事务场景(如只读缓存更新)。
​NESTED​
  • ​特点​​:
    • 当前有事务时,创建嵌套子事务(基于保存点机制)。
    • 子事务回滚不影响父事务,父事务回滚则子事务必然回滚。
  • ​场景​​:部分操作需独立回滚(如订单创建成功但库存扣减失败)。
  • ​依赖​​:需数据库支持保存点(如MySQL的InnoDB引擎)。

事务的隔离级别

  • TransactionDefinition.ISOLATION_DEFAULT使用后端数据库默认的隔离级别,MySQL 默认采用的 REPEATABLE_READ 隔离级别 Oracle 默认采用的 READ_COMMITTED 隔离级别.
  • TransactionDefinition.ISOLATION_READ_UNCOMMITTED : 最低的隔离级别,使用这个隔离级别很少,因为它允许读取尚未提交的数据变更,可能会导致脏读、幻读或不可重复读
  • TransactionDefinition.ISOLATION_READ_COMMITTED : 允许读取并发事务已经提交的数据,可以阻止脏读,但是幻读或不可重复读仍有可能发生
  • TransactionDefinition.ISOLATION_REPEATABLE_READ : 对同一字段的多次读取结果都是一致的,除非数据是被本身事务自己所修改,可以阻止脏读和不可重复读,但幻读仍有可能发生。
  • TransactionDefinition.ISOLATION_SERIALIZABLE : 最高的隔离级别,完全服从 ACID 的隔离级别。所有的事务依次逐个执行,这样事务之间就完全不可能产生干扰,也就是说,该级别可以防止脏读、不可重复读以及幻读。但是这将严重影响程序的性能。通常情况下也不会用到该级别。

事务失效的原因

1. 非public方法:Spring AOP默认只代理public方法,@Transactional标注在private/protected方法上无效。

​2. 自调用问题(同类内部调用):同一个类中,非事务方法A直接调用事务方法B时,不经过Spring代理(AOP基于动态代理),事务失效。

解决方法:

  • 注入自身代理对象:@Autowired private UserService selfProxy; 调用 selfProxy.methodB()
  • 使用AOP工具((UserService)AopContext.currentProxy()).methodB()(需开启@EnableAspectJAutoProxy(exposeProxy=true))。
  • 拆分方法到不同类中

3. 异常类型不匹配:默认仅对RuntimeExceptionError回滚。需指定回滚异常:@Transactional(rollbackFor = Exception.class)

4.异常被捕获未抛出:try-catch捕获异常后未重新抛出,事务拦截器无法触发回滚。

5.数据库底层需要支持事务

Spring中的设计模式

一、创建型模式​

  1. ​单例模式(Singleton):​​Spring容器默认以单例模式管理Bean(如@Service@Component),确保每个Bean定义仅有一个实例,节省资源并提高性能。

  2. ​工厂模式(Factory)​​:BeanFactoryApplicationContext作为核心工厂接口,负责Bean的创建、配置和管理,解耦对象实例化过程。

  3. ​原型模式(Prototype)​​:通过@Scope("prototype")声明原型作用域的Bean,每次请求时创建新实例,适用于需要状态隔离的场景。

​二、结构型模式​

  1. ​代理模式(Proxy)​​:Spring AOP的核心实现,通过JDK动态代理(接口)或CGLIB(类)生成代理对象,实现日志、事务等横切逻辑。

  2. ​适配器模式(Adapter)​:

    • ​Spring MVC​​:HandlerAdapter适配多种控制器(如@ControllerHttpRequestHandler)。

    • ​AOP​​:适配不同通知类型(如MethodBeforeAdviceAdapter)。

  3. ​装饰器模式(Decorator)​​:BeanPostProcessor在Bean初始化前后动态增强功能(如缓存、监控),不修改原始类代码。

  4. ​门面模式(Facade)​​:JdbcTemplate封装复杂数据库操作(连接管理、异常处理),提供简洁API。

三、行为型模式​

  1. ​模板方法模式(Template Method):​JdbcTemplateRestTemplate等定义算法骨架(如事务流程),子类仅需实现特定步骤(如SQL执行)。

  2. ​观察者模式(Observer)​​:事件驱动模型(ApplicationEventPublisher发布事件,ApplicationListener监听响应),实现组件间松耦合通信。

  3. ​策略模式(Strategy)​:

    • ​视图解析​​:ViewResolver根据请求类型(JSP、Thymeleaf)选择不同实现。

    • ​事务管理​​:支持JDBC、JTA等多种事务策略。

  4. ​责任链模式(Chain of Responsibility)​​:Spring Security的过滤器链(FilterChain)和Spring MVC的拦截器(HandlerInterceptor),按顺序处理请求。


Spring Boot

Spring Boot 约定大约配置怎么理解

约定的内容及作用

  1. 约定项目结构和命名规范

    • Spring Boot鼓励开发者使用一致的项目结构,避免手动配置Spring组件扫描路径。例如,@SpringBootApplication注解默认会扫描同级包及子包中的组件。
    • 配置文件只需用application.yml格式即可自动加载;使用application-环境.yml时,它会根据环境判断是否加载,省去了XML配置。
  2. 自动配置

    • 根据项目的依赖、类路径等条件,Spring Boot能自动配置各种组件。如默认使用SLF4J并集成logback作为日志实现,若需其他日志框架则需排除此包并引入新包。
    • 引入spring-boot-starter-web包后,程序会自动识别为servlet项目并创建servlet容器;引入数据库依赖时,会自动配置数据源、事务管理器等组件。自动装配是这一思想的体现。
  3. Starter

    • starter约定了spring.factories配置中需要注册的类,使我们快速整合组件到Spring中。Spring Boot提供了许多现成的starter,只需引入相应依赖即可生效。
    • 许多组件还附带了配置类(如MultipartProperties),其中包含默认值(如最大上传文件大小为1M),仅在需要修改时才需配置。

Spring Boot自动装配原理

核心机制,三个注解组成

大概可以把 @SpringBootApplication看作是 @Configuration@EnableAutoConfiguration@ComponentScan 注解的集合。根据 SpringBoot 官网,这三个注解的作用分别是:

  • @EnableAutoConfiguration:启用 SpringBoot 的自动配置机制
  • @Configuration:允许在上下文中注册额外的 bean 或导入其他配置类
  • @ComponentScan:扫描被@Component (@Service,@Controller)注解的 bean,注解默认会扫描启动类所在的包下所有的类 ,可以自定义不扫描某些 bean。

@EnableAutoConfiguration 是实现自动装配的重要注解

自动装配流程

1.加载自动配置类

  1. @EnableAutoConfiguration​ 通过@Import导入​AutoConfigurationImportSelector​类。
  2. 该类调用SpringFactoriesLoader.loadFactoryNames()扫描所有META-INF/spring.factories文件,加载其中声明的自动配置类(如org.springframework.boot.autoconfigure.web.servlet.WebMvcAutoConfiguration

2.​​条件化筛选配置类​

自动配置类使用​​条件注解​​动态决定是否生效,例如:

  • @ConditionalOnClass​:类路径存在指定类时生效(如存在DataSource才加载数据库配置)。
  • @ConditionalOnMissingBean​:容器中无指定Bean时生效(避免重复覆盖用户自定义Bean)。
  • @ConditionalOnProperty​:配置文件属性匹配时生效(如spring.datasource.url存在)

3.注册Bean与属性绑定​

1.通过​@Configuration​类中的@Bean方法向容器注册Bean

​2.属性绑定​​:配置类结合@EnableConfigurationProperties加载XxxProperties类,将application.properties中的属性(如server.port)注入到Bean中


如何实现一个Starter

  1. ​创建 Maven 项目​,例如

  2. ​配置 pom.xml,引入Spring Boot相关依赖

  3. 定义配置属性类​

  4. 实现核心服务类​

  5. 创建自动配置类​​,使用@Conditional等条件注解控制 Bean 加载

  6. ​注册自动配置,在项目的resource目录下添加 META-INF/spring.factories文件

    org.springframework.boot.autoconfigure.EnableAutoConfiguration=com.example.config.DemoAutoConfiguration

如何实现全局异常管理

Spring Boot 应用程序可以借助 @RestcontrollerAdvice和 @ExceptionHandler 实现全局统一异
常处理。

    http://www.dtcms.com/a/289054.html

    相关文章:

  • 基于单片机的温湿度报警系统设计与实现
  • 神经网络:池化层
  • 数字图像处理(四:图像如果当作矩阵,那加减乘除处理了矩阵,那图像咋变):从LED冬奥会、奥运会及春晚等等大屏,到手机小屏,快来挖一挖里面都有什么
  • 41.FeignClient整合Sentinel
  • 7-20 关于mysql
  • C#.NET EFCore.BulkExtensions 扩展详解
  • 【机器学习工具】Weights Biases
  • C++string类用法
  • gradle微服务依赖模版
  • OpenTelemetry学习笔记(九):Elastic 对 OTLP 的原生支持
  • 【成品设计】基于STM32的宠物检测系统
  • 状态管理与团队协作 - SRE 的核心关切
  • Flink2.0学习笔记:Table API SQL
  • Ubuntu 24.04 设置静态 IP 的方法
  • XILINX JESD204B/C IP的AXI配置
  • leetCode——1492. n的第k个因子
  • ps2025下载与安装教程(附安装包) 2025最新版photoshop安装教程
  • 进阶向:基于Python的局域网文件传输工具
  • 初识软件测试
  • Redis 详解:从入门到进阶
  • Hiredis 构建 Redis 命令实战指南
  • 基于pi/4-QPSK扩频解扩和gardner环定时同步的通信系统matlab性能仿真
  • 绝对定位 vs 浮动:CSS布局核心差异解析
  • Spring 源码阅读(二) 核心概念解析 ApplicationContext、类型转化
  • 企业安全防护:堡垒机技术解析
  • 数据结构与算法汇总
  • spring-cloud使用
  • 再谈文件-ext2文件系统
  • NISP-PTE基础实操——XSS
  • PPT科研画图插件