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

Spring 中四种常见初始化方法,对比 static {} 和 @PostConstruct 在并发,Spring 加载顺序大致为: JVM 加载类

🧠 一、JVM 层面:类加载顺序(非 Spring)

当类被首次主动使用时(如调用静态方法、创建对象等),JVM 会加载类并按如下顺序执行:

✅ JVM 加载顺序
加载(Loading)
类的 .class 文件被加载到 JVM 内存中。

连接(Linking)

验证(Verify)

准备(Prepare):静态变量赋默认值

解析(Resolve)

初始化(Initialization):
执行如下 初始化顺序:

静态变量 → 静态代码块(static {})

✅ 示例

public class Demo {static String A = initA();static {System.out.println("静态代码块执行");}private static String initA() {System.out.println("静态变量初始化");return "A";}public static void main(String[] args) {System.out.println("main执行");}
}

🌱 二、Spring 加载顺序(Spring Boot)
Spring Boot 启动过程中,涉及以下阶段:

Spring 加载顺序大致为: JVM 加载类(见上)

会触发类的 static 变量 和 static {} 块执行。

如果你有 static { gdal.AllRegister(); },它会最先执行。

SpringApplication.run(…) 启动容器

扫描并实例化 Bean(@Component、@Service 等)

注入依赖

执行 @PostConstruct 方法

如果实现了 InitializingBean 或 ApplicationRunner,也会执行相关回调

🔁 三、总结 JVM + Spring 加载关系

阶段加载内容执行时间
JVM 类加载static 变量赋值 + static {} 块类首次使用时
Spring 扫描实例化扫描 @Component/@Service/… 并实例化Spring 启动时
Spring 注入依赖注入 @Autowired 等依赖Spring 启动时
Spring 初始化回调@PostConstruct、InitializingBean、ApplicationRunnerSpring 启动后

✅ 建议实践(特别针对 GDAL 初始化)
❌ 不要将 gdal 初始化写在静态代码块中,否则类一被引用就执行,不受 Spring 控制。

✅ 推荐用 @Component + @PostConstruct 方式做初始化(上面给的那种),能配合配置文件读取、统一容器生命周期控制。

我们来深入对比 static {} 和 @PostConstruct 在并发、懒加载、配置读取等关键场景下的行为与适用场景。

🧩 一、核心差异总览

对比点static {} 静态代码块@PostConstruct 生命周期回调方法
触发时机类首次加载(由 JVM)时执行Bean 被实例化并注入完依赖后,Spring 自动调用
执行次数只执行一次(类加载时)每个 Bean 实例执行一次(多实例就多次)
是否受 Spring 控制❌ 否✅ 是
能否访问配置项❌ 不能(Spring 环境未准备好)✅ 可以使用 @Value@Autowired 获取配置或依赖
是否支持懒加载❌ 否(类一用就执行)✅ 可配合 @Lazy 延迟初始化
线程安全控制❌ 需手动控制(同步、锁)✅ Spring 默认单例 Bean 保证线程安全
用途通用工具初始化、常量、JVM级初始化Spring 生命周期相关的业务初始化,如连接池、注册组件等

🧵 二、并发场景对比

static {}
类加载是线程安全的,但你在代码块中写的逻辑不一定是。

如果你在里面初始化一些静态字段或资源,要小心并发问题。

static {if (!initialized) {someExpensiveInit();  // 非线程安全,可能多次执行initialized = true;}
}
❗ 建议用 synchronized 或 AtomicBoolean 防御并发。@PostConstruct
Spring 管理的单例 Bean 是线程安全的,@PostConstruct 只会被调用一次。配合 Spring 的依赖注入机制,更安全、更灵活。
@PostConstruct
public void init() {// 已经可以安全访问配置、依赖等
}

🌿 三、懒加载支持

加载方式是否懒加载配合使用
static {}❌ 否不可控
@PostConstruct + @Lazy✅ 支持@Component @Lazy,Bean 仅在第一次注入时创建

📘 四、示例对比:读取配置 + 初始化 GDAL

❌ 使用 static {}(错误做法)

public class GdalUtil {static {// Spring 还未加载,无法读取配置gdal.AllRegister();gdal.SetConfigOption("PROJ_LIB", System.getProperty("proj.lib"));  // 不推荐}
}

✅ 使用 @PostConstruct(推荐做法)

@Component
public class GdalInitializer {@Value("${gdal.proj-lib-path}")private String projLibPath;@PostConstructpublic void init() {gdal.AllRegister();gdal.SetConfigOption("PROJ_LIB", projLibPath);}
}

✅ 总结:什么时候用哪个?

场景推荐使用
初始化常量、纯静态数据static {}
初始化依赖配置、Bean 生命周期相关@PostConstruct
想延迟加载组件直到被用到@Lazy + @PostConstruct

五,使用 @PostConstruct替换static代码示例

  1. application.yml 配置文件
    yaml
gdal:proj-lib-path: "C:/Users/Adm/OSGeo4W64/share/proj"

✅ 2. Java 代码中加载配置并初始化 GDAL/OGR
java

import org.gdal.gdal.gdal;
import org.gdal.ogr.ogr;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Component;import javax.annotation.PostConstruct;@Component
public class GdalInitializer {@Value("${gdal.proj-lib-path}")private String projLibPath;@PostConstructpublic void init() {// 注册驱动gdal.AllRegister();ogr.RegisterAll();// 设置 PROJ_LIB 路径gdal.SetConfigOption("PROJ_LIB", projLibPath);System.out.println("GDAL/OGR 初始化完成,PROJ_LIB = " + projLibPath);}
}

✅ 自动执行初始化
通过 @PostConstruct 注解,在 Spring Boot 启动时自动执行 GDAL 初始化。

✅ 补充建议
如果你用的是 Windows 系统,确保 projLibPath 配置的路径真实存在且具有访问权限。

可以添加环境变量 fallback 逻辑,例如 System.getenv(“PROJ_LIB”),以提高容错性。

这里是 Spring 中四种常见初始化方法:@PostConstruct、InitializingBean、ApplicationRunner、CommandLineRunner 的对比详解,涵盖它们的执行时机、使用场景、优缺点等内容。

🧩 一、四种初始化方式对比表

特性 / 方法@PostConstructInitializingBeanApplicationRunnerCommandLineRunner
接口实现要求implements InitializingBeanimplements ApplicationRunnerimplements CommandLineRunner
执行时机Bean 构造完成 + 依赖注入后@PostConstruct 等效Spring Boot 启动完成(run()之后)Spring Boot 启动完成(run()之后)
执行顺序控制❌ 无法排序❌ 无法排序✅ 支持 @Order / 实现 Ordered✅ 支持 @Order / 实现 Ordered
适合用途通用初始化逻辑,如依赖检查等同上(更适合大型或有接口规范场景)处理启动参数、业务启动流程ApplicationRunner,偏通用
依赖注入支持✅ 有✅ 有✅ 有✅ 有
异常处理方式抛出异常会导致容器启动失败同上同上同上
适合读配置/注入依赖?

二、逐个示例说明
✅ 1. @PostConstruct —— 最常用、简洁

@Component
public class MyBean {@PostConstructpublic void init() {// 依赖已注入,可以使用配置项、service 等System.out.println("PostConstruct 初始化");}
}

✅ 2. InitializingBean —— 更适合框架内、可测试、可被覆盖

@Component
public class MyBean implements InitializingBean {@Overridepublic void afterPropertiesSet() {System.out.println("afterPropertiesSet 初始化");}
}

✅ 3. ApplicationRunner —— Spring Boot 启动完成后执行(可接收参数)

@Component
@Order(1)  // 控制执行顺序
public class MyAppRunner implements ApplicationRunner {@Overridepublic void run(ApplicationArguments args) {System.out.println("ApplicationRunner 启动参数: " + args.getOptionNames());}
}

✅ 4. CommandLineRunner —— 启动后执行,参数来自 main(String[] args)

@Component
@Order(2)
public class MyCmdRunner implements CommandLineRunner {@Overridepublic void run(String... args) {System.out.println("CommandLineRunner 参数: " + Arrays.toString(args));}
}

二者主要区别在于:

ApplicationRunner 支持解析命令行参数(–option=value)

CommandLineRunner 只拿原始 String[] args

Spring Bean 生命周期阶段: 构造器 → 依赖注入 → @PostConstruct → InitializingBean.afterPropertiesSet → 容器启动完成 → ApplicationRunner / CommandLineRunner.run()

✅ 建议使用场景总结

场景推荐使用方式
简单初始化逻辑@PostConstruct
需要更强的接口语义、适配框架InitializingBean
启动后执行任务、加载缓存、打印欢迎信息等ApplicationRunner / CommandLineRunner
启动参数解析ApplicationRunner
想控制多个执行器的顺序@Order + Runner 接口

相关文章:

  • 4.29 tag的完整实现和登录页面的初步搭建
  • Python 数据智能实战 (13):AI的安全可靠 - 电商数据智能的红线与指南
  • qt国际化翻译功能用法
  • 哈尔滨服务器租用
  • 亿级流量系统架构设计与实战(四)
  • 第九节:图像处理基础-图像几何变换 (缩放、旋转、平移、翻转)
  • 数据结构(一)——线性表的顺序表示和实现
  • Xcode16提交App Store审核时提示bitcode报错
  • 【coze】工作流(B站视频总结改写)
  • 什么是原子变量
  • 今日行情明日机会——20250506
  • The 2023 ICPC Asia Taoyuan Regional Programming Contest
  • C++自动重连机制设计与实现指南
  • 2025ACTF Web部分题解
  • Linux/AndroidOS中进程间的通信线程间的同步 - POSIX IPC
  • 【MongoDB篇】MongoDB的事务操作!
  • LeetCode 1128. 等价多米诺骨牌对的数量 题解
  • C++ STL 基础与多线程安全性说明文档
  • Visual Studio 快捷键更改和设置
  • 使用ip池后,爬虫还被封,是什么原因呢?
  • 印对巴军事打击后,巴外交部召见印度驻巴临时代办
  • 中国电信财务部总经理周响华调任华润集团总会计师
  • 纪念|“补白大王”郑逸梅,从藏扇看其眼光品味
  • 金价大反攻,国内金饰价格涨回千元,能否重返巅峰?
  • 马斯克的胜利?OpenAI迫于压力放弃营利性转型计划
  • 热点问答丨新加坡人民行动党缘何再赢议会选举