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

面试:Spring

1.依赖注入(IOC)高频问题解析

1.1 Spring的IOC是什么意思?

  • 核心定义
    IOC(Inversion of Control,控制反转)是设计思想,将对象的 创建、依赖管理权限 从开发者转移到Spring容器。
  • 实现方式(DI)
    通过 依赖注入(Dependency Injection)完成,包括 构造器注入、Setter注入、字段注入(如@Autowired)。
  • 对比传统模式
    传统开发中,开发者需手动new对象并维护依赖(如UserService service = new UserService(new UserDao()));IOC下,容器统一管理Bean的生命周期和依赖,解耦对象关系。
  • 总结:IOC让开发者聚焦业务,容器负责“对象编排”,是Spring解耦的核心。

1.2 Spring中的Bean是线程安全的吗?

  • 分场景判断
    • 单例(默认)
      • 若Bean是 无状态(无成员变量或变量只读),天然线程安全(如工具类StringUtils);
      • 若含 可变成员变量(如private String name),多线程共享会引发竞争(如并发修改name)。
      • 解决方法
        • 避免定义可变状态;
        • ThreadLocal隔离线程变量;
        • 改为原型(prototype)(每次请求新建Bean,性能开销大);
        • 加锁(synchronized,影响效率)。
    • 原型(prototype):每次获取新实例,无共享问题,线程安全。

1.3 什么是Spring的三级缓存?

  • 缓存结构(解决单例Bean循环依赖的核心):
    缓存层级作用存储对象状态
    一级缓存(singletonObjects存储 完全初始化完成 的单例Bean成品Bean(可直接使用)
    二级缓存(earlySingletonObjects存储 实例化后、未初始化 的半成品Bean半成品(已实例化,未注入依赖/初始化)
    三级缓存(singletonFactories存储 Bean的工厂函数(生成早期引用)工厂Lambda(创建早期Bean)
  • 工作流程(以A→B→A循环依赖为例):
    1. 创建A:实例化后,将A的工厂放入三级缓存,尝试注入B
    2. 创建B:实例化后,从三级缓存取A的早期引用(放入二级缓存,删除三级缓存),完成B的初始化并放入一级缓存。
    3. 回到A:从二级缓存取B的成品,完成A的初始化,最终放入一级缓存。

1.4 Spring的循环依赖问题是什么?如何解决?

  • 问题定义
    多个Bean互相依赖(如A依赖BB依赖A),导致创建时相互等待,无法初始化。
  • 解决范围
    • 支持Setter注入/字段注入(依赖注入发生在实例化后,可通过三级缓存提前暴露引用)。
    • 不支持构造器注入(依赖注入发生在实例化阶段,此时Bean未实例化,无法提前暴露),会抛BeanCurrentlyInCreationException
  • 解决原理
    利用三级缓存,在Bean 实例化后(未初始化) 提前暴露引用,打破循环等待。

2. AOP原理高频问题解析

2.1 SpringAOP的实现原理是什么?

  • 核心:动态代理,运行时生成目标对象的代理类,拦截方法调用并增强。
  • 两种代理方式
    • JDK动态代理
      • 基于接口(目标类必须实现接口),通过java.lang.reflect.Proxy生成代理,重写invoke方法。
      • 优点:JDK原生支持,性能高;缺点:必须依赖接口。
    • CGLIB代理
      • 基于类继承(目标类无需接口),通过字节码增强生成子类,重写目标方法。
      • 优点:支持类代理;缺点:无法代理final类/方法(子类无法继承)。
  • Spring策略
    • 目标类有接口:优先JDK代理;
    • 目标类无接口或配置强制CGLIB(如Spring Boot默认):用CGLIB。
  • 织入时机运行时(区别于AspectJ的编译时织入),代理对象替代目标对象执行,插入通知(Before、After等)。

2.2 Spring的AOP在什么场景下会失效?

常见失效场景

  1. 目标对象未被Spring管理
    手动new对象(如UserService service = new UserService()),而非从容器获取,代理不生效。
  2. 方法是final/static
    • final方法:CGLIB无法继承重写,JDK代理也无法拦截(接口方法不能是final);
    • static方法:属于类,代理针对实例方法,无法拦截。
  3. 同一类内的方法调用(this调用)
    class A { public void method1() { this.method2(); } }method2的切面不生效——因this是目标对象,而非代理对象,跳过拦截。
  4. 代理方式不匹配
    目标类有接口,但强制用CGLIB代理,且方法是final,则代理失败(CGLIB无法重写final方法)。

3. Bean生命周期与创建高频问题解析

3.1说一下Spring Bean的生命周期是怎么样的?

单例Bean完整流程

  1. 实例化(Instantiation):通过构造器/工厂方法创建Bean实例(内存分配,未注入依赖)。
  2. 属性注入(Populate):注入依赖(@Autowired、<property>等)。
  3. 初始化前(BeanPostProcessor前置处理):执行BeanPostProcessor.postProcessBeforeInitialization,可修改Bean属性(如统一加日志)。
  4. 初始化(Initialization)
    • 实现InitializingBean:调用afterPropertiesSet
    • 配置init-method:执行自定义初始化逻辑。
  5. 初始化后(BeanPostProcessor后置处理):执行BeanPostProcessor.postProcessAfterInitialization此处是AOP生成代理的关键时机(替换目标对象为代理)。
  6. 使用(Usage):Bean进入容器,供其他Bean调用。
  7. 销毁(Destruction):容器关闭时,实现DisposableBean则调用destroy,或执行destroy-method

3.2聊聊Spring的BeanFactory和FactoryBean?

  • BeanFactory
    • 角色:Spring容器的顶层接口,定义IOC容器核心能力(如getBean()containsBean()),管理所有Bean的生命周期。
    • 典型实现DefaultListableBeanFactory(Spring内部核心容器)。
  • FactoryBean
    • 角色特殊的Bean(由BeanFactory管理),作用是创建其他Bean(工厂模式)。
    • 场景:复杂对象创建(如MyBatis的SqlSessionFactoryBean,构建SqlSessionFactory)。
    • 核心方法
      • getObject():返回实际要创建的Bean;
      • getObjectType():返回Bean类型;
      • isSingleton():是否单例。
  • 类比:BeanFactory是“容器管理者”,FactoryBean是“Bean的工厂工人”——前者管所有Bean,后者专门生产某类Bean。

面试答题技巧

  1. 分层拆解:如Bean生命周期分阶段,结合接口(InitializingBean)和配置(init-method),体现细节。
  2. 对比强调:如BeanFactory vs FactoryBean,从“角色”“作用”维度区分,避免混淆。
  3. 原理+场景:解释三级缓存时,结合“A→B→A循环依赖”讲流程;讲AOP失效时,举“this调用”的代码例子。
  4. 避坑提示:如构造器注入的循环依赖无法解决,单例Bean的线程安全问题,体现思考深度。
http://www.xdnf.cn/news/1367245.html

相关文章:

  • MySQL 面试题系列(三)
  • week5-[循环结构]听歌
  • cuda编程笔记(16)--使用 cuDNN 实现卷积、激活、池化等反向操作
  • 淘宝/天猫商品详情API数据解析【附代码】
  • AP8105 PFM升压芯片数据手册
  • 支持向量机(SVM)学习笔记
  • 如何安装 VS2019 和 .NET Core SDK 2.2.301(winx64)?完整操作步骤(附安装包下载)
  • Ubuntu22.04安装OBS
  • 【软考论文】论自动化测试方法及其应用
  • 办公无纸化的关键:cpolar让Paperless-ngx远程扫描更便捷
  • 【Elasticsearch】k-NN 搜索深度解析:参数优化与分数过滤实践
  • 【SystemUI】锁屏来通知默认亮屏Wake模式
  • 32.Ansible平台搭建
  • 1424. 对角线遍历 II
  • 2024年Engineering SCI2区,面向工程管理的无人机巡检路径与调度,深度解析+性能实测
  • 计算机毕业设计 java 药店药品信息管理系统 基于 Java 的药店药品管理平台Java 开发的药品信息系统
  • 设计模式:原型模式(Prototype Pattern)
  • 如何通过虚函数实现多态?
  • 实现自己的AI视频监控系统-第二章-AI分析模块2
  • 【git使用场景】本地仓库与远程仓库存在独立历史
  • ​Visual Studio + UE5 进行游戏开发的常见故障问题解决
  • 系统开发 Day4
  • 音视频学习(五十六):单RTP包模式和FU-A分片模式
  • Linux驱动开发笔记(七)——并发与竞争(上)——原子操作
  • 深度学习-----《PyTorch深度学习核心应用解析:从环境搭建到模型优化的完整实践指南》
  • 链表OJ习题(2)
  • 操作系统中,进程与线程的定义与区别
  • 似然函数对数似然函数负对数似然函数
  • Ant Design for UI 选择下拉框
  • BIO、NIO 和 AIO