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

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 应用底层运行机制。

相关文章:

  • MySQL慢查询分析与处理
  • Basler acA1920-40gc
  • RabbitMQ 学习路线与知识总结
  • Opencv 阈值与平滑处理
  • 京东外卖举办首批全职骑手代表签约仪式
  • az devops login报错:Failed to authenticate using the supplied token.
  • 广义表(C语言代码链式存储结构)
  • Linux基础33-C语言篇之字符串的基础操作【入门级】
  • 浅入浅出Selenium DevTools
  • 【数据结构】_顺序表
  • SringAop
  • 互联网医院实时数据监测智能分析系统设计概述(上)
  • 基于springboot后台管理的校园网站系统(源码+lw+部署文档+讲解),源码可白嫖!
  • 【HarmonyOS NEXT】控制 WebP 格式动图播放次数的实现方案
  • 【Prometheus】prometheus服务发现与relabel原理解析与应用实战
  • 如何用 Python 进行机器学习
  • python学习七
  • linux上搭建Lago并部署
  • word转换为pdf后图片失真解决办法、高质量PDF转换方法
  • C语言32个关键字
  • 前端做网站需要的技能/网站怎么建立
  • 母版页做网站例子/电话百度
  • 找网站建设客户/百度网盘下载官网
  • 郑州网站建设seo优化/建设网站推广
  • 网站开发检测用户微信号/推广app有哪些
  • wordpress获取php变量给模板/西安网站seo诊断