跳到主要内容
极客日志极客日志面向AI+效率的开发者社区
首页博客我的书AI学习GitHub 精选镜像AI 生图工具UI配色美学关于
搜索内容 / 工具 / 仓库 / 镜像...⌘K搜索
注册
博客列表
Javajava

Spring Bean 作用域、生命周期与自动装配源码解析

Spring Bean 作用域定义了实例的生命周期范围,包括单例、原型及 Web 相关作用域。生命周期涵盖实例化、属性赋值、初始化回调及销毁等关键阶段,其中 BeanPostProcessor 的处理顺序易产生混淆。自动装配通过约定优于配置原则,利用 @EnableAutoConfiguration 扫描并加载第三方依赖的配置类,简化了容器管理流程。

赛博朋克发布于 2026/3/25更新于 2026/10/2285 浏览
Spring Bean 作用域、生命周期与自动装配源码解析

SpringBoot 版本: 3.5.8

Bean 的作用域

Spring Bean 的作用域决定了实例在哪些上下文中可用。理解不同作用域的行为,尤其是 Web 环境下的 Request 和 Session,对于避免状态污染至关重要。

/**
 * 实体类
 */
public class Dog {}

/**
 * 配置类
 */
@Configuration
public class DogConfig {
    // 单例:容器启动时创建,全局共享
    @Bean
    @Scope(ConfigurableBeanFactory.SCOPE_SINGLETON)
    public Dog singleDog() {
        return new Dog();
    }

    // 原型:每次请求都创建新实例
    @Bean
    @Scope(ConfigurableBeanFactory.SCOPE_PROTOTYPE)
    public Dog prototypeDog() {
        return new Dog();
    }

    // 请求:每个 HTTP 请求创建一个新实例
    @Bean
    @RequestScope
    public Dog requestDog() {
        return new Dog();
    }

    // 会话:每个用户会话创建一个新实例
    @Bean
    @SessionScope
    public Dog sessionDog() {
        return new Dog();
    }

    
    
    
     Dog  {
          ();
    }
}



   {
        {
        SpringApplication.run(SpringPrincipleApplication.class, args);
    }
}




   {
      Dog single;
      Dog prototype;
      Dog request;
      Dog session;
      Dog application;
      ApplicationContext context;

      {
        .single = single;
        .prototype = prototype;
        .request = request;
        .session = session;
        .application = application;
        .context = context;
    }

    
     String  {
           (Dog) context.getBean();
          + .single.toString() +  +  + singleDog;
    }

    
     String  {
           (Dog) context.getBean();
          + .prototype.toString() +  +  + prototypeDog;
    }

    
     String  {
           (Dog) context.getBean();
          + .request.toString() +  +  + requestDog;
    }

    
     String  {
           (Dog) context.getBean();
          + .session.toString() +  +  + sessionDog;
    }

    
     String  {
           (Dog) context.getBean();
          + .application.toString() +  +  + applicationDog;
    }
}
// 应用:整个 Web 应用共享一个实例
@Bean
@ApplicationScope
public
applicationDog
()
return
new
Dog
/** * 启动类 */
@SpringBootApplication
public
class
SpringPrincipleApplication
public
static
void
main
(String[] args)
/** * 视图层 */
@RequestMapping("/test")
@RestController
public
class
TestController
private
final
private
final
private
final
private
final
private
final
private
final
public
TestController
(@Qualifier("singleDog") Dog single, @Qualifier("prototypeDog") Dog prototype, @Qualifier("requestDog") Dog request, @Qualifier("sessionDog") Dog session, @Qualifier("applicationDog") Dog application, ApplicationContext context)
this
this
this
this
this
this
@RequestMapping("/single")
public
single
()
Dog
singleDog
=
"singleDog"
return
"dog: "
this
"<br>"
"contextDog: "
@RequestMapping("/prototype")
public
prototype
()
Dog
prototypeDog
=
"prototypeDog"
return
"dog: "
this
"<br>"
"contextDog: "
@RequestMapping("/request")
public
request
()
Dog
requestDog
=
"requestDog"
return
"dog: "
this
"<br>"
"contextDog: "
@RequestMapping("/session")
public
session
()
Dog
sessionDog
=
"sessionDog"
return
"dog: "
this
"<br>"
"contextDog: "
@RequestMapping("/application")
public
application
()
Dog
applicationDog
=
"applicationDog"
return
"dog: "
this
"<br>"
"contextDog: "

直接通过 context.getBean() 获取会触发新实例创建(针对非单例)。这里有个常见的坑:当使用 @Autowired 或 @Resource 注入 Prototype 作用域的 Bean 时,注入操作仅在容器初始化阶段执行一次。后续通过字段引用访问的始终是最初注入的那个实例,不会随请求变化而自动更新。

对于 Request 作用域,Spring 实际上注入的是一个代理对象而非真实实例。这个代理对象在应用启动时就被注入到依赖它的单例 Bean 中,但真实实例的创建被延迟到了 HTTP 请求发生时。代理对象内部持有对当前 HTTP 请求上下文的引用,调用方法时会从上下文中查找或创建新的真实实例。这种延迟查找机制确保了每个请求线程都能获得独立的实例。

  • Singleton(单例):默认作用域,每个 Spring 容器中仅存在一个 Bean 实例。
  • Prototype(原型):每次请求 Bean 时都会创建一个新的实例。
  • Request(请求):每个 HTTP 请求创建一个新的 Bean 实例,仅在 Web 应用中有效。
  • Session(会话):每个用户会话创建一个 Bean 实例,仅在 Web 应用中有效。
  • Application(应用):整个 Web 应用共享一个 Bean 实例。

Bean 的生命周期

Bean 的生命周期指的是对象从创建到销毁的全过程。主要包含五个阶段:

  1. 实例化:容器通过反射调用 Bean 的构造器创建对象实例。
  2. 属性赋值:容器注入依赖的属性值(例如 @Autowired)。
  3. 初始化:
    • 通知方法调用:通过特定接口(如 BeanNameAware)注入框架相关依赖或上下文信息。
    • 前置处理:进行准备工作,例如参数校验、资源加载或权限检查。
    • 初始化回调:在对象初始化阶段触发的自定义逻辑(如实现 InitializingBean 接口的 afterPropertiesSet 方法)。
    • 后置处理:在流程结束后执行清理或结果处理(如 AOP 中的 @After 通知)。
  4. 使用 Bean:Bean 进入就绪状态,可被应用程序调用。
  5. 销毁 Bean:容器关闭时触发销毁。

示例代码

/**
 * 实体类
 */
public class Cat {}

/**
 * 配置类
 */
@Configuration
public class CatConfig {
    @Bean
    public Cat cat() {
        return new Cat();
    }
}

/**
 * 实现类
 */
@Component
@Slf4j
public class BeanLifeComponent implements BeanNameAware, BeanPostProcessor, InitializingBean {
    private Cat cat;

    // 1. 实例化:执行构造方法
    public BeanLifeComponent() {
        log.info("1.实例化:执行构造方法");
    }

    // 2. 属性赋值:执行 setter 方法
    @Autowired
    public void setCat(Cat cat) {
        log.info("2.属性赋值:执行 setter 方法");
        this.cat = cat;
    }

    // 3.1 通知方法调用
    @Override
    public void setBeanName(String name) {
        log.info("3.1 通知方法调用,bean name is {}", name);
    }

    // 3.2 前置处理
    @Override
    public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
        log.info("3.3 前置处理,bean:{},beanName:{}", bean, beanName);
        return BeanPostProcessor.super.postProcessBeforeInitialization(bean, beanName);
    }

    // 3.3 初始化回调
    @Override
    public void afterPropertiesSet() {
        log.info("3.2 初始化回调");
    }

    // 3.4 后置处理
    @Override
    public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
        log.info("3.4 后置处理,bean:{},beanName:{}", bean, beanName);
        return BeanPostProcessor.super.postProcessAfterInitialization(bean, beanName);
    }

    // 4. 使用 Bean
    public void use() {
        log.info("4.使用 Bean");
    }

    // 5. 销毁 Bean
    @PreDestroy
    public void preDestroy() {
        log.info("5.销毁 Bean");
    }
}

/**
 * 测试类
 */
@SpringBootTest
class SpringPrincipleApplicationTests {
    private final ApplicationContext context;

    @Autowired
    public SpringPrincipleApplicationTests(ApplicationContext context) {
        this.context = context;
    }

    @Test
    public void test() {
        BeanLifeComponent beanLifeComponent = context.getBean(BeanLifeComponent.class);
        beanLifeComponent.use();
    }
}

运行日志显示的顺序往往是:invokeInitMethods(初始化回调) -> applyBeanPostProcessorsBeforeInitialization(前置处理) -> applyBeanPostProcessorsAfterInitialization(后置处理)。这看起来似乎与理论流程矛盾,其实关键在于 BeanPostProcessor 本身也是 Bean。

当 Spring 初始化一个 BeanPostProcessor 实现类时,这个过程是递归的。Spring 需要先让这个 BeanPostProcessor 对象本身完成初始化(调用 invokeInitMethods),然后才能将它加入到 BeanPostProcessor 列表中,供后续其他 Bean 使用。但对于这个 BeanPostProcessor Bean 自己来说,它自己的 postProcessBeforeInitialization 和 postProcessAfterInitialization 方法不会在它自己的创建过程中被调用,只会作用于其他 Bean。

因此,日志中显示的前置处理和后置处理,实际上是该组件作为处理器去处理其他 Bean 的过程,或者是自身初始化完成后被注册为处理器后的行为体现。正确的生命周期流程依然是:前置处理 → 初始化回调 → 后置处理。

SpringBoot 自动装配

自动装配的作用是自动注册 Bean 到 Spring 容器,不需要手动配置。通过约定大于配置的方式减少手动配置的复杂性。换言之,Spring Boot 的自动配置就是将依赖 Jar 包中的配置类以及 Bean 加载到 IoC 容器的过程。

SpringBoot 加载 Bean

在 pom.xml 文件中引入第三方依赖,实际上是将第三方代码引入到项目中。Spring Boot 项目在启动时能识别这些依赖并自动将它们的配置类以及 Bean 加载到 IoC 容器。

如果 Bean 所在的包不在启动类的扫描路径下,就需要手动指定扫描范围。

@ComponentScan

告诉 Spring 容器去哪里扫描那些被 @Component、@Service、@Repository、@Controller 等注解标记的类,并将它们自动注册为 Bean。

@SpringBootApplication
@ComponentScan("com.example.springprincicle.component")
public class SpringPrincipleApplication {
    public static void main(String[] args) {
        SpringApplication.run(SpringPrincipleApplication.class, args);
    }
}
@Import

用于将一个或多个配置类、组件类或其他类导入到当前的 Spring 应用上下文中。

用法一:导入单个类

@SpringBootApplication
@Import(TestConfig.class)
public class SpringPrincipleApplication {
    public static void main(String[] args) {
        SpringApplication.run(SpringPrincipleApplication.class, args);
    }
}

用法二:ImportSelector 接口实现类

适合批量导入场景,通常配合自定义注解使用。

public class MyImportSelector implements ImportSelector {
    @Override
    public String[] selectImports(AnnotationMetadata importingClassMetadata) {
        return new String[]{
            "com.example.springprincicle.component.TestConfig",
            "com.example.springprincicle.component.DemoConfig"
        };
    }
}
自定义注解

在使用 @Import 注解导入 Bean 时,需要程序员熟悉第三方依赖的所有配置类,这对开发不友好。所以,应该由依赖的开发者来做这件事。比较常见的方案就是第三方依赖给我们提供一个注解,该注解内部封装了 @Import 注解。

@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.TYPE)
@Import(MyImportSelector.class)
public @interface EnableTestConfig {}

@SpringBootApplication
@EnableTestConfig
public class SpringPrincipleApplication {
    public static void main(String[] args) {
        SpringApplication.run(SpringPrincipleApplication.class, args);
    }
}

@SpringBootApplication 源码解析

这是一个组合注解,包含以下三个核心注解的功能:

@ComponentScan

在 @SpringBootApplication 注解中,如果没有指定扫描路径,那么默认扫描路径为 @SpringBootApplication 标注的类的类路径。排除不需要扫描的配置类,防止自动配置类被重复扫描或注册。

@SpringBootConfiguration

标记该类为 Spring 的配置类。同时支持 @Indexed,为 Spring 的组件扫描提供索引支持,加速应用启动时的类加载过程。

@EnableAutoConfiguration

这是自动装配的核心。AutoConfigurationImportSelector 类实现了 DeferredImportSelector 接口,负责在 Spring 应用启动时动态加载自动配置类。

其核心逻辑在于 getCandidateConfigurations 方法。在 Spring Boot 3.x 中,该方法不仅加载 Spring Boot 默认的自动配置类,还会加载所有第三方库提供的自动配置类。遵循 Spring Boot 的'约定优于配置'理念,第三方依赖库需要将其自动配置类定义在 META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports 文件中,这样 Spring Boot 启动时就能自动发现并加载这些配置。

此外,为了保持向后兼容性,Spring Framework 仍然保留了 spring.factories 的支持,但在 Spring Boot 3.x 中推荐使用 .imports 机制。

目录

  1. Bean 的作用域
  2. Bean 的生命周期
  3. 示例代码
  4. SpringBoot 自动装配
  5. SpringBoot 加载 Bean
  6. @ComponentScan
  7. @Import
  8. 自定义注解
  9. @SpringBootApplication 源码解析
  10. @ComponentScan
  11. @SpringBootConfiguration
  12. @EnableAutoConfiguration

更多推荐文章

查看全部
  • Windows 下使用 VSCode 结合 WSL 进行远程开发配置
  • 国内大模型市场发展现状、技术架构与人才需求分析
  • 2026 年主流 AI Agent 产品梳理与选型指南
  • Harness Engineering:给 AI 套上缰绳的工程学
  • FPGA 摄像头采集到 HDMI 显示完整链路实战
  • Windows 命令行实用技巧与趣味演示
  • 基于 Angular UI 构建 C# 跨平台桌面应用
  • Python 入门实战:Windows 环境下 Python 下载、安装及环境配置详解
  • OpenClaw 跨平台安装指南:Windows、macOS 与 Linux 全方案
  • YOLOv11 数据集训练与推理指南及网络结构解析
  • Windows 平台 ComfyUI 环境配置与常见问题排查指南
  • openKylin 通过 SSH 与 cpolar 实现远程连接
  • OpenClaw 配置指南:5 步让 AI 助手真正能干活
  • Node.js 安装教程与环境变量配置
  • STM32 上运行 AI 大模型的四种方案及案例
  • CSS 样式基础与布局实战指南
  • SpringBoot 学生管理系统:核心配置与 Controller 实现
  • SpringBoot 项目整合 OpenFeign 启动失败及运行时常见错误总结
  • Ubuntu 20.04 安装 Ollama 及 Open WebUI 部署大型语言模型
  • 数据结构:归并排序算法详解与实现

相关免费在线工具

  • Keycode 信息

    查找任何按下的键的javascript键代码、代码、位置和修饰符。 在线工具,Keycode 信息在线工具,online

  • Escape 与 Native 编解码

    JavaScript 字符串转义/反转义;Java 风格 \uXXXX(Native2Ascii)编码与解码。 在线工具,Escape 与 Native 编解码在线工具,online

  • JavaScript / HTML 格式化

    使用 Prettier 在浏览器内格式化 JavaScript 或 HTML 片段。 在线工具,JavaScript / HTML 格式化在线工具,online

  • JavaScript 压缩与混淆

    Terser 压缩、变量名混淆,或 javascript-obfuscator 高强度混淆(体积会增大)。 在线工具,JavaScript 压缩与混淆在线工具,online

  • Base64 字符串编码/解码

    将字符串编码和解码为其 Base64 格式表示形式即可。 在线工具,Base64 字符串编码/解码在线工具,online

  • Base64 文件转换器

    将字符串、文件或图像转换为其 Base64 表示形式。 在线工具,Base64 文件转换器在线工具,online