静态代码块在类首次主动使用时执行一次,适合初始化启动即需、全局共享、值稳定的轻量配置;需用classloader加载资源、判空防npe、指定utf-8编码、try-catch兜底、声明public static final确保不可变。

静态代码块在类加载的初始化阶段执行一次,适合做轻量、确定、全局共享的配置初始化——它不依赖 Spring 容器,天然线程安全,但必须手动处理资源加载、异常兜底和顺序依赖。
什么时候真正开始执行
静态代码块不会在类被加载(Loading)时就运行,而是在 JVM 判定该类“首次被主动使用”、进入初始化(Initialization)阶段时触发。以下操作会启动这个过程:
- 用 new 创建该类第一个实例
- 调用该类任意 static 方法
- 访问或修改一个 非 final 的静态字段(如 public static String HOST = "localhost";)
- 通过 Class.forName("X") 反射加载(注意:ClassLoader.loadClass("X") 不会触发)
- JVM 启动时直接运行含 main() 的主类
反例:仅声明变量、导入类、或访问 public static final int PORT = 8080; 这类编译期常量,均不会触发静态块。
怎么写才稳妥地初始化配置
配置初始化不是把代码塞进 static{} 就完事,关键在三点:路径对、能容错、结果不可变。
在 Java 中初始化和管理阿里云 SDK客户端。包括单例模式、线程安全、endpoint 与 region 配置、VPC 终端节点、同步与异步等。
- 用 ClassLoader.getResourceAsStream("config.properties") 加载,不要加斜杠("/config.properties" 是错的)
- InputStream 必须判空,否则可能 NPE;Properties.load() 建议用 new InputStreamReader(is, "UTF-8") 避免中文乱码
- 所有 IO 操作都套 try-catch,捕获后包装为 ExceptionInInitializerError,防止静默失败
- 配置字段声明为 public static final,确保运行期不可变
- 多个静态成员混合时,把强依赖项(如配置对象)放在前面,严格按源码顺序执行
哪些配置适合放这里,哪些要避开
静态代码块适合初始化启动即需、全应用共享、值稳定、无外部框架依赖的资源:
- 本地 properties/yaml 文件解析后的数据库连接参数
- 预编译的正则 Pattern(如 Pattern.compile("^[a-z]+\d*$"))
- 枚举映射表、地区码字典等不可变静态集合
- JVM 关闭钩子注册(Runtime.getRuntime().addShutdownHook())
应避免:
- HTTP 请求、数据库连接池创建等耗时或可能失败的操作(会阻塞类加载)
- 访问其他尚未初始化类的静态字段(易引发循环依赖或读到 null/默认值)
- 在块里启动新线程并等待其完成
- 试图修改实例变量或调用非静态方法(编译直接报错)
如果配置很重,要不要懒加载
是的。若初始化开销大(比如构建百万级缓存、初始化 HikariCP 连接池),又不想拖慢启动,可用静态内部类模式:
- 把逻辑封装进 static class Holder 的静态块中
- 对外暴露 public static final Resource INSTANCE = Holder.INSTANCE
- Holder 初始化仅在首次访问 INSTANCE 时触发,JVM 保证线程安全且异常隔离
- 即使 Holder 初始化失败,外层类仍可正常使用
Java免费学习笔记:立即使用
解锁 Java 大师之旅:从入门到精通的终极指南










