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

三、Spring


TOP 1:Spring 中的 Bean 是线程安全的吗?

核心答案

Bean 作用域线程安全性
singleton(默认)❌ 不安全,因为多个线程共享同一个实例
prototype✅ 相对安全,每次获取都是新实例

解决方案

  1. 避免在 Bean 中定义有状态的成员变量
  2. 使用ThreadLocal存储线程局部变量
  3. 将 Bean 作用域改为prototype(不推荐,开销大)
  4. 使用不可变对象(final字段)

一句话:默认 singleton 模式下,有状态的 Bean 不安全,无状态的是安全的。


TOP 2:Spring 如何解决循环依赖?

核心答案三级缓存

缓存名称存储内容
一级singletonObjects完全初始化好的单例 Bean
二级earlySingletonObjects提前暴露的 Bean(实例化完成,未属性注入)
三级singletonFactoriesBean 工厂(用于生成代理对象)

解决流程(以 A 依赖 B,B 依赖 A 为例):

实例化 A

将 A 放入三级缓存
singletonFactories

填充 A 属性
发现依赖 B

实例化 B

将 B 放入三级缓存

填充 B 属性
发现依赖 A

从三级缓存获取 A
移到二级缓存

B 初始化完成
放入一级缓存

A 从一级缓存获取 B

A 初始化完成
放入一级缓存

注意:只能解决singleton作用域的循环依赖,prototype 无法解决。

Spring三级缓存是解决循环依赖问题的核心机制。所谓循环依赖,就是Bean A依赖Bean B,Bean B又依赖Bean A。

为什么需要三级缓存?

  • 只用一级缓存:成品和半成品混在一起,无法区分
  • 只用二级缓存:可以解决普通循环依赖,但无法处理AOP代理问题
  • 三级缓存的核心作用:通过ObjectFactory,在真正需要暴露早期对象时再决定是返回原始对象还是代理对象(避免提前创建代理,保持代理与原始对象统一)

局限

Spring的三级缓存只能解决单例模式下的setter注入循环依赖,无法解决:

  • 构造器注入的循环依赖(直接报错)
  • 多例Bean的循环依赖

TOP 3:Bean 的生命周期?

销毁阶段

执行PreDestroy标注的方法

实现DisposableBean接口的destroy方法

执行XML或Bean中指定的destroy-method

初始化阶段

执行PostConstruct标注的方法

实现InitializingBean接口的afterPropertiesSet方法

执行XML或Bean中指定的init-method

实例化 - 通过构造器创建Bean实例

属性填充 - 注入Autowired Value等依赖

Bean初始化完成 可投入使用

面试口诀

Spring Bean 的生命周期顺序为:实例化 → 属性填充 → 初始化(@PostConstruct → afterPropertiesSet → init-method)→ 使用 → 销毁(@PreDestroy → destroy → destroy-method)。


TOP 4:@Autowired 和 @Resource 的区别?

对比项@Autowired@Resource
来源Spring 原生Java 标准(JSR-250)
注入方式byType 优先byName 优先
参数requirednametype
适用框架仅 Spring任何 Java EE 容器

使用示例

// @Autowired:优先按类型匹配@AutowiredprivateUserServiceuserService;// @Resource:优先按名称匹配(name=userService)@Resource(name="userService")privateUserServiceuserService;

一句话@Autowired默认按类型填充,@Resource模型按名称填充。


TOP 5:Spring AOP 的原理是什么?

核心答案动态代理

场景代理方式条件
有接口JDK 动态代理目标类实现了接口
无接口CGLIB 动态代理目标类没有接口(生成子类)

AOP 核心概念

概念说明
JoinPoint连接点,可被增强的方法
Pointcut切入点,实际要增强的方法集合
Advice通知,增强的逻辑(@Before、@After、@Around)
Aspect切面 = Pointcut + Advice
Weaving织入,将切面应用到目标对象的过程

一句话:AOP 通过动态代理,在不修改源码的情况下给方法增强功能。

Spring 生成代理对象的时机?

是否有循环依赖生成时机
实例化后生成代理
初始化后生成代理

Spring 哪些场景会生成代理对象?

场景生成时机生成时机
普通 AOP@Aspect + @Around前置增强、后置增强
事务管理@Transactional事务提交、回滚
异步执行@Async把方法包装成任务提交给线程池
缓存管理@Cacheable @EnableCaching从缓存读取数据、数据放入缓存

Spring 创建代理失效的场景

排名失效场景出现率代码示例(❌ 失效)代码示例(✅ 正确)核心原因
1内部调用95%this.methodA()self.methodA()(注入自身代理)this指向原始对象,不经过代理
2非 public 方法80%@Transactional protected void methodA()@Transactional public void methodA()Spring 默认只代理 public 方法
3异常被 catch 吞掉70%try { ... } catch(Exception e) { log... }catch(Exception e) { throw e; }手动回滚代理感知不到异常,无法回滚
4rollbackFor 配置错误55%@Transactional(抛 checked 异常)@Transactional(rollbackFor = Exception.class)默认只回滚 RuntimeException
5final 方法45%@Transactional public final void methodA()移除final关键字CGLIB 通过子类重写,final 方法无法重写
6final 类30%@Service public final class UserService移除final关键字CGLIB 需要继承目标类,final 类无法继承

TOP 6:BeanFactory 和 FactoryBean的区别?

  • BeanFactory 是 Spring IOC 容器的根接口,定义了 getBean() 这些基础方法,它是容器本身,负责管理所有 Bean 的创建和生命周期,默认是懒加载的。
  • FactoryBean 是一个接口,开发者实现它来自定义某个复杂 Bean 的创建逻辑。FactoryBean 本身也是一个 Bean,会被 Spring 管理。创建出来的对象通过 getBean(“name”) 获取,如果想获取 FactoryBean 本身,需要用 & 前缀。
  • 常见的使用场景比如 MyBatis 的 SqlSessionFactoryBean 就是通过 FactoryBean 来生产 SqlSessionFactory 的。"

TOP 7:BeanPostProcessor 和BeanFactoryPostProcessor的区别

一句话:BeanPostProcessor 针对 Bean 实例,在 Bean 初始化前后进行增强;BeanFactoryPostProcessor 针对 BeanDefinition,在 Bean 实例化之前修改 Bean 的定义信息。

BeanDefinition有哪些信息

“BeanDefinition 是 Bean 的元数据,包含类名、作用域、构造参数、属性值、生命周期方法、懒加载、dependsOn 等信息,是 Spring 实例化 Bean 的依据。”

TOP 8:Spring 中 Bean 的作用域有哪些?

作用域说明使用场景
singleton单例(默认),容器唯一无状态 Bean
prototype原型,每次获取都新建有状态 Bean
request每个 HTTP 请求一个Web 应用
session每个 HTTP Session 一个Web 应用
application每个 ServletContext 一个Web 应用
@Scope("prototype")@ComponentpublicclassPrototypeBean{}

TOP 9:@SpringBootApplication 包含哪些注解?

核心答案:它是三个注解的组合

注解作用
@SpringBootConfiguration标注为配置类(底层是@Configuration
@EnableAutoConfiguration开启自动配置
@ComponentScan组件扫描(默认扫描当前包及子包)

等效代码

@SpringBootApplication// 等价于 ↓@SpringBootConfiguration@EnableAutoConfiguration@ComponentScan(basePackages="com.example")

TOP 10:Spring 中常用的设计模式有哪些?

设计模式Spring 中的应用
工厂模式BeanFactory、ApplicationContext
单例模式默认 Bean 作用域
代理模式AOP 动态代理
模板模式JdbcTemplate、RedisTemplate
观察者模式ApplicationListener、事件机制
适配器模式HandlerAdapter(Spring MVC)
装饰器模式BeanWrapper
策略模式InstantiationStrategy

Spring Boot 自动装配原理

一、一句话总结

Spring Boot 自动装配通过@SpringBootApplication注解中的@EnableAutoConfiguration,利用SpringFactoriesLoaderMETA-INF/spring.factories文件中加载配置类,再结合条件注解(如@ConditionalOnClass)按需生效。


高频追问链

Q: Spring 如何解决循环依赖? → (答完后)Q: 为什么需要三级缓存?两级够吗? → 两级无法处理代理对象 → Q: 什么情况下会生成代理对象? → AOP 会生成代理 → Q: AOP 的原理是什么? → 动态代理(JDK/CGLIB) → Q: JDK 和 CGLIB 有什么区别? → JDK 需要接口,CGLIB 不需要

http://www.gsyq.cn/news/1464024.html

相关文章:

  • CPT Markets:经纪商服务体验的理性观察
  • 从ReLU到Tanh:浅层神经网络激活函数怎么选?看完这篇避坑指南再决定
  • 从通信系统到振动分析:矩阵束(Matrix Pencil)方法如何成为工程界的‘瑞士军刀’?
  • 期货量化限价挂单总漏状态:天勤 InsertOrderTask 用法
  • Windows窗口管理革命:用AlwaysOnTop实现300%效率提升的终极方案
  • 实地探访深圳木点点整装:21年本土工厂,凭什么能做到84%转介绍率? - 产品测评官
  • qorder实战:基于快马平台快速集成订单状态管理与物流跟踪接口
  • 律所多人协作办案的实践方法:权限管理、任务跟踪与在线协同的落地经验
  • 如何用Pixelorama零基础成为像素艺术创作高手:从入门到精通的完整指南
  • 元宝 LeetCode 2977. 转换字符串的最小成本 II C语言实现
  • 【AI工具产品路线图预测权威指南】:20年实战经验总结的5大关键信号与3年趋势推演模型
  • 别再只懂MSE了!PyTorch实战:用Smooth L1 Loss搞定目标检测中的边界框回归
  • 手把手教你用TwinCAT 3为EtherCAT设备生成XML配置文件(附避坑指南)
  • 别再死记硬背了!用这4种方法搞定正激拓扑的磁复位,选型避坑指南
  • 2026年新消息:东莞诚信的圆瓶贴标机定做厂家选型指南与骐麟新创智能推荐 - 2026年企业资讯
  • RTX5凭啥通过汽车级安全认证?深入剖析其在STM32F407上的零中断延迟与确定性
  • 3分钟快速安装Figma中文界面插件:设计师人工翻译校验的终极指南
  • 保姆级教程:用MATLAB处理CSV实测数据,从频谱到1/3倍频程的完整分析流程
  • 别再在PyCharm里直接敲pip install了!SyntaxError报错的真正原因和3种正确安装姿势
  • Matlab版DBN-BP两阶段回归预测工具包:含训练脚本、可视化结果与实测数据
  • Logstash管道(Pipeline)配置入门:手把手教你写第一个`.conf`文件并理解input/filter/output
  • FastAPI+Uniapp私域知识库问答系统:支持PDF/TXT上传、多端部署与语义检索
  • GCC 的 inline 扩展,和c99 inline规则的异同,static inline的统一
  • AI工具×智能简历:3天打造HR秒回率超85%的动态求职系统
  • 轻量级3D场景图技术:开放词汇与语义属性组合
  • 用Python+OpenCV复现1952年植物光谱实验:从叶片颜色到叶绿体提取,手把手教你做高光谱分析
  • 【无敌数据驱动】【自动驾驶】一种数据驱动的优化前馈补偿器的方法,用于自动驾驶汽车控制研究(Matlab代码实现)
  • 华为WLAN三层漫游实战:旁挂组网下,如何让不同VLAN的AP无缝切换不掉线?
  • 告别单核苦力!手把手教你用DSP6678的MPAX实现多核镜像共享(附完整工程配置)
  • 蒙特卡洛仿真教学实践包:双语课件+投资组合/面积估算/方差缩减全功能示例代码