Spring面试题 01
目录1. 谈谈你对 AOP 的理解2. 谈谈你对 IOC 的理解3. 解释下 Spring 支持的几种 Bean 的作用域4. 简述 Spring 中的事务的实现方式5. 了解 Spring 中的事务传播机制吗6. 说一说 Spring 事务的底层实现逻辑7. Spring 事务什么时候会失效8. 什么是 Bean 的自动装配有哪些模式9. Spring 中 Bean 是线程安全的吗10. 如何应对单例 Bean 的线程安全问题呢 面试加分小贴士这是一份非常经典的 Spring 核心面试题清单涵盖了AOP、IOC、Bean 管理、事务机制四大核心板块。针对大厂面试如华为、字节、美团回答不能仅停留在“背诵定义”而要体现“原理理解 场景应用 避坑经验”。以下是为你整理的高分回答话术采用“结论先行 - 原理解析 - 场景/细节 - 总结”的逻辑结构。1. 谈谈你对 AOP 的理解关键词解耦、横切关注点、动态代理、责任链核心结论AOP面向切面编程的核心目的是解耦。它将那些与业务逻辑无关却为多个模块共同关注的功能如日志、事务、权限控制封装起来减少重复代码。原理解析底层基于动态代理实现。如果目标类实现了接口默认使用JDK 动态代理如果没有实现接口则使用CGLIB 代理生成子类。核心概念包括切面Aspect、连接点JoinPoint、通知Advice如 Before/After/Around、切入点Pointcut。应用场景最典型的就是 Spring 的声明式事务Transactional和全局日志记录。个人思考在实际开发中我常用 AOP 做统一的数据脱敏或接口耗时统计。需要注意的是AOP 本质是代理对象所以在类内部调用Self-Invocation时AOP 可能会失效因为绕过了代理对象。2. 谈谈你对 IOC 的理解关键词控制反转、依赖注入、解耦、容器管理核心结论IOC控制反转是一种设计思想DI依赖注入是其具体实现。核心是将对象的创建、初始化、销毁等生命周期控制权从代码中移交给Spring 容器管理。原理解析传统模式下对象 A 需要主动new对象 B耦合度高。IOC 模式下A 只需要声明“我需要 B”容器会在运行时自动将 B 注入给 A。底层核心是BeanFactory和ApplicationContext通过反射机制实例化对象并利用Map结构存储 Bean 实例单例池。优势极大降低了模块间的耦合度方便单元测试和模块替换。个人思考IOC 让开发者更专注于业务逻辑本身而不是基础设施的搭建。但也要注意过度依赖 IOC 可能导致项目启动变慢因为要扫描和初始化大量 Bean所以在大型项目中我们会按需加载或使用懒加载Lazy。3. 解释下 Spring 支持的几种 Bean 的作用域关键词Singleton, Prototype, Request, Session核心结论Spring 默认是单例Singleton但也支持多例和其他 Web 作用域。详细分类Singleton单例默认模式。整个 Spring 容器中只有一个实例线程不安全适合无状态的 Service/Dao。Prototype多例/原型每次请求都创建一个新实例适合有状态的对象如 Struts2 的 Action。Request一次 HTTP 请求一个实例仅限 Web 环境。Session一个 HTTP Session 一个实例仅限 Web 环境。Application整个 ServletContext 生命周期内一个实例。注意点如果在 Singleton Bean 中注入 Prototype Bean直接注入会导致 Prototype 失效因为 Singleton 只初始化一次。此时需要通过ObjectFactory或Lookup注解来解决。4. 简述 Spring 中的事务的实现方式关键词编程式 vs 声明式、AOP、Transactional核心结论主要有两种方式编程式事务和声明式事务。实际开发中 99% 的情况都用声明式事务。对比分析编程式使用TransactionTemplate或在代码中手动管理commit/rollback。优点是粒度控制精确缺点是代码侵入性强维护困难。声明式基于AOP实现。只需在方法或类上添加Transactional注解。Spring 会在方法执行前后自动拦截开启事务、提交或回滚。底层逻辑声明式事务本质是 Spring 通过动态代理生成的一个代理对象包裹了目标方法在调用前后织入事务管理逻辑。5. 了解 Spring 中的事务传播机制吗关键词REQUIRED, REQUIRES_NEW, NESTED核心结论传播行为定义了当一个事务方法被另一个事务方法调用时这个事务方法应该如何运行。Spring 定义了 7 种最常用的是前 3 种。重点详解REQUIRED默认如果当前存在事务则加入该事务如果不存在则新建一个事务。父子同生共死REQUIRES_NEW不管当前是否存在事务都挂起当前事务新建一个新事务。子事务独立父事务异常不影响子事务提交反之亦然NESTED如果当前存在事务则在嵌套事务内执行保存点机制如果不存在则按 REQUIRED 处理。子事务可以单独回滚而不影响父事务但父事务回滚会导致子事务也回滚场景举例比如注册送积分注册是主事务送积分是子事务。如果希望注册失败积分也不送用REQUIRED如果希望即使注册失败已经送的积分也要保留极少见或者送积分失败不影响注册成功可以用REQUIRES_NEW。6. 说一说 Spring 事务的底层实现逻辑关键词DataSourceTransactionManager, ThreadLocal, 代理对象核心结论Spring 事务底层依赖于数据库连接池和ThreadLocal。流程解析Spring 通过DataSourceTransactionManager管理事务。当开启事务时Spring 会从数据源获取一个 Connection并将该 Connection 绑定到当前线程的ThreadLocal中。后续在该线程内的所有数据库操作都会从 ThreadLocal 中获取同一个 Connection从而保证在同一个事务中。方法执行成功提交事务并移除 ThreadLocal方法抛出异常回滚事务并移除 ThreadLocal。关键点这就是为什么事务必须在同一个线程内才有效的原因。如果是多线程异步调用ThreadLocal 拿不到同一个 Connection事务就会失效。7. Spring 事务什么时候会失效关键词自调用、非 public、异常捕获、多线程、数据库引擎核心结论事务失效通常是因为绕过了 Spring 的代理对象或配置不当。常见场景如下同类自调用方法 A有事务调用本类的方法 B有事务B 的事务会失效。因为 A 调用 B 是this.B()没有经过代理对象。-解决注入自身或使用 AopContext。方法修饰符非 publicTransactional只能用在 public 方法上。异常被吞掉方法内部try-catch了异常但没有抛出Spring 感知不到异常不会回滚。-解决catch 中手动抛出 RuntimeException 或调用TransactionAspectSupport.currentTransactionStatus().setRollbackOnly()。异常类型不匹配默认只回滚RuntimeException和Error。如果抛出 Checked Exception如 IOException且未配置rollbackFor不会回滚。数据库引擎不支持如 MySQL 使用了 MyISAM 引擎不支持事务必须用 InnoDB。多线程调用不同线程无法共享事务上下文。8. 什么是 Bean 的自动装配有哪些模式关键词byType, byName, Constructor, Autowired核心结论自动装配是指 Spring 容器自动检测并注入 Bean 之间的依赖关系无需手动new或配置 XML。装配模式byType根据类型匹配。如果容器中有多个同类型的 Bean会报错。byName根据属性名匹配 Bean 的 ID。Constructor通过构造函数注入推荐保证依赖不可变且非空。No不自动装配。注解实现Autowired默认按类型装配。配合Qualifier(beanName)可按名称装配。Resource默认按名称装配JSR-250 标准。个人思考在构造器注入中如果一个类有多个构造函数Spring 会选择参数最多的那个如果只有一个无论是否有Autowired都会自动注入。9. Spring 中 Bean 是线程安全的吗核心结论不是绝对的取决于 Bean 的作用域和是否包含可变状态。具体分析Singleton单例Spring 容器中的 Bean 默认是单例的。如果 Bean 是无状态的如 Service、Dao只包含方法逻辑不存成员变量则是线程安全的。有状态风险如果单例 Bean 中定义了可变的成员变量如private int count;并且多个线程同时修改它就会出现线程安全问题。Prototype多例每次请求 new 一个新对象天然线程安全因为每个线程操作的都是不同的对象实例。总结Spring 并不保证 Bean 的线程安全线程安全责任在于开发者。最佳实践是尽量将 Service/Controller 设计为无状态的。10. 如何应对单例 Bean 的线程安全问题呢关键词避免成员变量、ThreadLocal、锁、原型作用域方案一推荐避免使用可变的成员变量。将局部变量定义在方法栈中天然线程隔离。如果必须共享数据考虑放入 Redis 或数据库中。方案二使用ThreadLocal。将成员变量封装在ThreadLocal中确保每个线程拥有独立的变量副本。这是解决单例线程安全最常用的手段如 Spring 的事务管理器、UserContext。方案三加锁Synchronized / Lock。对临界区代码加锁。但会降低并发性能一般不推荐用于高并发业务逻辑。方案四改变作用域。将 Bean 的作用域改为Prototype多例但这会增加内存开销和 GC 压力通常不作为首选。方案五使用不可变类。如果成员变量必须存在将其声明为final且初始化后不再修改。 面试加分小贴士结合源码在回答第 6 题底层逻辑时如果能提到PlatformTransactionManager接口或TransactionInterceptor类会让面试官眼前一亮。结合业务在回答第 7 题失效场景时一定要举一个自己项目中遇到的真实例子比如“我之前在做订单模块时因为 try-catch 导致事务没回滚后来通过...解决了”这比纯理论更有说服力。条理清晰回答问题时先说结论再分点阐述最后做个小总结。
本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/2415776.html
如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!