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


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

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


1. 示例代码
1.1 定义一个 Service 类
java 复制代码
@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 主启动类
java 复制代码
@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 应用底层运行机制。

相关推荐
程序员蜗牛2 分钟前
9个Spring Boot参数验证高阶技巧,第8,9个代码量直接减半!
后端
yeyong3 分钟前
咨询kimi关于设计日志告警功能,还是有启发的
后端
库森学长9 分钟前
2025年,你不能错过Spring AI,那个汲取了LangChain灵感的家伙!
后端·openai·ai编程
Java水解29 分钟前
Spring Boot 启动流程详解
spring boot·后端
学历真的很重要42 分钟前
Claude Code Windows 原生版安装指南
人工智能·windows·后端·语言模型·面试·go
转转技术团队44 分钟前
让AI成为你的编程助手:如何高效使用Cursor
后端·cursor
shellvon1 小时前
你怎么被识别的?从TLS到Canvas的设备追踪术
后端·算法
yinke小琪1 小时前
消息队列如何保证消息顺序性?从原理到代码手把手教你
java·后端·面试
考虑考虑1 小时前
Java实现墨水屏点阵图
java·后端·java ee
网安Ruler1 小时前
第49天:Web开发-JavaEE应用&SpringBoot栈&模版注入&Thymeleaf&Freemarker&Velocity
java·spring boot·后端