Spring面试题(一)

发布于 2025-09-25 17:39:47 浏览 85 次

1.什么是循环依赖?

循环依赖指两个或多个 Bean 之间相互依赖形成闭环的情况。例如,Bean A 依赖 Bean B,而 Bean B 同时依赖 Bean A,这种相互引用的关系即为循环依赖。

2.Spring 如何解决循环依赖?

Spring 通过三级缓存机制解决单例 Bean 的循环依赖:
一级缓存(singletonObjects):存储完全初始化完成的 Bean。
二级缓存(earlySingletonObjects):存储提前暴露的、未完全初始化的 Bean 实例。
三级缓存(singletonFactories):存储 Bean 的工厂对象,用于在需要时创建提前暴露的实例。
流程:当创建 Bean A 时,先将其工厂放入三级缓存,若此时依赖 Bean B,创建 Bean B 时发现依赖 A,便从三级缓存获取 A 的提前暴露实例,放入二级缓存,完成 B 的初始化后,A 可继续依赖 B 完成初始化,最终存入一级缓存。

3.为什么 Spring 循环依赖需要三级缓存,二级不够吗?

不够。三级缓存的核心作用是处理 Bean 的动态代理场景:若 Bean 需要被代理,三级缓存中的工厂会生成代理对象而非原始对象。若仅用二级缓存,无法延迟生成代理对象(需在初始化前确定是否代理),可能导致循环依赖时注入的是原始对象而非代理对象,破坏代理逻辑。三级缓存通过工厂延迟创建代理对象,确保注入的是正确的代理实例。

4.看过源码吗?说下 Spring 由哪些重要的模块组成?

Spring 核心模块包括:
Spring Core:核心容器,实现 IOC 容器功能,包括 BeanFactory、ApplicationContext 等。
Spring AOP:面向切面编程,提供动态代理、通知、切点等功能。
Spring Context:基于 Core 模块,扩展了国际化、事件传播、资源加载等功能。
Spring DAO/ORM:数据访问模块,整合 JDBC、MyBatis、Hibernate 等持久层框架。
Spring Web:Web 应用支持,包括 Spring MVC、WebSocket 等。
Spring Test:测试支持,整合 JUnit 等测试框架。

5.什么是 Spring IOC?

IOC(Inversion of Control,控制反转)是 Spring 的核心思想,指将对象的创建、依赖管理等控制权从业务代码转移到 Spring 容器,由容器统一管理对象的生命周期和依赖关系,而非手动通过new创建对象。

6.Spring IOC 有什么好处?

降低代码耦合度:对象依赖由容器管理,减少硬编码依赖。
提高代码复用性:容器可复用对象实例(如单例 Bean)。
便于测试:依赖注入使 Mock 对象替换更简单。
集中管理:对象的创建、初始化、销毁等统一由容器控制,便于配置和维护。

7.Spring 中的 DI 是什么?

DI(Dependency Injection,依赖注入)是 IOC 的具体实现方式,指容器在创建对象时,自动将其依赖的其他对象注入到该对象中,无需手动调用setter或构造方法设置依赖。常见方式有构造器注入、setter 注入、字段注入。

8.什么是 Spring Bean?

Spring Bean 是由 Spring IOC 容器管理的对象,是应用程序的组件。Bean 的创建、初始化、依赖注入、销毁等过程均由容器控制,开发者通过配置(XML、注解)定义 Bean 的类型、依赖关系和生命周期。

9.Spring 中的 BeanFactory 是什么?

BeanFactory 是 Spring IOC 容器的顶层接口,提供了获取 Bean、判断 Bean 是否存在等基础功能,是 Spring 容器的核心。它采用懒加载模式(获取 Bean 时才创建),适合资源有限的场景,常见实现类有DefaultListableBeanFactory。

10.Spring 中的 FactoryBean 是什么?

FactoryBean 是一个工厂 Bean 接口,用于创建复杂或特殊的 Bean。实现该接口的类可自定义 Bean 的创建逻辑,容器通过getObject()方法获取其创建的 Bean 实例。例如,MyBatis 的SqlSessionFactoryBean用于创建SqlSessionFactory。

11.Spring 中的 ObjectFactory 是什么?

ObjectFactory 是一个函数式接口,用于延迟获取 Bean 实例,定义了getObject()方法。它通常用于循环依赖场景,作为三级缓存的存储对象,在需要时创建 Bean 的早期实例,避免提前初始化。

12.Spring 中的 ApplicationContext 是什么?

ApplicationContext 是 BeanFactory 的子接口,扩展了更多功能,是更完整的 IOC 容器实现。它在容器启动时预加载所有单例 Bean,支持国际化、事件发布、资源加载等,常见实现类有ClassPathXmlApplicationContext、AnnotationConfigApplicationContext。

13.Spring Bean 一共有几种作用域?

共 6 种作用域:
singleton:单例,容器中仅一个实例(默认)。
prototype:原型,每次获取都创建新实例。
request:Web 环境中,每个请求对应一个实例。
session:Web 环境中,每个会话对应一个实例。
application:Web 环境中,整个应用生命周期一个实例。
websocket:Web 环境中,每个 WebSocket 会话对应一个实例。

14.Spring 一共有几种注入方式?

主要有 3 种:
构造器注入:通过构造方法参数注入依赖,适合必填依赖。
setter 注入:通过setter方法注入依赖,适合可选依赖。
字段注入:直接在字段上用@Autowired注解注入,简洁但不利于测试。

15.什么是 AOP?

AOP(Aspect-Oriented Programming,面向切面编程)是一种编程范式,通过将横切关注点(如日志、事务、权限)从业务逻辑中分离,实现代码解耦。核心思想是 “横向抽取”,在不修改原有代码的情况下增强功能。

16.Spring AOP 默认用的是什么动态代理,两者的区别?

Spring AOP 默认根据目标类是否实现接口选择代理方式:
若目标类实现接口,使用JDK 动态代理(基于接口生成代理类)。
若未实现接口,使用CGLIB 动态代理(基于继承生成目标类的子类)。
区别:JDK 代理只能代理接口方法,CGLIB 可代理类方法;JDK 代理效率在调用次数多时更高,CGLIB 在创建代理时开销更大。

17.能说说 Spring 拦截链的实现吗?

Spring AOP 的拦截链通过MethodInterceptor接口实现,多个拦截器(通知)按顺序组成链。当目标方法被调用时,拦截器链依次执行:先执行前置通知,再执行目标方法,最后执行后置通知、异常通知或最终通知。拦截链的顺序由通知的优先级(如@Order注解)或配置顺序决定。

18.Spring AOP 和 AspectJ 有什么区别?

实现方式:Spring AOP 基于动态代理(运行时增强),AspectJ 基于字节码编织(编译期或类加载期增强)。
功能范围:AspectJ 支持更多切点表达式和通知类型,功能更全面;Spring AOP 更轻量,集成于 Spring 生态。
适用场景:Spring AOP 适合简单的横切逻辑,AspectJ 适合复杂的切面需求(如私有方法增强)。

19.说下 Spring Bean 的生命周期?

实例化:容器通过构造方法创建 Bean 实例。
属性注入:容器将依赖的 Bean 注入到当前 Bean 的字段或 setter 方法。
初始化前:执行BeanPostProcessor的postProcessBeforeInitialization方法(前置处理)。
初始化:执行@PostConstruct注解方法、InitializingBean的afterPropertiesSet方法、自定义初始化方法。
初始化后:执行BeanPostProcessor的postProcessAfterInitialization方法(后置处理,如生成代理)。
使用:Bean 可被应用程序使用。
销毁:容器关闭时,执行@PreDestroy注解方法、DisposableBean的destroy方法、自定义销毁方法。

20.说下对 Spring MVC 的理解?

Spring MVC 是 Spring 框架的 Web 模块,基于 MVC(Model-View-Controller)模式,用于开发 Web 应用。它通过 DispatcherServlet(前端控制器)统一处理请求,将请求分发给对应的处理器(Controller),并通过视图解析器返回页面或数据,简化了 Web 层的开发,支持 RESTful 风格接口。

21.Spring MVC 具体的工作原理?

客户端发送请求至 DispatcherServlet。
DispatcherServlet 根据请求 URL 调用 HandlerMapping,获取对应的 Handler(Controller 方法)。
HandlerMapping 返回 HandlerExecutionChain(包含 Handler 和拦截器)。
DispatcherServlet 通过 HandlerAdapter 调用 Handler 处理请求。
Handler 执行完成后返回 ModelAndView(数据模型和视图名)。
DispatcherServlet 将 ModelAndView 交给 ViewResolver 解析,得到具体 View。
View 渲染模型数据,生成响应返回客户端。

22.SpringMVC 父子容器是什么知道吗?

Spring MVC 中存在两个容器:
父容器:由 ContextLoaderListener 初始化,管理 Service、Dao 等业务层 Bean。
子容器:由 DispatcherServlet 初始化,管理 Controller、ViewResolver 等 Web 层 Bean。
关系:子容器可访问父容器的 Bean,父容器不能访问子容器的 Bean,实现了分层隔离。

23.你了解的 Spring 都用到哪些设计模式?

工厂模式:BeanFactory、FactoryBean 创建 Bean。
单例模式:默认的 Bean 作用域(singleton)。
代理模式:AOP 的动态代理(JDK/CGLIB)。
观察者模式:事件监听机制(ApplicationEvent、ApplicationListener)。
模板方法模式:JdbcTemplate、TransactionTemplate 等模板类。
适配器模式:HandlerAdapter 适配不同的 Handler。

24.Spring 事务有几个隔离级别?

基于数据库隔离级别,Spring 定义了 5 种:
DEFAULT:默认,使用数据库的隔离级别。
READ_UNCOMMITTED:读未提交,允许脏读。
READ_COMMITTED:读已提交,防止脏读,允许不可重复读和幻读。
REPEATABLE_READ:可重复读,防止脏读、不可重复读,允许幻读。
SERIALIZABLE:串行化,最高隔离级别,防止所有并发问题,但性能低。

25.Spring 有哪几种事务传播行为?

共 7 种,定义了事务方法调用另一个事务方法时的行为:
REQUIRED:默认,若当前有事务则加入,否则新建。
SUPPORTS:若当前有事务则加入,否则以非事务执行。
MANDATORY:必须在事务中执行,否则抛异常。
REQUIRES_NEW:新建事务,若当前有事务则挂起。
NOT_SUPPORTED:以非事务执行,若当前有事务则挂起。
NEVER:必须以非事务执行,否则抛异常。
NESTED:若当前有事务,则嵌套在当前事务中执行(保存点机制)。

26.Spring 事务传播行为有什么用?

用于控制多个事务方法之间的交互方式,解决复杂业务场景中的事务管理问题。例如:
调用方和被调用方共用一个事务(REQUIRED)。
被调用方需要独立事务(REQUIRES_NEW),即使失败也不影响调用方事务。
禁止在事务中执行(NEVER),避免误操作。

27.Spring 的优点

轻量:核心包体积小,无侵入性。
松耦合:IOC 和 DI 降低组件依赖。
扩展性强:支持多种框架整合(MyBatis、Hibernate 等)。
AOP 支持:方便实现日志、事务等横切功能。
事务管理:简化数据库事务操作,支持声明式事务。
一站式:提供 Web、数据访问等全方位支持。

28.Spring AOP 相关术语都有哪些?

切面(Aspect):封装横切关注点的类(如日志切面)。
连接点(Joinpoint):程序执行过程中可被增强的点(如方法调用、字段赋值)。
切点(Pointcut):通过表达式指定的具体连接点(如所有service包下的方法)。
通知(Advice):切面的具体增强逻辑(如前置通知、后置通知)。
目标对象(Target):被增强的对象。
代理(Proxy):AOP 为目标对象创建的代理对象。
织入(Weaving):将切面应用到目标对象并创建代理的过程。

29.Spring 通知有哪些类型?

前置通知(Before):目标方法执行前执行。
后置通知(After):目标方法执行后(无论是否异常)执行。
返回通知(AfterReturning):目标方法正常返回后执行。
异常通知(AfterThrowing):目标方法抛出异常后执行。
环绕通知(Around):包裹目标方法,可自定义执行逻辑(如控制是否执行目标方法)。

30.Spring IOC 容器初始化过程?

资源定位:读取配置文件(XML / 注解),定位 Bean 定义信息。
BeanDefinition 载入:将配置信息解析为BeanDefinition对象(包含 Bean 的类名、属性、依赖等)。
BeanDefinition 注册:将BeanDefinition存入BeanDefinitionRegistry(如DefaultListableBeanFactory)。
初始化容器:执行refresh()方法,初始化 BeanFactory、注册 BeanPostProcessor、初始化事件机制等。
Bean 实例化:对单例 Bean(非懒加载)进行实例化、属性注入、初始化,存入一级缓存。
容器就绪:IOC 容器初始化完成,可对外提供 Bean 服务。

0 条评论

发布
问题