静态代码块适合启动清零,因其在类首次主动使用时执行且仅一次,不依赖框架、线程安全、时机可靠;推荐声明volatile字段并用静态块显式赋0以增强可读性与可见性。

直接在类加载阶段用静态代码块把全局计数器设为 0,就能确保服务器启动时自动清零,无需额外触发逻辑。
为什么静态块适合做启动清零
静态代码块在类首次被主动使用(比如 Spring 容器加载 Bean、第一个 HTTP 请求访问某个工具类)时执行,且只运行一次。它天然契合“服务启动初期执行一次”的需求,比监听 ContextRefreshedEvent 或 ServletContextListener 更轻量、更底层、不依赖框架。
- 不依赖 Spring、Tomcat 等运行环境,纯 JVM 层机制
- 线程安全:JVM 保证同一类的静态初始化仅由一个线程执行,其他线程阻塞等待
- 时机可靠:只要该类被加载(通常在应用启动早期),清零就已完成
标准写法:声明 + 静态块双保险
推荐将计数器声明为 public static volatile int,并在静态块中显式赋值 0。这样既明确意图,又避免因编译器优化或字段未显式初始化导致行为模糊。
public class GlobalCounter {public static volatile int requestCount = 0;
public static volatile int errorCount = 0;
static {
// 启动时强制清零,覆盖可能的默认值或残留值
requestCount = 0;
errorCount = 0;
System.out.println("GlobalCounter initialized: requestCount=" + requestCount);
}
}
- 即使字段声明时已写
int requestCount = 0,静态块再次赋值仍可增强可读性与维护性 - volatile 保证多线程下读写可见性,适合后续被并发更新的场景
- 打印日志可用于验证是否成功执行(生产环境建议用 SLF4J)
配合 Spring 的典型落地方式
如果项目基于 Spring,可让某个核心配置类或 Starter 类引用 GlobalCounter,从而触发其初始化。例如:
public class CounterAutoConfiguration {
@PostConstruct
public void init() {
// 强制加载 GlobalCounter 类(触发静态块)
Class.forName("com.example.GlobalCounter");
}
}
- 也可直接在某个
@Service类中访问GlobalCounter.requestCount,首次访问即触发 - 不建议在静态块里调用 Spring Bean(此时容器尚未就绪),保持静态块内纯 Java 逻辑
注意事项与避坑点
清零动作看似简单,但容易因细节引发问题:
- 别在静态块中抛异常:如读取外部文件失败,会导致
NoClassDefFoundError,整个类不可用 - 避免跨类强依赖:若
GlobalCounter初始化依赖另一个尚未加载的类,可能引发死锁或初始化失败 - 不要用静态块做耗时操作:比如远程调用、大文件解析——会拖慢类加载,影响启动速度
- 测试验证:写个单元测试,反射获取
GlobalCounter.requestCount值,确认为 0

















