当前位置: 首页 > article >正文

Spring Boot 启动与 Service 注入的 JVM 运行细节


Spring Boot 启动与 Service 注入的 JVM 运行细节

我们通过一个具体的 Spring Boot 项目示例,结合 JVM 的类加载和对象实例化机制,详细说明 Service 类的加载、Bean 的创建 以及 方法调用的时序关系


1. 示例代码
1.1 定义一个 Service 类
@Service
public class UserService {
    // 静态代码块:类加载时执行(仅一次)
    static {
        System.out.println("[JVM] UserService 类加载,静态代码块执行");
    }

    // 构造方法:对象实例化时执行(每次创建 Bean 时执行)
    public UserService() {
        System.out.println("[Spring] UserService Bean 实例化,构造方法执行");
    }

    public void getUser() {
        System.out.println("[业务] 调用 getUser 方法");
    }
}
1.2 主启动类
@SpringBootApplication
public class MyApp implements CommandLineRunner {
    @Autowired
    private UserService userService;

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

    @Override
    public void run(String... args) {
        System.out.println("[Spring] 应用启动完成,开始调用 UserService 方法");
        userService.getUser();
    }
}

2. 运行流程与输出分析
2.1 启动 Spring Boot 应用

运行 main 方法时,Spring Boot 启动流程如下:

  1. JVM 加载 MyApp

    • 加载 MyApp.class,生成 Class 对象。
    • 执行 MyApp<clinit>(如果有静态代码块)。
  2. Spring 容器初始化

    • 扫描 @SpringBootApplication 注解下的所有组件。
    • 加载 UserService
      • JVM 加载 UserService.class,触发静态代码块。
      • 输出:[JVM] UserService 类加载,静态代码块执行
  3. 创建 UserService Bean

    • Spring 实例化 UserService(单例模式,默认在启动时创建)。
    • 执行 UserService 的构造方法。
    • 输出:[Spring] UserService Bean 实例化,构造方法执行
  4. 依赖注入

    • UserService Bean 注入到 MyAppuserService 字段。
  5. 启动完成,调用 run 方法

    • 输出:[Spring] 应用启动完成,开始调用 UserService 方法
    • 调用 userService.getUser()
    • 输出:[业务] 调用 getUser 方法

2.2 完整输出结果
[JVM] UserService 类加载,静态代码块执行
[Spring] UserService Bean 实例化,构造方法执行
...
[Spring] 应用启动完成,开始调用 UserService 方法
[业务] 调用 getUser 方法

3. 关键机制详解
3.1 类加载与静态代码块
  • 时机:当 JVM 首次使用 UserService 类时(Spring 扫描到 @Service 注解时触发加载)。
  • 特点
    • 静态代码块在类加载的 初始化阶段 执行,且仅执行一次。
    • 与 Spring Bean 是否创建无关,仅依赖类是否被 JVM 加载。
3.2 Bean 实例化与构造方法
  • 时机:Spring 容器启动时,默认 立即创建单例 Bean(可通过 @Lazy 改为延迟初始化)。
  • 特点
    • 构造方法在对象实例化时执行,每次创建 Bean 都会调用(单例模式下仅一次)。
    • Bean 的创建在类加载完成后进行。
3.3 方法调用
  • 时机:Bean 实例化完成后,通过依赖注入的实例调用方法。
  • 特点
    • 方法调用与对象生命周期无关,仅操作已存在的 Bean 实例。
    • 不会触发类加载或对象创建(单例模式下)。

4. 扩展:JVM 与 Spring 的协作流程
+---------------------+       +---------------------+       +---------------------+
|     JVM 类加载阶段     |       |  Spring Bean 生命周期  |       |      业务方法调用       |
|---------------------|       |---------------------|       |---------------------|
| 1. 加载 MyApp.class  |       | 1. 扫描组件,加载类     |       | 1. 调用 userService.getUser() |
| 2. 加载 UserService  |       | 2. 实例化 Bean(构造方法)|       |                     |
|    - 执行静态代码块    |       | 3. 依赖注入           |       |                     |
+---------------------+       | 4. BeanPostProcessor |       +---------------------+
                               +---------------------+

5. 总结
  • 类加载:由 JVM 在 Spring 扫描组件时触发,静态代码块在此阶段执行(仅一次)。
  • Bean 实例化:由 Spring 容器在启动时完成,构造方法在此阶段执行(单例模式下仅一次)。
  • 方法调用:操作已存在的 Bean 实例,与 JVM 类加载和对象创建无关。

关键结论

  • Service 类在 Spring Boot 启动时被加载,构造方法在 Bean 实例化时执行
  • 调用 Service 方法时,使用的是已创建好的 Bean 对象,不会触发新的对象创建

通过此示例,可以清晰看到 JVM 类加载、Spring Bean 生命周期和业务方法调用之间的关系,帮助理解 Java 应用底层运行机制。


http://www.kler.cn/a/566850.html

相关文章:

  • DeepSeek接入问题-Xshell5连接Ubuntu22失败解决方案
  • 【欢迎来到Git世界】Github入门
  • 【FL0086】基于SSM和微信小程序的垃圾分类小程序
  • 火语言RPA--Word写入文本段
  • MySQL数据库基本概念
  • DeepSeek开源周Day5: 3FS存储系统与AI数据处理新标杆
  • Github 2025-02-28 Java开源项目日报 Top9
  • 13.重新设计oj_model|综合测试|顶层makefile(C++)
  • SAP-ABAP:SAP数据库视图(Database View)详解-创建
  • 学习dify第二天-web前篇
  • 典型相关分析:原理、检验与Matlab实战
  • 领域驱动设计:事件溯源架构简介
  • DeepSeek再次重磅开源DeepEP:开源世界里的 AI 通信 “新引擎”
  • 自动化测试无法启动(java.net.SocketException)
  • 清理docker资源
  • 构建逻辑思维链(CoT)为金融AI消除幻觉(保险赔付篇)
  • STM32——HAL库开发笔记24(定时器5—超声波测距)(参考来源:b站铁头山羊)
  • React底层常见的设计模式
  • Vue的data配置项
  • Go红队开发—语法补充