Spring Boot+Vaadin项目中@Autowired与@Lazy注入异常排查
问题分析与解决:Spring Boot + Vaadin项目中@Lazy导致的空指针异常
问题场景
接手的Spring Boot + Vaadin项目未使用@Autowired,调整时为MyService添加@Lazy注解解决启动时UserService未就绪的问题:
@Lazy @Service public class MyService { private UserService userService; public MyService() { log.debug("******** construction ****************"); } @PostConstruct public void init() { log.debug("******** PostConstruct ****************"); userService = ServiceAccessor.getService(UserService.class); } // ... 其他方法 }
在调用MyService的客户端类中注入后,日志显示service不为null,但调用doSome()时抛出空指针异常,且观察到MyService的构造方法未执行(不加@Lazy时启动阶段会执行)。怀疑客户端类未纳入Spring容器,或@Lazy代理导致初始化异常。
核心原因分析
- 客户端类未被Spring容器管理:如果客户端类没有
@Component/@Service/@Route(Vaadin视图类)等Spring stereotype注解,@Autowired注解不会生效,此时拿到的service可能是Spring生成的空代理壳,而非真实实例,调用方法时无法触发真实对象的初始化,导致userService未赋值。 - @Lazy代理的初始化时机问题:使用
@Lazy时,Spring会先创建代理对象,真实实例会在第一次调用方法时才初始化。但如果客户端类不在容器内,代理无法正确触发真实实例的初始化流程,@PostConstruct方法不会执行,userService始终为null,最终引发NPE。
解决方案
1. 将客户端类纳入Spring容器
根据客户端类的类型选择对应方式:
- Vaadin视图/UI类:添加
@Route或@UIScope注解,Spring会自动扫描并注册这类组件; - 普通业务类:添加
@Component/@Service注解,确保Spring组件扫描路径覆盖该类所在包; - 特殊类(如工具类):在Spring配置类中通过
@Bean手动注册:@Configuration public class AppConfig { @Bean public ClientClass clientClass() { return new ClientClass(); } }
2. 替换手动服务获取为Spring标准注入方式
放弃ServiceAccessor,使用Spring原生的构造注入,自动处理依赖的懒加载顺序,避免手动获取服务的时机问题:
@Lazy @Service public class MyService { private final UserService userService; // 构造注入,Spring自动注入懒加载的UserService public MyService(@Lazy UserService userService) { this.userService = userService; log.debug("******** construction ****************"); } // 无需@PostConstruct初始化userService // ... 其他方法 }
3. 验证调整效果
- 启动项目后,检查日志是否出现
MyService的构造方法打印信息; - 调用
doSome()方法,确认userService已正常赋值,无空指针异常。
内容的提问来源于stack exchange,提问作者vic
相关产品推荐
相关产品推荐

