先说一个技术场景:不少项目里,全局配置字典变量(比如系统枚举、业务类型码表)都习惯用静态代码块来初始化——类一加载,字典就绪,干净利索。但问题也随之而来:静态代码块只执行一次,运行时想改个字典值?行不通。所以今天聊的核心是:如何用静态代码块把“首次加载”这事做稳当,同时再搭一套动态更新机制,让字典真正“活”起来。

静态代码块适合初始化全局配置字典变量,但本身不支持运行时动态更新;要实现“可配置+可更新”,需结合外部数据源与主动刷新机制。核心在于分清职责:静态代码块管“首次加载”,后续更新靠业务逻辑驱动。
静态代码块初始化字典变量
用静态代码块加载一次性的基础字典,确保类加载即就绪,避免重复初始化:
- 声明
public static final Map或Map作为字典容器> - 在
static{}中从配置文件(如dict.properties)、数据库查询结果或硬编码映射填充数据 - 推荐加
final修饰,防止引用被意外替换;若需后续修改内容,用ConcurrentHashMap保证线程安全
让字典支持运行时动态更新
静态代码块只执行一次,真正“动态”要靠外部触发+内存替换:
- 提供一个
public static void reload()方法,重新读取配置源并覆盖原Map内容 - 配合监听机制:例如监听
application.yml变化(Spring Boot可用@ConfigurationPropertiesRefresh),或接收HTTP接口调用(如/api/dict/reload) - 更新时加写锁(如
ReentrantLock)或使用AtomicReference,避免读写并发问题
对接RuoYi等配置中心实践
脱离硬编码,把字典变量与系统级配置管理打通:
- 启动时用静态代码块加载默认字典(兜底),再异步调用
SysDictTypeService.listAll()拉取最新数据 - 将字典缓存到
ConcurrentHashMap,并注册监听器——当RuoYi后台修改字典类型或数据,通过WebSocket或Redis Pub/Sub通知服务端刷新本地Map - 关键字段如
dict_type作Map的key,List作value,便于按类型快速查值
规避常见陷阱
静态初始化和动态更新容易混淆职责,导致状态不一致:
- 不要在静态代码块里调用可能失败的远程接口(如未启动的数据库),应拆到
init()方法中并做异常兜底 - 避免多个静态块相互依赖,尤其当字典A依赖字典B时,确保加载顺序可控
- 更新后务必清除相关缓存(如MyBatis二级缓存、自定义LRU缓存),否则前端仍读旧值