Spring面试题小结
面试题来源:https://blog.csdn.net/v123411739/article/details/110009966
Spring源码:https://javadoop.com/post/spring-ioc
IOC容器初始化过程?
BeanFactory(常用ClassPathXmlApplicationContext)初始化,调用refresh——加载Spring配置,解析成bean对象并注册到BeanDefinition(注册中心)——调用BeanFactoryPostProcessor(前提是实现了这个接口)实例化和使用——调用BeanPostProcessor两个方法(PostProcessBeforeInitialization和PostProcessAfterInitialization)分别在bean初始化前后调用——实例化所有bean——FinishRefresh广播,通知所有监听器完成refresh
tips:结合上面第二篇文章的源码看
Bean生命周期?
Bean的生命周期可以先分为几大部分:1)实例化初始化2)使用3)销毁,其中实例化初始化可分为1)实例化(instantiation)2)属性填充(populate)3初始化(initialize)。
在实例化和初始化时都有一个切面方法,分为在切面前后进行预(后)处理,分别=、为InstantiationAwareBeanPostProcessor和BeanPostProcessor的xxxbeforexxx和xxxafterxxx方法。剩余一些细节:1)实例化后,属性填充前,MergedBeanDefinitionPostProcessor修改合并bean定义,曝光objectFactory,解决循环引用(待消化)。2)初始化前,BeanFactoryAware,BeanNameAware,BeanClassLoaderAware(如果实现,invoke方法)。3)销毁阶段,DestructionAwareBeanPostProcessor有个beforeDestruction方法,然后destory-method。
BeanFactory 和 FactoryBean 的区别?
BeanFactory是IOC容器的基类,常用的ClassPathXmlApplicationContext是它的一个具体实现。
FactoryBean是是一种工厂bean,可以自实现getObject方法,自定义要创建的的Object实例。中间件源码大量使用FactoryBean。
一般来说,都是通过 FactoryBean#getObject 来返回一个代理类,当我们触发调用时,会走到代理类中,从而可以在代理类中实现中间件的自定义逻辑,比如:RPC 最核心的几个功能,选址、建立连接、远程调用,还有一些自定义的监控、限流等等。(待消化)
BeanFactory 和 ApplicationContext 的区别?
BeanFactory是IOC的基类,基础容器;ApplicationContext是BeanFactory的高级实现,高级容器。BeanFactory实现了基础功能(可以类比成座机),ApplicationContext有更多拓展功能(类比为智能手机)。
Spring 的 AOP 是怎么实现的?
本质是动态代理,1)获得增强器例如@Aspect注解。2)创建实例时,通过判断是否包含在execution中,确定是否需要增强器,增强器作为参数传递,通过动态代理完成增强。3)当调用这个实例的时候,走增强器。
Spring 的 AOP 有哪几种创建代理的方式?
JDK的动态代理和Cglib动态代理。
JDK 动态代理和 Cglib 代理的区别?
1)JDK动态代理通过接口实现,Cglib通过继承实现。
2)JDK动态代理只能通过接口实现,因为底层是继承了Proxy类,无法多继承;Cglib没有要求,但是Cglib通过继承实现,无法代理final修饰的类。
3)JDK动态代理通过反射实现调用,Cglib通过FastClass机制调用。
4)JDK1.7以前效率慢于Cglib,1.7以后反之。
JDK 动态代理为什么只能对实现了接口的类生成代理?
因为底层是继承了Proxy类,无法多继承。
Spring 的事务传播行为有哪些?
1)Required Spring默认传播级别,如果上下文有事务,就加入到事务当中,如果没有事务,就新建事务。
2)Requires_New 每次都会新建一个事务,如果上下文有事务,则会将事务挂起,当前事务完成后,上下文事务再恢复执行。
3)Supports 如果上下文存在事务,则加入事务,如果没有事务,则按非事务执行。
4)Not_supported 如果上下文存在事务,则挂起事务,执行完当前逻辑后,上下文事务再恢复执行。
5)Mandatory 上下文必须存在事务,不然会抛出异常。
6)Never 上下文不能存在事务,不然会抛出异常。
7)Nested 嵌套事务,上下文存在事务则嵌套执行,不存在则新建事务。
Spring 的事务隔离级别?
Spring的事务隔离级别是基于数据库的隔离级别,不存在自己的一套隔离级别。
Default:数据库默认隔离级别。
Read_Uncommited:读未提交,会读到其他事务还未提交的内容,存在脏读。
Read_Commited:读已提交,会读到其他事务已提交的内容,存在不可重复读。
Repeatable_Read:可重复度,每次读取一条记录的内容是一样的,但是存在幻读。
Serialization:串行化,最高隔离级别,每一条数据读写都上锁,只有读读可以并行。其他操作如读写,写读,写写,都不能并发操作。解决脏读,不可重复读,幻读。
Spring 的事务隔离级别是如何做到和数据库不一致的?
本质还是通过数据库命令来控制,在执行前修改数据库隔离级别,例如下面命令。
SET SESSION TRANSACTION ISOLATION LEVEL READ COMMITTED
Spring 事务的实现原理?
AOP(动态代理)+ThreadLocal+Try/Catch
AOP用于逻辑增强,ThreadLocal用于线程资源隔离(不同线程不同dataSource、connection等),Try/Catch用于rollback和commit。
Spring 怎么解决循环依赖的问题?
每个对象实例化后,将ObjectFactory曝光到缓存中,每次实例前到缓存里检查是否存在。
A依赖B,B依赖A,那么创建对象的过程如下:
1)A开始创建前,到缓存中检查是否存在ObjectFactory,不存在,则调用构造方法创建对象,然后把A的ObjectFactory曝光
2)A创建后,进行属性填充,发现B,即将实例化B
3)B开始创建前,先到缓存中检查是否存在ObjectFactory,不存在,则调用构造方法创建对象,然后把B的ObjectFactory曝光
4)B创建后,进行属性填充,发现A,即将实例化A
5)A开始创建前,先到缓存中检查是否存在ObjectFactory,存在,则获得ObjectFactory,由此获得A的bean
6)B进行其他属性填充和初始化
7)A进行其他属性填充和初始化
Spring 能解决构造函数循环依赖吗?
不行,Spring通过分解创建过程,在其中增加到缓存中的可见性(类似volatile),来解决循环依赖问题,但是构造函数中是其中一个单元,没有分解。
Spring 三级缓存?
Spring解决循环依赖用到的就是三级缓存。
一级缓存SingletonObjects,对象创建完毕(实例化、注入,初始化)后会放到该缓存,key:beanName value:bean实例。
二级缓存earlySingletonObjects,从ObjectFactory返回的bean会放到该缓存(实例化),ObjectFactory只会调用一次,然后从earlySingletonObjects里面获得,key:beanName value:早期bean实例。
三级缓存SingletonFactories,对象实例化后会把ObjectFactory放到该缓存(曝光),key:beanName value:ObjectFactory。
Tips:为什么使用三级缓存而不是一级二级? https://www.zhihu.com/question/445446018
@Resource 和 @Autowire 的区别?
Autowired按类型装配,默认要求依赖对象必须存在。
Resource可以按名称或类型装配,默认使用名称,名称装配失败则使用类型,也可以指定按名称或类型。
@Autowire 怎么使用名称来注入?
搭配Qualifier使用
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· TypeScript + Deepseek 打造卜卦网站:技术与玄学的结合
· Manus的开源复刻OpenManus初探
· AI 智能体引爆开源社区「GitHub 热点速览」
· 从HTTP原因短语缺失研究HTTP/2和HTTP/3的设计差异
· 三行代码完成国际化适配,妙~啊~