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

Spring 学习笔记

1.Spring AOP 怎么实现的

AOP 即面向切面编程,是通过代理实现的,主要分为静态代理和动态代理,静态代理就是在程序运行前就已经指定并声明了代理类和增强逻辑,运行时就已经被编译为字节码文件了,而动态代理则是在运行过程中,动态生成代理类增强目标类,主要分为 JDK 和 CGLIB 动态代理,一般在项目中多采用注解方式声明切面,切点以及连接点,Spring 会自动扫描切面,通过切点寻找需要代理增强的类,pring 会根据目标 Bean 的类型来选择代理方式:

  • 如果目标类实现了接口,Spring 默认采用 JDK 动态代理,生成实现接口的代理类;
  • 如果目标类未实现任何接口,或设置了 proxyTargetClass = true,则使用 CGLIB 动态代理,生成目标类的子类进行方法增强;
  • CGLIB 是通过继承并重写目标类中非 final 的方法,在子类中织入增强逻辑并调用父类方法完成的。

2.Spring的两大核心是什么?谈一谈你对IOC的理解? 谈一谈你对DI的理解?

Spring 的两大核心是控制反转(IOC)和面向切面编程(AOP),IOC 的目的是将 Bean 的生命周期管理从程序员手中交由 Spring 管理,传统开发都需要程序员 new 对象并管理对象,IOC 则只需要声明依赖,使程序员专注于业务逻辑的实现,DI 依赖注入则是 IOC 控制反转的具体实现,Bean 交由 Spring 容器管理后,就需要在程序员调用的时候注入进来。

IOC 的一般实现方法有 XML 配置和注解配置,注解配置主要是通过 Component, Service,Bean,Controller,Confuguration 等注解;

DI 的一般实现方法有构造器注入,Setter 注入以及字段注入;

3.Spring 的生命周期?

Spring 的生命周期指的是 Spring 容器从创建、初始化 Bean、管理 Bean 到销毁 Bean 的整个过程。这个过程贯穿了从启动到关闭整个应用的生命周期。

阶段

说明

1. 实例化

通过构造方法或反射创建 Bean 对象

2. 依赖注入(DI)

Spring 根据配置注入属性值(@Autowired、@Value、@Resource)

3. 执行 Aware 接口回调

如 BeanNameAware、ApplicationContextAware 获取容器信息

4. BeanPostProcessor(前置)

调用 postProcessBeforeInitialization()

方法

5. 初始化

- @PostConstruct

方法执行 - 实现 InitializingBean.afterPropertiesSet()

- 配置的 init-method

执行

6. BeanPostProcessor(后置)

调用 postProcessAfterInitialization()

方法

7. Bean 使用阶段

Bean 进入工作状态,参与项目逻辑处理

8. 销毁前处理

- @PreDestroy

方法执行 - 实现 DisposableBean.destroy()

- 配置的 destroy-method

执行

9. Bean 被销毁

Spring 容器关闭,释放资源

4.Spring 支持 bean 的作用域有几种吗? 每种作用域是什么样的?

Bean 的作用域有单例,原型,request,session,globalSession 五种;

单例是默认作用域,在整个程序生命周期内有且仅有一个实例;

原型作用域则是每次注入或调用 getBean() 都会返回一个新对象;

request 作用域则是在单个请求内有且仅有一个实例 Bean,不同请求中的实例不同;

session 作用域则是在同一个 session 内有且仅有一个实例 Bean,session 关闭后所有 session 作用域的 Bean 销毁;

application 则是一个 ServletContext 对应一个 Bean,整个 Web 应用共享一个实例。

@Component
@Scope("prototype") // 也可以是 singleton, request, session 等
public class MyBean {...
}

5.Spring 事务的实现方式和实现原理

Spring 事务可以通过注解 Transactional 来实现,Spring 事务的实现主要依赖于底层数据库的事务

Spring 事务有两种实现方式:

    1. 编程式事务管理(使用 TransactionTemplate
    2. 声明式事务管理(使用 @Transactional 注解)——最常用

Spring 声明式事务的核心原理是:基于 AOP(面向切面编程)实现方法级别的事务增强。其底层实现包括以下几个关键点:

    1. 代理机制
      Spring 会为标注了 @Transactional 的类或方法创建代理对象:
      • 如果类实现了接口,使用 JDK 动态代理
      • 如果没有实现接口,使用 CGLIB 动态代理
    1. 事务拦截器(TransactionInterceptor)
      拦截器会拦截所有事务方法,在方法执行前后插入统一事务逻辑:
      • 获取事务属性(事务传播、隔离级别、是否只读等);
      • 调用事务管理器(PlatformTransactionManager)开启、提交或回滚事务。
    1. 事务管理器(TransactionManager)
      Spring 并不直接操作数据库事务,而是通过事务管理器统一封装底层操作。常用管理器包括:
      • DataSourceTransactionManager(JDBC/MyBatis)
      • JpaTransactionManager(JPA/Hibernate)
    1. 数据库事务控制
      Spring 的事务最终会调用底层连接(Connection)来控制事务,例如:
java复制代码
conn.setAutoCommit(false); // 开启事务
conn.commit();             // 提交事务
conn.rollback();           // 回滚事务

Spring 的声明式事务是基于 AOP 实现的,它通过为 @Transactional 方法创建代理对象,在方法调用前后统一管理事务。其核心是 TransactionInterceptor 拦截器,它依赖 PlatformTransactionManager 与底层数据库事务交互,最终通过 JDBC 的事务操作实现提交与回滚。这样程序员只需要添加注解即可实现完整的事务控制,极大地简化了开发流程。

6.Spring 框架中都用到了哪些设计模式?

提到 Spring 框架中的设计模式,必不可少的就是其两大核心性质,IOC 和 AOP,IOC 则是通过 Spring 容器管理 Bean,就是使用了工厂方法进行 Bean 的依赖注入,以及 Bean 默认都是单例的,所以采用了单例模式;而 AOP 就是采用了代理模式实现目标类的代理增强;

以及 JDBCTemplate,RedisTemplate 都采用了模板方法,Spring 项目启动时一系列的监听时间,采用了观察者模式。

7.你知道的 Spring 的通知类型有哪些,分别在什么时候执行?

before: 方法执行之前调用(不影响方法执行)

after: 方法执行之后调用(无论是否抛异常都会执行)

around: 方法执行前后都能控制可手动决定是否执行目标方法

afterReturning: 方法正常返回后调用(无异常时才会执行

afterThrowing: 方法抛出异常后调用

8.Spring 的对象默认是单例的还是多例的? 单例 bean 存不存在线程安全问题呢?

Spring 的对象默认是单例的,单例 Bean 也存在线程安全问题,比如某个有状态的 Bean,允许不同线程修改该状态,在多线程环境下就会出现状态异常的情况。解决方式包括加锁、使用线程安全结构,或通过 @Scope("prototype")、ThreadLocal 等方式避免共享。

9.@Resource 和 @Autowired 依赖注入的区别是什么? @Qualifier 使用场景是什么?

Resource 和 Autowired 都是 Spring 自动依赖注入的注解,Resource 只能修饰属性,而 Autowired 既可以修饰属性又可以修饰方法,修饰属性就是在容器中寻找对应实例并注入,修饰方法时,则是自动执行该方法。再使用 Resource 依赖注入属性时,Spring 会先通过属性名在容器中查找对应的类,找不到再使用类型匹配,Autowired 则相反;Autowired 也可以通过使用 Qualifier 指定类名称来依赖注入,在容器中存在多个同类型 Bean 时,应使用 @Qualifier 明确指定注入的 Bean。

10.Spring 的常用注解

注解名

功能分类

用于位置

作用说明

@Component

组件定义

类上

通用组件,注册到容器

@Controller

Web 控制层

类上

MVC 控制器,返回视图

@Service

业务逻辑层

类上

标识 Service 层组件

@Repository

持久层组件

类上

DAO 层组件,支持异常转换

@RestController

Web 控制层

类上

等价于 @Controller + @ResponseBody

,返回 JSON

@Configuration

配置类

类上

声明 Java 配置类,等同 XML 配置

@Bean

注册 Bean

方法上

注册一个手动管理的 Bean 到容器

@ComponentScan

Bean 扫描配置

类上

指定包路径,自动扫描 @Component

等注解

@Autowired

依赖注入

属性/构造器/方法

按类型注入 Bean

@Qualifier

Bean 精确注入

属性/参数

指定注入 Bean 的名称,配合 @Autowired

使用

@RequestMapping

请求映射

类/方法上

映射请求路径,支持所有 HTTP 方法

@GetMapping

请求映射

方法上

映射 GET 请求,@RequestMapping(method=GET)

简写

@PostMapping

请求映射

方法上

映射 POST 请求

@PutMapping

请求映射

方法上

映射 PUT 请求

@DeleteMapping

请求映射

方法上

映射 DELETE 请求

@PathVariable

参数绑定

方法参数

绑定 URL 路径中的变量值

@RequestParam

参数绑定

方法参数

绑定请求参数(?id=123)

@RequestBody

参数绑定

方法参数

接收 JSON 请求体,自动反序列化成对象

@ResponseBody

响应绑定

方法/类上

将方法返回值序列化为 JSON 响应体

@Transactional

事务控制

类/方法上

开启事务支持,自动提交/回滚

@SpringBootApplication

启动配置

主类上

组合注解,包含 @Configuration

@EnableAutoConfiguration

@ComponentScan

11.Spring 的事务传播行为

传播行为

含义说明

常见使用场景

REQUIRED

(默认)

如果当前存在事务,则加入;否则新建事务

常用(最常用的默认值)

REQUIRES_NEW

挂起当前事务,新建一个事务

重要操作不影响主事务

SUPPORTS

有事务就加入,没有就以非事务方式执行

读操作(可选事务)

NOT_SUPPORTED

以非事务方式执行,挂起当前事务

调用不希望有事务的逻辑

NEVER

不能处于事务中,若存在事务就抛异常

明确禁止事务的代码

MANDATORY

必须在事务中执行,若没有就抛异常

依赖事务的逻辑(如更新)

NESTED

当前有事务,则在嵌套事务中执行(使用保存点),否则新建事务

回滚子逻辑不影响主逻辑

12.Spring 中的事务隔离级别

Spring 中事务隔离级别通过 @Transactional(isolation = Isolation.XXX) 来设置,实质上是借助底层数据库(如 MySQL、Oracle)提供的隔离机制。所以分为读未提交,读已提交,可重复读,串行化。

Spring 的事务隔离级别通过 @Transactional 设置,最终由底层数据库实现。Spring 提供 5 种隔离级别,分别对应数据库中的标准隔离等级。默认使用数据库配置(MySQL 是 REPEATABLE_READ)。合理设置隔离级别可以避免脏读、不可重复读、幻读等并发问题。

13.拦截器,过滤器,统一异常处理器的区别

过滤器(Filter)是 Servlet 提供的,在 DispatcherServlet 之前执行,作用范围是所有请求(包括静态资源),一般用作登录校验、请求日志、跨域处理(CORS);

而拦截器(Interceptor)是 Spring MVC 提供的,拦截器在 DispatcherServlet 之后,Controller 之前执行,一般用作权限校验、参数封装、请求预处理/后处理;

统一异常处理器(ControlerAdvice)也是是 Spring MVC 提供的,ControlerAdvice 则是在 Controller 执行时抛出异常后,一般用作统一异常转换成友好 JSON 响应;

当一个请求进入到程序中,需要先进入 Spring 容器,再通过过滤器到 Servlet,最后通过拦截器后才能到控制器,同样返回结果就是根据相反方向流动,统一异常处理器则是当程序允许出现了异常,一路抛出直到被统一异常处理器捕获,它根据异常类型采取不一样的策略。

@ControllerAdvice
public class GlobalExceptionHandler {@ExceptionHandler(value = RuntimeException.class)public ResponseEntity<String> handleRuntimeException(RuntimeException ex) {return ResponseEntity.status(500).body("系统错误:" + ex.getMessage());}
}

14.有哪些不同类型的依赖注入实现方式?

DI 的一般实现方法有构造器注入,Setter 注入以及字段注入;

@Component
public class OrderService {private final UserService userService;@Autowiredpublic OrderService(UserService userService) {this.userService = userService;}
}@Component
public class OrderService {private UserService userService;@Autowiredpublic void setUserService(UserService userService) {this.userService = userService;}
}@Component
public class OrderService {@Autowiredprivate UserService userService;
}

构造器注入依赖最明确、安全性高、支持 final,是官方推荐方式;Setter 注入适合可选依赖;字段注入虽然最常见但不利于测试和维护,不推荐在生产中使用。

15.Spring 中事务失效的场景?

1. 自调用:同一个类内部调用自己的 @Transactional 方法 , Spring 的事务是通过代理对象调用生效的,自调用直接调用原始对象,不会走代理。在同一个类内部,方法之间直接调用不会通过 Spring AOP 的代理对象,因此 @Transactional 注解失效。如果外部没有事务,内部也不会开启事务;如果外部已有事务,内部方法虽然注解失效,但其逻辑会“加入”外部事务一起提交或回滚。所以,内部方法的事务传播属性不会生效,所有事务行为以外部为准。

@Service
public class UserService {@Transactionalpublic void outer() {inner(); // 事务不生效}@Transactionalpublic void inner() {// 不会被代理拦截}
}public void outer() {// 无 @Transactional,也没事务开启inner(); // inner 虽然有 @Transactional,但事务失效,也不会开启事务
}
@Transactional
public void inner() {// 实际没有事务!!!
}@Transactional // 外部有事务
public void outer() {inner(); // 调用 inner 时没走代理,@Transactional 失效
}@Transactional(propagation = Propagation.REQUIRES_NEW)
public void inner() {// 事务传播属性不生效,只是加入了 outer 的事务
}

2.方法不是 public 修饰的,Spring 事务 AOP 默认只能拦截 public 方法。非 public 方法(如 private, protected)不会被代理增强。

3. 异常被捕获后未抛出,默认只有 RuntimeException 或其子类 异常才会触发事务回滚;如果捕获了异常但没有重新抛出,就无法触发回滚。

@Transactional
public void save() {try {// 报错了} catch (Exception e) {log.error("异常", e);}// 没有回滚
}

4. 数据库不支持事务或操作本身不在事务控制范围内,比如 DDL 语句(如 CREATE, ALTER)在某些数据库下不会被事务控制;非关系型数据库(如 Redis、Mongo)不支持 Spring 的 JDBC 事务。

5. 未被 Spring 容器管理的类上加了 @Transactional,如果不是 @Service、@Component、@Controller、@Repository 注解的类,Spring 不会创建代理。

6. 事务传播行为设置不当,比如外层无事务,调用内部 REQUIRES_NEW 方法,会新建事务;但外层异常回滚不会影响内层已经提交的事务。

7. 多线程操作中事务不生效,每个线程是独立的,线程中执行方法不会沿用主线程的事务上下文。在异步任务(如 @Async)中事务失效。

16.JDK 动态代理和 CGLIB 动态代理的区别

Spring AOP 是通过 动态代理 实现增强的。根据目标类是否实现接口,选择不同的代理方式:

JDK 动态代理:要求目标类实现接口;Spring 会生成一个实现目标接口的代理类;通过 InvocationHandler#invoke() 拦截方法调用,执行增强逻辑。

CGLIB 动态代理:目标类没有接口,或强制使用 proxyTargetClass=true;通过生成目标类的子类,并重写非 final 方法实现增强;增强逻辑织入子类方法中,调用时先执行增强逻辑再调用原方法。

17.Spring 中的循环引用

Spring 中的循环依赖指多个 Bean 之间互相引用的现象。Spring 通过三级缓存(singletonObjects、earlySingletonObjects 和 singletonFactories)解决了单例作用域和非构造器注入的循环依赖。但对于构造器注入或原型作用域 Bean 的循环依赖,Spring 无法解决,会抛出异常。

@Component
public class A {@Autowiredprivate B b;
}@Component
public class B {@Autowiredprivate A a;
}

Spring 通过 三级缓存机制解决了大部分单例 Bean 的构造器注入(Setter 或字段注入)循环依赖问题。

缓存名称

类型

描述

一级缓存

singletonObjects

成熟 Bean(完全初始化)

二级缓存

earlySingletonObjects

半成品 Bean(已实例化未初始化)

三级缓存

singletonFactories

Bean 工厂,用于暴露代理或提前引用

  • Spring 在创建 Bean A 时,发现它依赖 B;
  • 开始创建 B,发现 B 又依赖 A;
  • Spring 会从三级缓存提前暴露 A 的实例引用(还未注入属性);
  • B 获取到 A 的“早期引用”,顺利注入;
  • A、B 最终都能完整实例化,注入完成。

18.Spring 有什么好处

1.解耦 + 降低复杂度(IOC/DI)

核心优势:通过控制反转(IoC)和依赖注入(DI)实现对象管理,解耦对象之间的依赖关系;

你只需要关注“用什么”,而不是“怎么创建”;

减少了硬编码,提升了系统可测试性和扩展性。

2.AOP 支持

面向切面编程(AOP)让你可以统一处理横切关注点,如:事务、日志、安全、权限校验等;

可以在不修改业务代码的前提下,动态增强 Bean 的功能。

3.统一事务管理

Spring 提供了声明式事务管理(@Transactional),简洁、清晰;

支持多种事务管理器(JDBC、JPA、Hibernate、MyBatis)。

4.丰富的模块和生态支持

Spring 不是一个工具,而是一个完整生态体系。

19. 为什么构造器注入不能解决循环依赖?

Spring 的循环依赖解决机制依赖于 提前暴露“半成品” Bean 实例(early reference)

  • 构造器注入是在 Bean 还没创建出来之前就必须准备好所有依赖;
  • Spring 此时无法提前放入三级缓存,没有机会暴露半成品
  • 所以只要 A 和 B 都通过构造器互相依赖,Bean 根本创建不出来,就死锁或抛异常。
http://www.dtcms.com/a/278484.html

相关文章:

  • UI前端大数据处理新挑战:如何高效处理实时数据流?
  • JavaScript 与 C语言基础知识差别
  • GO语言中的垃圾回收(GC)
  • 怎么挑选最新贝琪入门电钢琴才高效?
  • Java进程、线程与协程对比
  • GD32/STM32嵌入CMSIS-DSP的库(基于Keil)
  • 2025年 GitHub 主流开源视频生成模型介绍
  • Go语言第一个程序--hello world!
  • arthas:Java 应用问题诊断利器
  • 企业培训笔记:axios 发送 ajax 请求
  • vue中计算属性的介绍
  • 前端基础知识TypeScript 系列 - 08(TypeScript 装饰器的理解)
  • 代理模式详解:代理、策略与模板方法模式
  • SpringMVC1
  • GraphRAG核心提示词工程完整中文版
  • VyOS起步指南:用Docker快速搭建网络实验环境
  • 分享三个python爬虫案例
  • HTML应用指南:利用GET请求获取河南省胖东来超市门店位置信息
  • STM32新建工程
  • HTB 赛季8靶场 - Outbound
  • 微算法科技技术创新,将量子图像LSQb算法与量子加密技术相结合,构建更加安全的量子信息隐藏和传输系统
  • 复习笔记 38
  • 安卓基于 FirebaseAuth 实现 google 登录
  • 【小米训练营】C++方向 实践项目 Android Player
  • C++ 左值右值、左值引用右值引用、integral_constant、integral_constant的元模板使用案例
  • 量子计算新突破!阿里“太章3.0”实现512量子比特模拟(2025中国量子算力巅峰)
  • ethers.js-5–和solidity的关系
  • RPC 框架学习笔记
  • Spark 之 like 表达式
  • 软件测试中的BUG等级与生命周期详解