Spring相关面试题
1.什么是 Spring Bean?作用域有哪些?
Bean 代指的就是那些被 IoC 容器所管理的对象。
Bean 的作用域通常有下面几种:
作用域 | 描述 |
---|---|
singleton |
容器中唯一的 Bean 实例(默认)。 |
prototype |
每次获取都会创建新实例。 |
request |
每次 HTTP 请求创建新实例(仅 Web 应用)。 |
session |
每次 HTTP Session 创建新实例(仅 Web 应用)。 |
application/global-session |
每个 Web 应用启动时创建一个实例(仅 Web 应用)。 |
websocket |
每次 WebSocket 会话创建新实例(仅 Web 应用)。 |
singleton
(最常用,默认的作用域)和prototype
这两个作用域是相对用的多点的,其他的基本不会用到。
2.谈谈你对 Spring IoC 的理解
① IoC(Inversion of Control,控制反转)是一种设计思想,而非具体的技术实现。
② IoC的核心在于“控制反转”,即将对象的创建和管理权从应用程序代码中转移到外部容器(如 Spring IoC 容器)中,这样应用程序只需关注业务逻辑,而无需关心对象的创建和管理。
③ IoC 使得对象之间的耦合度降低。
3.IoC 和 DI 有区别吗?
IoC最常见以及最合理的实现方式叫做依赖注入(Dependency Injection,简称 DI)。DI 通过将对象的依赖关系注入到对象内部来实现控制反转。
换句话说,DI 是一种实现 IoC 的技术,它通过构造函数注入、setter方法注入或字段注入等方式,将所需的依赖对象传递给需要它们的组件。
4.Bean 是线程安全的吗?
在 Spring 中,默认的 Singleton Bean 不是线程安全的。这是因为单例模式下,所有线程共享同一个 Bean 实例。如果 Bean 有可变状态,就需要自行管理线程安全。
- 无状态 Bean(如大部分 Service、Dao)通常是线程安全的。
- 有状态 Bean 需要通过同步机制、ThreadLocal 等方式来确保线程安全。
5.Spring Bean 的生命周期说一下
① 整体上可以简单分为四步:实例化 –> 属性赋值 –> 初始化 –> 销毁。
② 初始化这一步涉及到的步骤比较多,包含 Aware 接口的依赖注入、BeanPostProcessor 在初始化前后的处理以及 InitializingBean 和 init-method 的初始化步骤。
③ 销毁这一步会注册相关销毁回调接口,最后通过 DisposableBean 和 destroy-method 进行销毁。
6. BeanDefinition 的作用?其中的懒加载是什么?
- BeanDefinition 是 Spring 框架中用于描述和封装一个 Bean 的元信息的重要概念。它包含了 Spring 容器在创建 Bean 实例时所需要的全部信息。
- 一个 Bean 所创建过程中所需要的一些信息都可以从 BeanDefinition 中获取,比如这个 Bean 的 Class 类型、作用域、懒加载(Lazy Initialization)等等。其中,懒加载决定该 Bean 是否应当延迟加载。如果设置为懒加载,则该Bean 只有在第一次被请求时才会实例化,而不是在容器启动时立即创建。
7.注入 Bean 的方式有哪些?你的项目是构造函数注入还是 Setter 注入?
1️⃣ 依赖注入(Dependency Injection,DI)的常见方式:
- 构造函数注入:通过类的构造函数来注入依赖项。
- Setter 注入:通过类的 Setter 方法来注入依赖项。
- Field(字段)注入:直接在类的字段上使用注解(如 @Autowired 或 @Resource)来注入依赖项。
2️⃣ Spring 官方推荐构造函数注入,这种注入方式的优势如下:
- 依赖完整性:确保所有必需依赖在对象创建时就注入,避免了空指针异常的风险。
- 不可变性:有助于创建不可变对象,提高了线程安全性。
- 初始化保证:组件在使用前已完全初始化,减少了潜在的错误。
- 测试便利性:在单元测试中,可以直接通过构造函数传入模拟的依赖项,而不必依赖 Spring 容器进行注入。