Spring组件中字段提前引用导致未初始化问题的解决方法
问题原因
这是Java实例字段初始化顺序和Spring依赖注入机制共同导致的问题:
@RequiredArgsConstructor会生成一个构造函数,在构造函数体内给startCommand字段赋值。- 但实例字段
COMMANDS的初始化表达式(Map.of(...))是在构造函数体执行之前运行的,此时startCommand还处于未赋值的null状态,lambda 引用它自然会出问题。
解决方案
提供三种可行的解决方式,按需选择:
方式1:手动编写构造函数,延后Map初始化
放弃 @RequiredArgsConstructor,手动编写构造函数,确保 startCommand 赋值完成后再初始化 COMMANDS:
@Component public class CommandsHandler { private final StartCommand startCommand; public Map<String, BiFunction<Long, String, SendMessage>> COMMANDS; public CommandsHandler(StartCommand startCommand) { this.startCommand = startCommand; // 此时startCommand已完成注入,安全初始化Map COMMANDS = Map.of( "/start", (x, y) -> startCommand.apply(x, y) ); } }
方式2:用@PostConstruct完成初始化
保留 @RequiredArgsConstructor,将 COMMANDS 的初始化放到被 @PostConstruct 标记的方法中。Spring会在所有依赖注入完成后自动执行这个方法:
@Component @RequiredArgsConstructor public class CommandsHandler { private final StartCommand startCommand; public Map<String, BiFunction<Long, String, SendMessage>> COMMANDS; @PostConstruct public void initCommands() { COMMANDS = Map.of( "/start", (x, y) -> startCommand.apply(x, y) ); } }
方式3:改为懒加载的方法
将 COMMANDS 从字段改为返回Map的方法,每次调用时才创建Map,此时 startCommand 必然已经完成注入:
@Component @RequiredArgsConstructor public class CommandsHandler { private final StartCommand startCommand; public Map<String, BiFunction<Long, String, SendMessage>> getCommands() { return Map.of( "/start", (x, y) -> startCommand.apply(x, y) ); } }
内容的提问来源于stack exchange,提问作者Arzybek
相关产品推荐
相关产品推荐

