版权说明:本文档由用户提供并上传,收益归属内容提供方,若内容存在侵权,请进行举报或认领
文档简介
Spring源码高频面试题及详细答案(实战向)一、Spring核心容器基础源码问题1.简单说一下SpringIoC容器的初始化完整流程?SpringIoC容器初始化核心可以分为三大步骤,也是源码执行的主干流程,面试中不用罗列细碎方法,讲清主干即可:第一,资源加载与解析。容器启动后,会读取XML配置、注解配置或者JavaConfig配置,将配置文件封装成Resource资源对象,再通过解析器解析成BeanDefinition对象。这一步不会创建Bean实例,只是把Bean的类路径、属性、依赖、作用域等元信息读取并缓存。第二,BeanDefinition注册。解析完成后,会把所有BeanDefinition注册到BeanDefinitionRegistry注册表中,本质就是一个ConcurrentHashMap,key是bean名称,value是BeanDefinition对象。此时容器中只有Bean的定义信息,没有实例对象。第三,Bean实例化与初始化。容器刷新完成后,会遍历所有已注册的BeanDefinition,针对单例、非懒加载的Bean,执行实例化、属性填充、初始化方法执行、后置处理器增强等流程,最终将完整的Bean实例存入单例池。简单总结:加载配置→解析元信息→注册Bean定义→刷新容器→实例化初始化Bean。2.BeanFactory和ApplicationContext的区别?源码层面如何理解?BeanFactory是Spring容器的顶层核心接口,是IoC容器的最基础规范,定义了Bean获取、判断Bean是否存在、获取Bean类型等最基础方法。它的设计偏向轻量化、延迟加载,默认只有在调用getBean()时才会创建Bean实例。ApplicationContext是BeanFactory的子接口,在BeanFactory基础上做了全方位扩展,也是我们开发中实际使用的容器对象。核心区别(源码角度):1.功能扩展:ApplicationContext新增了事件发布、资源加载、国际化、环境配置、AOP自动适配等能力,BeanFactory只有基础的Bean管理能力。2.加载机制不同:BeanFactory是延迟初始化,ApplicationContext默认容器启动时预初始化所有单例Bean,提前暴露问题,避免运行时报错。3.后置处理器支持:ApplicationContext启动时会自动注册并执行大量内置Bean后置处理器、工厂后置处理器,BeanFactory需要手动注册、手动触发执行。3.Spring中Bean的生命周期详细流程?源码执行顺序是什么?完整的Bean生命周期,贴合源码刷新容器后的执行顺序,分为7个核心阶段,面试高频:1.实例化:通过反射创建Bean的原始空对象,此时对象已存在,但属性都是默认值,未赋值。2.属性填充:Spring自动解析Bean的依赖,完成自动装配(@Autowired、构造器注入、set注入),给对象属性赋值。3.前置处理(BeanPostProcessor前置):执行所有Bean后置处理器的前置处理方法,这一步是AOP、动态代理的核心入口。4.初始化方法执行:先执行Aware系列接口(BeanNameAware、BeanFactoryAware等),再执行@PostConstruct标注的方法,最后执行init-method指定的初始化方法。5.后置处理(BeanPostProcessor后置):执行后置处理器的后置方法,完成Bean的最终增强,代理对象就是这一步生成替换原始对象的。6.就绪阶段:Bean完全初始化完成,存入单例池,可供业务使用。7.销毁阶段:容器关闭时,执行@PreDestroy、destroy-method指定的销毁方法,释放资源。二、SpringBean作用域与循环依赖源码问题1.Spring默认的单例Bean是线程安全的吗?为什么?不是线程安全的,这是面试高频坑点。Spring的单例Bean是容器级单例,整个IoC容器中只存在一个Bean实例,所有请求、所有线程都会共用这一个对象。如果Bean中存在成员变量,多线程并发修改成员变量时,一定会出现线程安全问题。如果Bean是无状态的(没有成员变量,只有方法),则不存在线程安全问题,这也是Spring中Controller、Service、Mapper默认单例的原因,这类组件都是无状态的。解决方案:尽量保证Bean无状态;有状态场景可以使用ThreadLocal隔离线程变量,或者将Bean改为多例作用域。2.什么是Spring循环依赖?Spring能解决哪些循环依赖?为什么构造器循环依赖无法解决?循环依赖就是两个或多个Bean互相依赖,比如A依赖B,B又依赖A,容器初始化时会出现互相等待的问题。Spring默认只能解决单例Bean的setter/字段注入循环依赖,无法解决构造器注入、多例Bean的循环依赖。核心原理是Spring的三级缓存机制:一级缓存:存放完全初始化完成的单例Bean;二级缓存:存放已实例化但未填充属性、未初始化的Bean原始对象;三级缓存:存放Bean的工厂对象(ObjectFactory),用于提前暴露Bean引用。执行逻辑:A实例化后,先把自己的工厂对象放入三级缓存,再填充属性时发现需要B,于是去创建B;B创建时需要A,从三级缓存拿到A的提前引用,完成自身初始化,再回到A完成后续属性填充和初始化,以此打破循环。为什么构造器循环依赖无法解决?构造器注入是在Bean实例化阶段就需要依赖对象,而三级缓存的提前暴露是在实例化完成之后。构造器创建对象时,对象还没生成,没有任何引用可以提前暴露,所以无法破解,直接抛出循环依赖异常。3.详细说一下Spring三级缓存的作用,为什么必须要三级缓存,二级缓存不行?很多人会误以为二级缓存就够用,其实二级缓存无法满足AOP代理+循环依赖的场景。如果只有二级缓存,存储的是原始Bean对象,当Bean需要被AOP代理时,提前暴露的是原始对象,最终容器中会存在原始对象和代理对象两个实例,依赖注入的是原始对象,最终使用的是代理对象,出现对象不一致问题。三级缓存存放的是ObjectFactory工厂,它可以动态获取Bean对象:如果Bean不需要代理,就返回原始对象;如果需要代理,就返回代理对象。这样能保证提前暴露的对象和最终容器中的对象是同一个,彻底解决循环依赖+AOP代理冲突问题。简单总结:一级缓存存成品Bean,二级缓存存半成品Bean(防止重复创建),三级缓存解决代理对象一致性问题。三、SpringAOP源码核心面试题1.SpringAOP的核心原理是什么?JDK动态代理和CGLIB代理的区别?SpringAOP核心是动态代理机制,基于后置处理器AnnotationAwareAspectJAutoProxyCreator,在Bean初始化完成后,判断Bean是否需要切面增强,需要则生成代理对象替换原始Bean。两种代理的核心区别:1.JDK动态代理:只能代理实现了接口的类,基于接口生成代理对象,是JDK原生能力,无额外依赖。执行效率高,但局限性强。2.CGLIB代理:基于字节码增强,可以代理没有接口的普通类,通过继承目标类生成子类作为代理对象。无需接口,但无法代理final类和final方法,因为无法被继承重写。Spring5之后默认策略:目标类有接口用JDK代理,无接口用CGLIB代理;SpringBoot2.0+默认全部使用CGLIB代理。2.SpringAOP的执行顺序?多个切面如何排序?单个切面的完整执行顺序:前置通知→目标方法执行→后置返回通知→最终后置通知;如果方法异常,会执行异常通知,跳过后置返回通知。多个切面的执行遵循洋葱模型:前置通知:按切面优先级从高到低执行;后置通知、异常通知:按优先级从低到高逆向执行。切面排序方式:通过@Order注解或者实现Ordered接口设置优先级,数值越小,优先级越高。3.AOP为什么拦截不到static、final、private方法?核心原因和动态代理的实现机制有关:1.static方法:属于类而非对象,动态代理是基于对象层面的增强,无法重写、拦截静态方法。2.final方法:CGLIB基于继承重写方法实现增强,final方法无法被重写,所以无法拦截。3.private方法:私有方法无法被子类继承、无法被外部调用,代理框架无法获取并增强该方法,因此无法拦截。四、Spring事务源码面试题1.Spring事务的底层原理是什么?Spring事务本质是AOP动态代理,核心处理器是TransactionInterceptor事务拦截器。执行流程:1.容器启动时,扫描所有带有@Transactional注解的类和方法,通过AOP生成代理对象。2.调用目标方法时,进入TransactionInterceptor拦截器,开启事务切面逻辑。3.拦截器先获取事务管理器,根据事务传播行为判断是否开启新事务、加入已有事务。4.执行目标业务方法,方法正常执行完毕则提交事务;出现异常则根据异常类型判断是否回滚。2.为什么Spring事务默认只回滚RuntimeException和Error?受检异常不回滚的原因?这是Spring源码的默认规则,源码中事务回滚的判断条件是:仅对RuntimeException和Error执行回滚,对编译期受检异常(Exception子类)默认不回滚。设计初衷:受检异常是开发者必须主动捕获处理的异常,Spring认为这类异常是业务可预期、可处理的,不应该直接回滚事务;而运行时异常和系统错误是不可预期的、程序逻辑错误,必须回滚保证数据一致性。如果需要让受检异常也触发回滚,可以通过@Transactional(rollbackFor=Exception.class)手动指定。3.事务失效的常见场景(源码层面原因)?面试最常问的6种事务失效场景,核心原因基本都是绕过了AOP代理:1.方法内部调用:同类中A方法调用本类带事务的B方法,不会经过代理对象,直接调用原始方法,事务失效。2.方法非public:Spring事务拦截器只拦截public方法,非public方法不会生成事务切面,事务失效。3.异常被手动捕获:业务代码try-catch捕获了异常,拦截器无法感知异常,不会触发回滚。4.传播行为配置错误:如REQUIRES_NEW、NOT_SUPPORTED等传播行为使用不当,导致事务不生效或挂起。5.数据库引擎不支持事务:MyISAM引擎不支持事务,无论怎么配置都无效,必须InnoDB。6.多线程场景:子线程抛出异常,主线程事务不会回滚,线程独立事务上下文。五、Spring核心拓展点源码问题1.Spring的Bean后置处理器和工厂后置处理器的区别?1.BeanFactoryPostProcessor(工厂后置处理器):作用于BeanDefinition阶段,在Bean实例化之前执行。可以修改、新增、删除Bean的定义元信息,比如修改Bean的属性、作用域。执行时机早于所有Bean的创建。2.BeanPostProcessor(Bean后置处理器):作用于Bean实例化之后,在每个Bean初始化前后执行,用于对已生成的Bean对象做增强、修改、代理,AOP、注解注入都是靠它实现的。核心区别:一个操作Bean定义,一个操作Bean实例;工厂后置处理器全局执行一次,Bean后置处理器每个Bean都会执行一次。2.Spring的事件监听机制原理?Spring事件机制是典型的观察者模式,核心四要素:事件、事件发布器、事件监听器、事件广播器。流程:自定义事件继承ApplicationEvent,通过ApplicationContext.publishEvent发布事件,容器中所有实现ApplicationListener的监听器会自动监听并处理事件。默认是同步执行,发布事件后会阻塞等待所有监听器执行完毕;可以通过@Async实现异步事件监听,解耦业务逻辑。3.@Autowired和@Resource的底层源码区别?1.来源不同:@Auto
温馨提示
- 1. 本站所有资源如无特殊说明,都需要本地电脑安装OFFICE2007和PDF阅读器。图纸软件为CAD,CAXA,PROE,UG,SolidWorks等.压缩文件请下载最新的WinRAR软件解压。
- 2. 本站的文档不包含任何第三方提供的附件图纸等,如果需要附件,请联系上传者。文件的所有权益归上传用户所有。
- 3. 本站RAR压缩包中若带图纸,网页内容里面会有图纸预览,若没有图纸预览就没有图纸。
- 4. 未经权益所有人同意不得将文件中的内容挪作商业或盈利用途。
- 5. 人人文库网仅提供信息存储空间,仅对用户上传内容的表现方式做保护处理,对用户上传分享的文档内容本身不做任何修改或编辑,并不能对任何下载内容负责。
- 6. 下载文件中如有侵权或不适当内容,请与我们联系,我们立即纠正。
- 7. 本站不保证下载资源的准确性、安全性和完整性, 同时也不承担用户因使用这些下载资源对自己和他人造成任何形式的伤害或损失。
最新文档
- 2026及未来5年中国OPP薄膜市场现状数据分析及前景预测报告
- 2026年中级经济师资格考试(农业经济专业知识和实务)历年试题及答案
- 电击伤的急救与护理
- 2026年无人机操控员执照考试题库(含答案)
- 2026年企业年金管理人全真模拟题及答案详解
- 2026年肺水肿模拟试卷(含答案)
- 2026年工地安全证模拟试题(含答案)
- 2026年旅行用品模拟题及答案详解
- 月嫂考试填空题及答案详解
- 2026年水电考模拟题题及答案详解
- 烟草专卖局(公司)招聘考试试题题库(含答案)
- 6.4民生福祉持续增进 议题式教学课件(共24张)+内嵌视频 2026-2027学年统编版道德与法治9年级上册
- 2026年多旋翼无人机超视距驾驶员执照考试题库(新版)
- 旧房翻新施工方案模板(3篇)
- 2026安徽日报报业集团招聘工作人员专业测试及有关工作笔试历年常考点试题专练附带答案详解
- 2026年生物实验室风险评估与风险控制
- 2026年宁波市海曙区社区工作者招聘考试真题(附答案)
- 心内科冠脉介入治疗进展汇报
- 多胎妊娠孕妇的营养需求与补充策略
- 2025党课结业考试题及答案
- 牧羊少年奇幻之旅
评论
0/150
提交评论