Bean 作用域有哪些?如何答出技术深度?

导语:
Spring 面试绕不开 Bean 的作用域问题,这是面试官考察候选人对 Spring 框架理解深度的常见方式。本文将围绕“Spring 中的 Bean 作用域”展开,结合典型面试题及实战场景,帮你厘清重点,打破模板式回答,从容应对高阶提问。


一、面试主题概述

在 Spring 中,Bean 的作用域(Scope)定义了 Spring 容器中 Bean 的生命周期与访问范围。这是核心的 IOC 容器设计之一,对资源管理、线程安全及系统性能均有重要影响。

面试中,关于 Bean Scope 的问题,不仅会考基础定义,还可能深入追问其实际应用场景、多线程场景下的表现,甚至设计模式的关联。


二、高频面试题汇总

  1. Spring 中的 Bean 作用域有哪些?默认作用域是什么?
  2. singleton 和 prototype 有哪些区别?分别适合什么场景?
  3. request 和 session 作用域的底层实现原理是什么?
  4. 如果在 prototype Bean 中注入 singleton Bean,有什么需要注意的?
  5. 多线程环境下使用 request 或 session scope 的 Bean,会有什么问题?

三、重点题目详解

1️⃣ Spring 中的 Bean 作用域有哪些?

答:

Spring 支持以下 5 种主要作用域:

作用域 说明 适用场景
singleton 默认作用域,全容器中只创建一个 Bean 实例 大多数无状态服务类,如 DAO、Service
prototype 每次获取都会创建新的 Bean 实例 有状态对象,如自定义线程任务
request 每次 HTTP 请求创建一个新的 Bean,只在当前请求内有效(仅限 Web 应用) Controller 层的临时对象
session 每个 HTTP Session 创建一个 Bean 实例 与用户登录态、购物车状态相关的数据
application 每个 ServletContext 创建一个 Bean 实例 Web 应用级共享资源,如配置缓存等

2️⃣ singleton 和 prototype 有哪些区别?

@Component
@Scope("singleton") // 默认是 singleton,也可以省略
public class SingletonBean {
    public SingletonBean() {
        System.out.println("创建 Singleton Bean");
    }
}

@Component
@Scope("prototype")
public class PrototypeBean {
    public PrototypeBean() {
        System.out.println("创建 Prototype Bean");
    }
}

测试代码:

@SpringBootApplication
public class ScopeDemo implements CommandLineRunner {

    @Autowired
    private ApplicationContext context;

    public static void main(String[] args) {
        SpringApplication.run(ScopeDemo.class, args);
    }

    @Override
    public void run(String... args) {
        context.getBean(SingletonBean.class);
        context.getBean(SingletonBean.class);

        context.getBean(PrototypeBean.class);
        context.getBean(PrototypeBean.class);
    }
}

输出:

创建 Singleton Bean
创建 Prototype Bean
创建 Prototype Bean

解析:

  • singleton:容器启动时创建一次,之后每次注入或获取都是同一个实例。
  • prototype:每次调用 getBean() 都是新实例,生命周期不受容器管理,Spring 仅负责创建,销毁需手动处理。

常见误区: Prototype Bean 并不会像 Singleton 那样自动执行 @PreDestroy 等生命周期方法。


3️⃣ request 和 session 的实现机制

这些作用域依赖于 WebApplicationContext,并通过底层的 RequestContextHolder 维护线程上下文。

底层实现简析:

Spring 使用 ThreadLocal 维护每个线程对应的请求或会话对象,从而在非 Controller 中也能访问请求作用域 Bean。例如:

RequestAttributes requestAttributes = RequestContextHolder.getRequestAttributes();
HttpServletRequest request = ((ServletRequestAttributes) requestAttributes).getRequest();

面试官为什么爱问这个?

  • 考察对 Spring 与 Servlet 容器的理解
  • 是否具备 Web 环境下的线程模型意识
  • 是否能够区分请求级状态与全局状态

4️⃣ prototype Bean 中注入 singleton Bean 的问题

场景:

@Component
@Scope("prototype")
public class TaskHandler {
    @Autowired
    private LoggerService loggerService; // singleton Bean
}

问题解析:

这是合法且常见的组合,singleton Bean 可以安全注入到 prototype Bean 中,因为它是无状态的。

但反过来若在 singleton Bean 中注入 prototype Bean,则只有第一次注入有效,后续不会重新创建实例,此时应使用 @LookupObjectFactory 获取:

@Component
public class TaskManager {

    @Lookup
    public TaskHandler getTaskHandler() {
        return null; // 由 Spring 动态实现
    }
}

四、面试官视角与加分项

面试官通常关注的不是你是否背过定义,而是:

  • 是否理解不同作用域的设计动机与应用边界
  • 能否通过实例解释作用域对系统行为的影响
  • 能否发现作用域使用不当引发的线程安全、资源浪费等问题

加分项建议:

  • 结合实际项目场景举例说明,比如电商系统中的购物车 session 管理。
  • 能提及 Spring Boot 中通过注解 @Scope、配置文件等方式灵活配置作用域。
  • 理解作用域与设计模式之间的关系,如 Singleton 模式、Factory 模式。

五、总结与建议

Spring 中的 Bean 作用域虽为基础知识点,但蕴含的设计哲学、线程模型和容器管理机制非常丰富。建议在面试中做到以下几点:

  • 基础熟记:掌握每种作用域的定义、特性与生命周期。
  • 深入理解:理解作用域的底层原理、适用场景及组合方式。
  • 实战经验:结合项目使用场景,自信地举出具体案例。

面试不怕问到基础,怕的是“只会背书,不懂变通”。理解 Bean 作用域的真正用意,你就能在细节中脱颖而出。

你可能感兴趣的:(常用框架面试,spring,java)